1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                           */
3 /*                  This file is part of the program and library             */
4 /*         SCIP --- Solving Constraint Integer Programs                      */
5 /*                                                                           */
6 /*    Copyright (C) 2002-2021 Konrad-Zuse-Zentrum                            */
7 /*                            fuer Informationstechnik Berlin                */
8 /*                                                                           */
9 /*  SCIP is distributed under the terms of the ZIB Academic License.         */
10 /*                                                                           */
11 /*  You should have received a copy of the ZIB Academic License              */
12 /*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13 /*                                                                           */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file   nlpi/expr.c
17  * @ingroup OTHER_CFILES
18  * @brief  methods for expressions, expression trees, expression graphs, and related
19  * @author Stefan Vigerske
20  * @author Thorsten Gellermann
21  * @author Ingmar Vierhaus (exprparse)
22  */
23 
24 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
25 
26 #include <stdarg.h>
27 #include <string.h>
28 #include <math.h>
29 #include <ctype.h>
30 
31 #include "nlpi/pub_expr.h"
32 #include "nlpi/struct_expr.h"
33 #include "nlpi/exprinterpret.h"
34 
35 #include "scip/intervalarith.h"
36 #include "scip/pub_misc.h"
37 #include "scip/misc.h"
38 #include "scip/pub_message.h"
39 
40 
41 #define SCIP_EXPRESSION_MAXCHILDEST 16       /**< estimate on maximal number of children */
42 
43 /** sign of a value (-1 or +1)
44  *
45  *  0.0 has sign +1
46  */
47 #define SIGN(x) ((x) >= 0.0 ? 1.0 : -1.0)
48 
49 /** ensures that a block memory array has at least a given size
50  *
51  *  if cursize is 0, then *array1 can be NULL
52  */
53 #define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize)    \
54    do {                                                                 \
55       int __newsize;                                                    \
56       assert((blkmem)  != NULL);                                        \
57       if( *(cursize) >= (minsize) )                                     \
58          break;                                                         \
59       __newsize = calcGrowSize(minsize);                                \
60       assert(__newsize >= (minsize));                                   \
61       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
62       *(cursize) = __newsize;                                           \
63    } while( FALSE )
64 
65 #ifdef SCIP_DISABLED_CODE /* this macro is currently not used, which offends lint, so disable it */
66 /** ensures that two block memory arrays have at least a given size
67  *
68  *  if cursize is 0, then arrays can be NULL
69  */
70 #define ensureBlockMemoryArraySize2(blkmem, array1, array2, cursize, minsize) \
71    do {                                                                 \
72       int __newsize;                                                    \
73       assert((blkmem)  != NULL);                                        \
74       if( *(cursize) >= (minsize) )                                     \
75          break;                                                         \
76       __newsize = calcGrowSize(minsize);                                \
77       assert(__newsize >= (minsize));                                   \
78       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
79       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
80       *(cursize) = __newsize;                                           \
81    } while( FALSE )
82 #endif
83 
84 /** ensures that three block memory arrays have at least a given size
85  *
86  *  if cursize is 0, then arrays can be NULL
87  */
88 #define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize) \
89    do {                                                                 \
90       int __newsize;                                                    \
91       assert((blkmem)  != NULL);                                        \
92       if( *(cursize) >= (minsize) )                                     \
93          break;                                                         \
94       __newsize = calcGrowSize(minsize);                                \
95       assert(__newsize >= (minsize));                                   \
96       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
97       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
98       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array3, *(cursize), __newsize) ); \
99       *(cursize) = __newsize;                                           \
100    } while( FALSE )
101 
102 /**@name Miscellaneous private methods */
103 /**@{ */
104 
105 /** calculate memory size for dynamically allocated arrays (copied from scip/set.c) */
106 static
calcGrowSize(int num)107 int calcGrowSize(
108    int                   num                 /**< minimum number of entries to store */
109    )
110 {
111    int size;
112 
113    /* calculate the size with this loop, such that the resulting numbers are always the same (-> block memory) */
114    size = 4;
115    while( size < num )
116       size = (int)(1.2 * size + 4);
117 
118    return size;
119 }
120 
121 /** expression graph nodes comparison to use in sorting methods
122  *
123  * The nodes need to have been added to the expression graph (depth,pos >= 0).
124  * The better node is the one with the lower depth and lower position, if depth is equal.
125  */
126 static
SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)127 SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)
128 {
129    SCIP_EXPRGRAPHNODE* node1 = (SCIP_EXPRGRAPHNODE*)elem1;
130    SCIP_EXPRGRAPHNODE* node2 = (SCIP_EXPRGRAPHNODE*)elem2;
131 
132    assert(node1 != NULL);
133    assert(node2 != NULL);
134    assert(node1->depth >= 0);
135    assert(node1->pos >= 0);
136    assert(node2->depth >= 0);
137    assert(node2->pos >= 0);
138 
139    if( node1->depth != node2->depth )
140       return node1->depth - node2->depth;
141 
142    /* there should be no two nodes on the same position */
143    assert((node1->pos != node2->pos) || (node1 == node2));
144 
145    return node1->pos - node2->pos;
146 }
147 
148 /** checks if a given new lower bound is tighter (w.r.t. given bound strengthening epsilon) than the old one (copied from scip/set.c) */
149 static
isLbBetter(SCIP_Real minstrength,SCIP_Real newlb,SCIP_Real oldlb,SCIP_Real oldub)150 SCIP_Bool isLbBetter(
151    SCIP_Real             minstrength,        /**< minimal relative improvement required to be a better bound */
152    SCIP_Real             newlb,              /**< new lower bound */
153    SCIP_Real             oldlb,              /**< old lower bound */
154    SCIP_Real             oldub               /**< old upper bound */
155    )
156 {
157    SCIP_Real eps;
158 
159    /* nothing can be tighter than an empty interval */
160    if( oldlb > oldub )
161       return FALSE;
162 
163    eps = REALABS(oldlb);
164    eps = MIN(oldub - oldlb, eps);
165    return EPSGT(newlb, oldlb, minstrength * MAX(eps, 1e-3));
166 }
167 
168 /** checks if a given new upper bound is tighter (w.r.t. given bound strengthening epsilon) than the old one (copied from scip/set.c) */
169 static
isUbBetter(SCIP_Real minstrength,SCIP_Real newub,SCIP_Real oldlb,SCIP_Real oldub)170 SCIP_Bool isUbBetter(
171    SCIP_Real             minstrength,        /**< minimal relative improvement required to be a better bound */
172    SCIP_Real             newub,              /**< new upper bound */
173    SCIP_Real             oldlb,              /**< old lower bound */
174    SCIP_Real             oldub               /**< old upper bound */
175    )
176 {
177    SCIP_Real eps;
178 
179    /* nothing can be tighter than an empty interval */
180    if( oldlb > oldub )
181       return FALSE;
182 
183    eps = REALABS(oldub);
184    eps = MIN(oldub - oldlb, eps);
185    return EPSLT(newub, oldub, minstrength * MAX(eps, 1e-3));
186 }
187 
188 /**@} */
189 
190 /**@name Expression curvature methods */
191 /**@{ */
192 
193 /** curvature names as strings */
194 static
195 const char* curvnames[4] =
196    {
197       "unknown",
198       "convex",
199       "concave",
200       "linear"
201    };
202 
203 #undef SCIPexprcurvAdd
204 
205 /** gives curvature for a sum of two functions with given curvature */
SCIPexprcurvAdd(SCIP_EXPRCURV curv1,SCIP_EXPRCURV curv2)206 SCIP_EXPRCURV SCIPexprcurvAdd(
207    SCIP_EXPRCURV         curv1,              /**< curvature of first summand */
208    SCIP_EXPRCURV         curv2               /**< curvature of second summand */
209    )
210 {
211    return (SCIP_EXPRCURV) (curv1 & curv2);
212 }
213 
214 /** gives the curvature for the negation of a function with given curvature */
SCIPexprcurvNegate(SCIP_EXPRCURV curvature)215 SCIP_EXPRCURV SCIPexprcurvNegate(
216    SCIP_EXPRCURV         curvature           /**< curvature of function */
217    )
218 {
219    switch( curvature )
220    {
221    case SCIP_EXPRCURV_CONCAVE:
222       return SCIP_EXPRCURV_CONVEX;
223 
224    case SCIP_EXPRCURV_CONVEX:
225       return SCIP_EXPRCURV_CONCAVE;
226 
227    case SCIP_EXPRCURV_LINEAR:
228    case SCIP_EXPRCURV_UNKNOWN:
229       /* can return curvature, do this below */
230       break;
231 
232    default:
233       SCIPerrorMessage("unknown curvature status.\n");
234       SCIPABORT();
235    }
236 
237    return curvature;
238 }
239 
240 /** gives curvature for a functions with given curvature multiplied by a constant factor */
SCIPexprcurvMultiply(SCIP_Real factor,SCIP_EXPRCURV curvature)241 SCIP_EXPRCURV SCIPexprcurvMultiply(
242    SCIP_Real             factor,             /**< constant factor */
243    SCIP_EXPRCURV         curvature           /**< curvature of other factor */
244    )
245 {
246    if( factor == 0.0 )
247       return SCIP_EXPRCURV_LINEAR;
248    if( factor > 0.0 )
249       return curvature;
250    return SCIPexprcurvNegate(curvature);
251 }
252 
253 /** gives curvature for base^exponent for given bounds and curvature of base-function and constant exponent */
SCIPexprcurvPower(SCIP_INTERVAL basebounds,SCIP_EXPRCURV basecurv,SCIP_Real exponent)254 SCIP_EXPRCURV SCIPexprcurvPower(
255    SCIP_INTERVAL         basebounds,         /**< bounds on base function */
256    SCIP_EXPRCURV         basecurv,           /**< curvature of base function */
257    SCIP_Real             exponent            /**< exponent */
258    )
259 {
260    SCIP_Bool expisint;
261 
262    assert(basebounds.inf <= basebounds.sup);
263 
264    if( exponent == 0.0 )
265       return SCIP_EXPRCURV_LINEAR;
266 
267    if( exponent == 1.0 )
268       return basecurv;
269 
270    expisint = EPSISINT(exponent, 0.0); /*lint !e835*/
271 
272    /* if exponent is fractional, then power is not defined for a negative base
273     * thus, consider only positive part of basebounds
274     */
275    if( !expisint && basebounds.inf < 0.0 )
276    {
277       basebounds.inf = 0.0;
278       if( basebounds.sup < 0.0 )
279          return SCIP_EXPRCURV_LINEAR;
280    }
281 
282    /* if basebounds contains 0.0, consider negative and positive interval separately, if possible */
283    if( basebounds.inf < 0.0 && basebounds.sup > 0.0 )
284    {
285       SCIP_INTERVAL leftbounds;
286       SCIP_INTERVAL rightbounds;
287 
288       /* something like x^(-2) may look convex on each side of zero, but is not convex on the whole interval due to the singularity at 0.0 */
289       if( exponent < 0.0 )
290          return SCIP_EXPRCURV_UNKNOWN;
291 
292       SCIPintervalSetBounds(&leftbounds,  basebounds.inf, 0.0);
293       SCIPintervalSetBounds(&rightbounds, 0.0, basebounds.sup);
294 
295       return (SCIP_EXPRCURV) (SCIPexprcurvPower(leftbounds,  basecurv, exponent) & SCIPexprcurvPower(rightbounds, basecurv, exponent));
296    }
297    assert(basebounds.inf >= 0.0 || basebounds.sup <= 0.0);
298 
299    /* (base^exponent)'' = exponent * ( (exponent-1) base^(exponent-2) (base')^2 + base^(exponent-1) base'' )
300     *
301     * if base'' is positive, i.e., base is convex, then
302     * - for base > 0.0 and exponent > 1.0, the second deriv. is positive -> convex
303     * - for base < 0.0 and exponent > 1.0, we can't say (first and second summand opposite signs)
304     * - for base > 0.0 and 0.0 < exponent < 1.0, we can't say (first sommand negative, second summand positive)
305     * - for base > 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
306     * - for base < 0.0 and exponent < 0.0 and even, the second deriv. is positive -> convex
307     * - for base < 0.0 and exponent < 0.0 and odd, the second deriv. is negative -> concave
308     *
309     * if base'' is negative, i.e., base is concave, then
310     * - for base > 0.0 and exponent > 1.0, we can't say (first summand positive, second summand negative)
311     * - for base < 0.0 and exponent > 1.0 and even, the second deriv. is positive -> convex
312     * - for base < 0.0 and exponent > 1.0 and odd, the second deriv. is negative -> concave
313     * - for base > 0.0 and 0.0 < exponent < 1.0, the second deriv. is negative -> concave
314     * - for base > 0.0 and exponent < 0.0, the second deriv. is positive -> convex
315     * - for base < 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
316     *
317     * if base'' is zero, i.e., base is linear, then
318     *   (base^exponent)'' = exponent * (exponent-1) base^(exponent-2) (base')^2
319     * - just multiply signs
320     */
321 
322    if( basecurv == SCIP_EXPRCURV_LINEAR )
323    {
324       SCIP_Real sign;
325 
326       /* base^(exponent-2) is negative, if base < 0.0 and exponent is odd */
327       sign = exponent * (exponent - 1.0);
328       assert(basebounds.inf >= 0.0 || expisint);
329       if( basebounds.inf < 0.0 && ((int)exponent)%2 != 0 )
330          sign *= -1.0;
331       assert(sign != 0.0);
332 
333       return sign > 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
334    }
335 
336    if( basecurv == SCIP_EXPRCURV_CONVEX )
337    {
338       if( basebounds.sup <= 0.0 && exponent < 0.0 && expisint )
339          return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
340       if( basebounds.inf >= 0.0 && exponent > 1.0 )
341          return SCIP_EXPRCURV_CONVEX ;
342       return SCIP_EXPRCURV_UNKNOWN;
343    }
344 
345    if( basecurv == SCIP_EXPRCURV_CONCAVE )
346    {
347       if( basebounds.sup <= 0.0 && exponent > 1.0 && expisint )
348          return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
349       if( basebounds.inf >= 0.0 && exponent < 1.0 )
350          return exponent < 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
351       return SCIP_EXPRCURV_UNKNOWN;
352    }
353 
354    return SCIP_EXPRCURV_UNKNOWN;
355 }
356 
357 /** gives curvature for a monomial with given curvatures and bounds for each factor
358  *
359  *  See Maranas and Floudas, Finding All Solutions of Nonlinearly Constrained Systems of Equations, JOGO 7, 1995
360  *  for the categorization in the case that all factors are linear.
361  */
SCIPexprcurvMonomial(int nfactors,SCIP_Real * exponents,int * factoridxs,SCIP_EXPRCURV * factorcurv,SCIP_INTERVAL * factorbounds)362 SCIP_EXPRCURV SCIPexprcurvMonomial(
363    int                   nfactors,           /**< number of factors in monomial */
364    SCIP_Real*            exponents,          /**< exponents in monomial, or NULL if all 1.0 */
365    int*                  factoridxs,         /**< indices of factors (but not exponents), or NULL if identity mapping */
366    SCIP_EXPRCURV*        factorcurv,         /**< curvature of each factor */
367    SCIP_INTERVAL*        factorbounds        /**< bounds of each factor */
368    )
369 {
370    SCIP_Real mult;
371    SCIP_Real e;
372    SCIP_EXPRCURV curv;
373    SCIP_EXPRCURV fcurv;
374    int nnegative;
375    int npositive;
376    SCIP_Real sum;
377    SCIP_Bool expcurvpos;
378    SCIP_Bool expcurvneg;
379    int j;
380    int f;
381 
382    assert(nfactors >= 0);
383    assert(factorcurv   != NULL || nfactors == 0);
384    assert(factorbounds != NULL || nfactors == 0);
385 
386    if( nfactors == 0 )
387       return SCIP_EXPRCURV_LINEAR;
388 
389    if( nfactors == 1 )
390    {
391       f = factoridxs != NULL ? factoridxs[0] : 0;
392       e = exponents != NULL ? exponents[0] : 1.0;
393       /* SCIPdebugMessage("monomial [%g,%g]^%g is %s\n",
394          factorbounds[f].inf, factorbounds[f].sup, e,
395          SCIPexprcurvGetName(SCIPexprcurvPower(factorbounds[f], factorcurv[f], e))); */
396       return SCIPexprcurvPower(factorbounds[f], factorcurv[f], e);  /*lint !e613*/
397    }
398 
399    mult = 1.0;
400 
401    nnegative = 0; /* number of negative exponents */
402    npositive = 0; /* number of positive exponents */
403    sum = 0.0;     /* sum of exponents */
404    expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
405    expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
406 
407    for( j = 0; j < nfactors; ++j )
408    {
409       f = factoridxs != NULL ? factoridxs[j] : j;
410       if( factorcurv[f] == SCIP_EXPRCURV_UNKNOWN ) /*lint !e613*/
411          return SCIP_EXPRCURV_UNKNOWN;
412       if( factorbounds[f].inf < 0.0 && factorbounds[f].sup > 0.0 )  /*lint !e613*/
413          return SCIP_EXPRCURV_UNKNOWN;
414 
415       e = exponents != NULL ? exponents[j] : 1.0;
416       if( e < 0.0 )
417          ++nnegative;
418       else
419          ++npositive;
420       sum += e;
421 
422       if( factorbounds[f].inf < 0.0 )  /*lint !e613*/
423       {
424          /* if argument is negative, then exponent should be integer */
425          assert(EPSISINT(e, 0.0));  /*lint !e835*/
426 
427          /* flip j'th argument: (f_j)^(exp_j) = (-1)^(exp_j) (-f_j)^(exp_j) */
428 
429          /* -f_j has negated curvature of f_j */
430          fcurv = SCIPexprcurvNegate(factorcurv[f]);  /*lint !e613*/
431 
432          /* negate monomial, if exponent is odd, i.e., (-1)^(exp_j) = -1 */
433          if( (int)e % 2 != 0 )
434             mult *= -1.0;
435       }
436       else
437       {
438          fcurv = factorcurv[f];  /*lint !e613*/
439       }
440 
441       /* check if exp_j * fcurv is convex (>= 0) and/or concave */
442       fcurv = SCIPexprcurvMultiply(e, fcurv);
443       if( !(fcurv & SCIP_EXPRCURV_CONVEX) )
444          expcurvpos = FALSE;
445       if( !(fcurv & SCIP_EXPRCURV_CONCAVE) )
446          expcurvneg = FALSE;
447    }
448 
449    /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
450     * - all exponents are negative, or
451     * - all except one exponent j* are negative and exp_j* >= 1 - sum_{j!=j*}exp_j, but the latter is equivalent to sum_j exp_j >= 1
452     * further, the product is concave if
453     * - all exponents are positive and the sum of exponents is <= 1.0
454     *
455     * if factors are nonlinear, then we require additionally, that for convexity
456     * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
457     * and for concavity, we require that
458     * - all factors are concave, i.e., exp_j*f_j'' <= 0
459     */
460 
461    if( nnegative == nfactors && expcurvpos )
462       curv = SCIP_EXPRCURV_CONVEX;
463    else if( nnegative == nfactors-1 && EPSGE(sum, 1.0, 1e-9) && expcurvpos )
464       curv = SCIP_EXPRCURV_CONVEX;
465    else if( npositive == nfactors && EPSLE(sum, 1.0, 1e-9) && expcurvneg )
466       curv = SCIP_EXPRCURV_CONCAVE;
467    else
468       curv = SCIP_EXPRCURV_UNKNOWN;
469    curv = SCIPexprcurvMultiply(mult, curv);
470 
471    return curv;
472 }
473 
474 /** gives name as string for a curvature */
SCIPexprcurvGetName(SCIP_EXPRCURV curv)475 const char* SCIPexprcurvGetName(
476    SCIP_EXPRCURV         curv                /**< curvature */
477    )
478 {
479    assert(curv <= SCIP_EXPRCURV_LINEAR);  /*lint !e685*/
480 
481    return curvnames[curv];
482 }
483 
484 /**@} */
485 
486 /**@name Quadratic expression data private methods */
487 /**@{ */
488 
489 /** creates SCIP_EXPRDATA_QUADRATIC data structure from given quadratic elements */
490 static
quadraticdataCreate(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_QUADRATIC ** quadraticdata,SCIP_Real constant,int nchildren,SCIP_Real * lincoefs,int nquadelems,SCIP_QUADELEM * quadelems)491 SCIP_RETCODE quadraticdataCreate(
492    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
493    SCIP_EXPRDATA_QUADRATIC** quadraticdata,  /**< buffer to store pointer to quadratic data */
494    SCIP_Real             constant,           /**< constant */
495    int                   nchildren,          /**< number of children */
496    SCIP_Real*            lincoefs,           /**< linear coefficients of children, or NULL if all 0.0 */
497    int                   nquadelems,         /**< number of quadratic elements */
498    SCIP_QUADELEM*        quadelems           /**< quadratic elements */
499    )
500 {
501    assert(blkmem != NULL);
502    assert(quadraticdata != NULL);
503    assert(quadelems != NULL || nquadelems == 0);
504    assert(nchildren >= 0);
505 
506    SCIP_ALLOC( BMSallocBlockMemory(blkmem, quadraticdata) );
507 
508    (*quadraticdata)->constant   = constant;
509    (*quadraticdata)->lincoefs   = NULL;
510    (*quadraticdata)->nquadelems = nquadelems;
511    (*quadraticdata)->quadelems  = NULL;
512    (*quadraticdata)->sorted     = (nquadelems <= 1);
513 
514    if( lincoefs != NULL )
515    {
516       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->lincoefs, lincoefs, nchildren) );
517    }
518 
519    if( nquadelems > 0 )
520    {
521       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->quadelems, quadelems, nquadelems) );
522    }
523 
524    return SCIP_OKAY;
525 }
526 
527 /** sorts quadratic elements in a SCIP_EXPRDATA_QUADRATIC data structure */
528 static
quadraticdataSort(SCIP_EXPRDATA_QUADRATIC * quadraticdata)529 void quadraticdataSort(
530    SCIP_EXPRDATA_QUADRATIC* quadraticdata    /**< quadratic data */
531    )
532 {
533    assert(quadraticdata != NULL);
534 
535    if( quadraticdata->sorted )
536    {
537 #ifndef NDEBUG
538       int i;
539       for( i = 1; i < quadraticdata->nquadelems; ++i )
540       {
541          assert(quadraticdata->quadelems[i].idx1 <= quadraticdata->quadelems[i].idx2);
542          assert(quadraticdata->quadelems[i-1].idx1 <= quadraticdata->quadelems[i].idx1);
543          assert(quadraticdata->quadelems[i-1].idx1 < quadraticdata->quadelems[i].idx1 ||
544             quadraticdata->quadelems[i-1].idx2 <= quadraticdata->quadelems[i].idx2);
545       }
546 #endif
547       return;
548    }
549 
550    if( quadraticdata->nquadelems > 0 )
551       SCIPquadelemSort(quadraticdata->quadelems, quadraticdata->nquadelems);
552 
553    quadraticdata->sorted = TRUE;
554 }
555 
556 /**@} */
557 
558 /**@name Polynomial expression data private methods */
559 /**@{ */
560 
561 /** compares two monomials
562  *
563  *  gives 0 if monomials are equal */
564 static
SCIP_DECL_SORTPTRCOMP(monomialdataCompare)565 SCIP_DECL_SORTPTRCOMP(monomialdataCompare)
566 {
567    SCIP_EXPRDATA_MONOMIAL* monomial1;
568    SCIP_EXPRDATA_MONOMIAL* monomial2;
569 
570    int i;
571 
572    assert(elem1 != NULL);
573    assert(elem2 != NULL);
574 
575    monomial1 = (SCIP_EXPRDATA_MONOMIAL*)elem1;
576    monomial2 = (SCIP_EXPRDATA_MONOMIAL*)elem2;
577 
578    /* make sure, both monomials are equal */
579    SCIPexprSortMonomialFactors(monomial1);
580    SCIPexprSortMonomialFactors(monomial2);
581 
582    /* for the first factor where both monomials differ,
583     * we return either the difference in the child indices, if children are different
584     * or the sign of the difference in the exponents
585     */
586    for( i = 0; i < monomial1->nfactors && i < monomial2->nfactors; ++i )
587    {
588       if( monomial1->childidxs[i] != monomial2->childidxs[i] )
589          return monomial1->childidxs[i] - monomial2->childidxs[i];
590       if( monomial1->exponents[i] > monomial2->exponents[i] )
591          return 1;
592       else if( monomial1->exponents[i] < monomial2->exponents[i] )
593          return -1;
594    }
595 
596    /* if the factors of one monomial are a proper subset of the factors of the other monomial,
597     * we return the difference in the number of monomials
598     */
599    return monomial1->nfactors - monomial2->nfactors;
600 }
601 
602 /** ensures that the factors arrays of a monomial have at least a given size */
603 static
monomialdataEnsureFactorsSize(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_MONOMIAL * monomialdata,int minsize)604 SCIP_RETCODE monomialdataEnsureFactorsSize(
605    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
606    SCIP_EXPRDATA_MONOMIAL*  monomialdata,    /**< monomial data */
607    int                   minsize             /**< minimal size of factors arrays */
608    )
609 {
610    assert(blkmem != NULL);
611    assert(monomialdata != NULL);
612 
613    if( minsize > monomialdata->factorssize )
614    {
615       int newsize;
616 
617       newsize = calcGrowSize(minsize);
618       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->childidxs, monomialdata->factorssize, newsize) );
619       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->exponents, monomialdata->factorssize, newsize) );
620       monomialdata->factorssize = newsize;
621    }
622    assert(minsize <= monomialdata->factorssize);
623 
624    return SCIP_OKAY;
625 }
626 
627 /** creates SCIP_EXPRDATA_POLYNOMIAL data structure from given monomials */
628 static
polynomialdataCreate(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_POLYNOMIAL ** polynomialdata,int nmonomials,SCIP_EXPRDATA_MONOMIAL ** monomials,SCIP_Real constant,SCIP_Bool copymonomials)629 SCIP_RETCODE polynomialdataCreate(
630    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
631    SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
632    int                   nmonomials,         /**< number of monomials */
633    SCIP_EXPRDATA_MONOMIAL** monomials,       /**< monomials */
634    SCIP_Real             constant,           /**< constant part */
635    SCIP_Bool             copymonomials       /**< whether to copy monomials, or copy only given pointers, in which case polynomialdata assumes ownership of monomial structure */
636    )
637 {
638    assert(blkmem != NULL);
639    assert(polynomialdata != NULL);
640    assert(monomials != NULL || nmonomials == 0);
641 
642    SCIP_ALLOC( BMSallocBlockMemory(blkmem, polynomialdata) );
643 
644    (*polynomialdata)->constant = constant;
645    (*polynomialdata)->nmonomials  = nmonomials;
646    (*polynomialdata)->monomialssize = nmonomials;
647    (*polynomialdata)->monomials   = NULL;
648    (*polynomialdata)->sorted   = (nmonomials <= 1);
649 
650    if( nmonomials > 0 )
651    {
652       int i;
653 
654       if( copymonomials )
655       {
656          SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, nmonomials) );
657 
658          for( i = 0; i < nmonomials; ++i )
659          {
660             assert(monomials[i] != NULL);  /*lint !e613*/
661             SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i],
662                   monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) );  /*lint !e613*/
663          }
664       }
665       else
666       {
667          SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, monomials, nmonomials) );
668       }
669    }
670 
671    return SCIP_OKAY;
672 }
673 
674 /** creates a copy of a SCIP_EXPRDATA_POLYNOMIAL data structure */
675 static
polynomialdataCopy(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_POLYNOMIAL ** polynomialdata,SCIP_EXPRDATA_POLYNOMIAL * sourcepolynomialdata)676 SCIP_RETCODE polynomialdataCopy(
677    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
678    SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
679    SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata /**< polynomial data to copy */
680    )
681 {
682    assert(blkmem != NULL);
683    assert(polynomialdata != NULL);
684    assert(sourcepolynomialdata != NULL);
685 
686    SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, polynomialdata, sourcepolynomialdata) );
687 
688    (*polynomialdata)->monomialssize = sourcepolynomialdata->nmonomials;
689    if( sourcepolynomialdata->nmonomials > 0 )
690    {
691       int i;
692 
693       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize) );
694 
695       for( i = 0; i < sourcepolynomialdata->nmonomials; ++i )
696       {
697          assert(sourcepolynomialdata->monomials[i] != NULL);  /*lint !e613*/
698          SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i], sourcepolynomialdata->monomials[i]->coef,
699                sourcepolynomialdata->monomials[i]->nfactors, sourcepolynomialdata->monomials[i]->childidxs, sourcepolynomialdata->monomials[i]->exponents) );
700          (*polynomialdata)->monomials[i]->sorted = sourcepolynomialdata->monomials[i]->sorted;
701       }
702    }
703    else
704    {
705       (*polynomialdata)->monomials = NULL;
706    }
707 
708    return SCIP_OKAY;
709 }
710 
711 /** frees a SCIP_EXPRDATA_POLYNOMIAL data structure */
712 static
polynomialdataFree(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_POLYNOMIAL ** polynomialdata)713 void polynomialdataFree(
714    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
715    SCIP_EXPRDATA_POLYNOMIAL** polynomialdata /**< pointer to polynomial data to free */
716    )
717 {
718    assert(blkmem != NULL);
719    assert(polynomialdata != NULL);
720    assert(*polynomialdata != NULL);
721 
722    if( (*polynomialdata)->monomialssize > 0 )
723    {
724       int i;
725 
726       for( i = 0; i < (*polynomialdata)->nmonomials; ++i )
727       {
728          assert((*polynomialdata)->monomials[i] != NULL);
729          SCIPexprFreeMonomial(blkmem, &(*polynomialdata)->monomials[i]);
730          assert((*polynomialdata)->monomials[i] == NULL);
731       }
732 
733       BMSfreeBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize);
734    }
735    assert((*polynomialdata)->monomials == NULL);
736 
737    BMSfreeBlockMemory(blkmem, polynomialdata);
738 }
739 
740 /** ensures that the monomials array of a polynomial has at least a given size */
741 static
polynomialdataEnsureMonomialsSize(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_POLYNOMIAL * polynomialdata,int minsize)742 SCIP_RETCODE polynomialdataEnsureMonomialsSize(
743    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
744    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
745    int                   minsize             /**< minimal size of monomials array */
746    )
747 {
748    assert(blkmem != NULL);
749    assert(polynomialdata != NULL);
750 
751    ensureBlockMemoryArraySize(blkmem, &polynomialdata->monomials, &polynomialdata->monomialssize, minsize);
752    assert(minsize <= polynomialdata->monomialssize);
753 
754    return SCIP_OKAY;
755 }
756 
757 /** adds an array of monomials to a polynomial */
758 static
polynomialdataAddMonomials(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_POLYNOMIAL * polynomialdata,int nmonomials,SCIP_EXPRDATA_MONOMIAL ** monomials,SCIP_Bool copymonomials)759 SCIP_RETCODE polynomialdataAddMonomials(
760    BMS_BLKMEM*           blkmem,             /**< block memory of expression */
761    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
762    int                   nmonomials,         /**< number of monomials to add */
763    SCIP_EXPRDATA_MONOMIAL** monomials,       /**< the monomials to add */
764    SCIP_Bool             copymonomials       /**< whether to copy monomials or to assume ownership */
765    )
766 {
767    int i;
768 
769    assert(blkmem != NULL);
770    assert(polynomialdata != NULL);
771    assert(monomials != NULL || nmonomials == 0);
772 
773    if( nmonomials == 0 )
774       return SCIP_OKAY;
775 
776    SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials + nmonomials) );
777    assert(polynomialdata->monomialssize >= polynomialdata->nmonomials + nmonomials);
778 
779    if( copymonomials )
780    {
781       for( i = 0; i < nmonomials; ++i )
782       {
783          assert(monomials[i] != NULL);  /*lint !e613*/
784          SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials + i],
785                monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) );  /*lint !e613*/
786       }
787    }
788    else
789    {
790       BMScopyMemoryArray(&polynomialdata->monomials[polynomialdata->nmonomials], monomials, nmonomials);  /*lint !e866*/
791    }
792    polynomialdata->nmonomials += nmonomials;
793 
794    polynomialdata->sorted = (polynomialdata->nmonomials <= 1);
795 
796    return SCIP_OKAY;
797 }
798 
799 /** ensures that monomials of a polynomial are sorted */
800 static
polynomialdataSortMonomials(SCIP_EXPRDATA_POLYNOMIAL * polynomialdata)801 void polynomialdataSortMonomials(
802    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata  /**< polynomial expression */
803    )
804 {
805    assert(polynomialdata != NULL);
806 
807    if( polynomialdata->sorted )
808    {
809 #ifndef NDEBUG
810       int i;
811 
812       /* a polynom with more than one monoms can only be sorted if its monoms are sorted */
813       for( i = 1; i < polynomialdata->nmonomials; ++i )
814       {
815          assert(polynomialdata->monomials[i-1]->sorted);
816          assert(polynomialdata->monomials[i]->sorted);
817          assert(monomialdataCompare(polynomialdata->monomials[i-1], polynomialdata->monomials[i]) <= 0);
818       }
819 #endif
820       return;
821    }
822 
823    if( polynomialdata->nmonomials > 0 )
824       SCIPsortPtr((void**)polynomialdata->monomials, monomialdataCompare, polynomialdata->nmonomials);
825 
826    polynomialdata->sorted = TRUE;
827 }
828 
829 /** merges monomials that differ only in coefficient into a single monomial
830  *
831  *  Eliminates monomials with coefficient between -eps and eps.
832  */
833 static
polynomialdataMergeMonomials(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_POLYNOMIAL * polynomialdata,SCIP_Real eps,SCIP_Bool mergefactors)834 void polynomialdataMergeMonomials(
835    BMS_BLKMEM*           blkmem,             /**< block memory */
836    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
837    SCIP_Real             eps,                /**< threshold under which numbers are treat as zero */
838    SCIP_Bool             mergefactors        /**< whether to merge factors in monomials too */
839    )
840 {
841    int i;
842    int offset;
843    int oldnfactors;
844 
845    assert(polynomialdata != NULL);
846    assert(eps >= 0.0);
847 
848    polynomialdataSortMonomials(polynomialdata);
849 
850    /* merge monomials by adding their coefficients, eliminate monomials with no factors or zero coefficient*/
851    offset = 0;
852    i = 0;
853    while( i + offset < polynomialdata->nmonomials )
854    {
855       if( offset > 0 )
856       {
857          assert(polynomialdata->monomials[i] == NULL);
858          assert(polynomialdata->monomials[i+offset] != NULL);
859          polynomialdata->monomials[i] = polynomialdata->monomials[i+offset];
860 #ifndef NDEBUG
861          polynomialdata->monomials[i+offset] = NULL;
862 #endif
863       }
864 
865       if( mergefactors )
866       {
867          oldnfactors = polynomialdata->monomials[i]->nfactors;
868          SCIPexprMergeMonomialFactors(polynomialdata->monomials[i], eps);
869 
870          /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
871          if( oldnfactors != polynomialdata->monomials[i]->nfactors )
872             polynomialdata->sorted = FALSE;
873       }
874 
875       while( i+offset+1 < polynomialdata->nmonomials )
876       {
877          assert(polynomialdata->monomials[i+offset+1] != NULL);
878          if( mergefactors )
879          {
880             oldnfactors = polynomialdata->monomials[i+offset+1]->nfactors;
881             SCIPexprMergeMonomialFactors(polynomialdata->monomials[i+offset+1], eps);
882 
883             /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
884             if( oldnfactors != polynomialdata->monomials[i+offset+1]->nfactors )
885                polynomialdata->sorted = FALSE;
886          }
887          if( monomialdataCompare((void*)polynomialdata->monomials[i], (void*)polynomialdata->monomials[i+offset+1]) != 0 )
888             break;
889          polynomialdata->monomials[i]->coef += polynomialdata->monomials[i+offset+1]->coef;
890          SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i+offset+1]);
891          ++offset;
892       }
893 
894       if( polynomialdata->monomials[i]->nfactors == 0 )
895       {
896          /* constant monomial */
897          polynomialdata->constant += polynomialdata->monomials[i]->coef;
898          SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
899          ++offset;
900          continue;
901       }
902 
903       if( EPSZ(polynomialdata->monomials[i]->coef, eps) )
904       {
905          SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
906          ++offset;
907          continue;
908       }
909 
910       ++i;
911    }
912 
913 #ifndef NDEBUG
914    for( ; i < polynomialdata->nmonomials; ++i )
915       assert(polynomialdata->monomials[i] == NULL);
916 #endif
917 
918    polynomialdata->nmonomials -= offset;
919 
920    if( EPSZ(polynomialdata->constant, eps) )
921       polynomialdata->constant = 0.0;
922 }
923 
924 /** multiplies each summand of a polynomial by a given constant */
925 static
polynomialdataMultiplyByConstant(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_POLYNOMIAL * polynomialdata,SCIP_Real factor)926 void polynomialdataMultiplyByConstant(
927    BMS_BLKMEM*           blkmem,             /**< block memory */
928    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
929    SCIP_Real             factor              /**< constant factor */
930    )
931 {
932    int i;
933 
934    assert(polynomialdata != NULL);
935 
936    if( factor == 1.0 )
937       return;
938 
939    if( factor == 0.0 )
940    {
941       for( i = 0; i < polynomialdata->nmonomials; ++i )
942          SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
943       polynomialdata->nmonomials = 0;
944    }
945    else
946    {
947       for( i = 0; i < polynomialdata->nmonomials; ++i )
948          SCIPexprChgMonomialCoef(polynomialdata->monomials[i], polynomialdata->monomials[i]->coef * factor);
949    }
950 
951    polynomialdata->constant *= factor;
952 }
953 
954 /** multiplies each summand of a polynomial by a given monomial */
955 static
polynomialdataMultiplyByMonomial(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_POLYNOMIAL * polynomialdata,SCIP_EXPRDATA_MONOMIAL * factor,int * childmap)956 SCIP_RETCODE polynomialdataMultiplyByMonomial(
957    BMS_BLKMEM*           blkmem,             /**< block memory */
958    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
959    SCIP_EXPRDATA_MONOMIAL* factor,           /**< monomial factor */
960    int*                  childmap            /**< map children in factor to children in expr, or NULL for 1:1 */
961    )
962 {
963    int i;
964 
965    assert(blkmem != NULL);
966    assert(factor != NULL);
967    assert(polynomialdata != NULL);
968 
969    if( factor->nfactors == 0 )
970    {
971       polynomialdataMultiplyByConstant(blkmem, polynomialdata, factor->coef);
972       return SCIP_OKAY;
973    }
974 
975    /* multiply each monomial by factor */
976    for( i = 0; i < polynomialdata->nmonomials; ++i )
977    {
978       SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i], factor, childmap) );
979    }
980 
981    /* add new monomial for constant multiplied by factor */
982    if( polynomialdata->constant != 0.0 )
983    {
984       SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
985       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
986       SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[polynomialdata->nmonomials], factor, childmap) );
987       ++polynomialdata->nmonomials;
988       polynomialdata->sorted = FALSE;
989       polynomialdata->constant = 0.0;
990    }
991 
992    return SCIP_OKAY;
993 }
994 
995 /** multiplies a polynomial by a polynomial
996  *
997  *  Factors need to be different.
998  */
999 static
polynomialdataMultiplyByPolynomial(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_POLYNOMIAL * polynomialdata,SCIP_EXPRDATA_POLYNOMIAL * factordata,int * childmap)1000 SCIP_RETCODE polynomialdataMultiplyByPolynomial(
1001    BMS_BLKMEM*           blkmem,             /**< block memory */
1002    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1003    SCIP_EXPRDATA_POLYNOMIAL* factordata,     /**< polynomial factor data */
1004    int*                  childmap            /**< map children in factor to children in polynomialdata, or NULL for 1:1 */
1005    )
1006 {
1007    int i1;
1008    int i2;
1009    int orignmonomials;
1010 
1011    assert(blkmem != NULL);
1012    assert(polynomialdata != NULL);
1013    assert(factordata != NULL);
1014    assert(polynomialdata != factordata);
1015 
1016    if( factordata->nmonomials == 0 )
1017    {
1018       polynomialdataMultiplyByConstant(blkmem, polynomialdata, factordata->constant);
1019       return SCIP_OKAY;
1020    }
1021    assert(factordata->monomials != NULL);
1022 
1023    if( factordata->nmonomials == 1 && factordata->constant == 0.0 )
1024    {
1025       SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, polynomialdata, factordata->monomials[0], childmap) );
1026       return SCIP_OKAY;
1027    }
1028 
1029    /* turn constant into a monomial, so we can assume below that constant is 0.0 */
1030    if( polynomialdata->constant != 0.0 )
1031    {
1032       SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
1033       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
1034       ++polynomialdata->nmonomials;
1035       polynomialdata->sorted = FALSE;
1036       polynomialdata->constant = 0.0;
1037    }
1038 
1039    SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials * (factordata->nmonomials + (factordata->constant == 0.0 ? 0 : 1))) );
1040 
1041    /* for each monomial in factordata (except the last, if factordata->constant is 0),
1042     * duplicate monomials from polynomialdata and multiply them by the monomial for factordata */
1043    orignmonomials = polynomialdata->nmonomials;
1044    for( i2 = 0; i2 < factordata->nmonomials; ++i2 )
1045    {
1046       /* add a copy of original monomials to end of polynomialdata's monomials array */
1047       assert(polynomialdata->nmonomials + orignmonomials <= polynomialdata->monomialssize); /* reallocating in polynomialdataAddMonomials would make the polynomialdata->monomials invalid, so assert that above the monomials array was made large enough */
1048       SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, orignmonomials, polynomialdata->monomials, TRUE) );
1049       assert(polynomialdata->nmonomials == (i2+2) * orignmonomials);
1050 
1051       /* multiply each copied monomial by current monomial from factordata */
1052       for( i1 = (i2+1) * orignmonomials; i1 < (i2+2) * orignmonomials; ++i1 )
1053       {
1054          SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1055       }
1056 
1057       if( factordata->constant == 0.0 && i2 == factordata->nmonomials - 2 )
1058       {
1059          ++i2;
1060          break;
1061       }
1062    }
1063 
1064    if( factordata->constant != 0.0 )
1065    {
1066       assert(i2 == factordata->nmonomials);
1067       /* multiply original monomials in polynomialdata by constant in factordata */
1068       for( i1 = 0; i1 < orignmonomials; ++i1 )
1069          SCIPexprChgMonomialCoef(polynomialdata->monomials[i1], polynomialdata->monomials[i1]->coef * factordata->constant);
1070    }
1071    else
1072    {
1073       assert(i2 == factordata->nmonomials - 1);
1074       /* multiply original monomials in polynomialdata by last monomial in factordata */
1075       for( i1 = 0; i1 < orignmonomials; ++i1 )
1076       {
1077          SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1078       }
1079    }
1080 
1081    return SCIP_OKAY;
1082 }
1083 
1084 /** takes a power of a polynomial
1085  *
1086  *  Exponent needs to be an integer,
1087  *  polynomial needs to be a monomial, if exponent is negative.
1088  */
1089 static
polynomialdataPower(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_POLYNOMIAL * polynomialdata,int exponent)1090 SCIP_RETCODE polynomialdataPower(
1091    BMS_BLKMEM*           blkmem,             /**< block memory */
1092    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1093    int                   exponent            /**< exponent of power operation */
1094    )
1095 {
1096    SCIP_EXPRDATA_POLYNOMIAL* factor;
1097    int i;
1098 
1099    assert(blkmem != NULL);
1100    assert(polynomialdata != NULL);
1101 
1102    if( exponent == 0 )
1103    {
1104       /* x^0 = 1, except if x = 0 */
1105       if( polynomialdata->nmonomials == 0 && polynomialdata->constant == 0.0 )
1106       {
1107          polynomialdata->constant = 0.0;
1108       }
1109       else
1110       {
1111          polynomialdata->constant = 1.0;
1112 
1113          for( i = 0; i < polynomialdata->nmonomials; ++i )
1114             SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
1115          polynomialdata->nmonomials = 0;
1116       }
1117 
1118       return SCIP_OKAY;
1119    }
1120 
1121    if( exponent == 1 )
1122       return SCIP_OKAY;
1123 
1124    if( polynomialdata->nmonomials == 1 && polynomialdata->constant == 0.0 )
1125    {
1126       /* polynomial is a single monomial */
1127       SCIPexprMonomialPower(polynomialdata->monomials[0], exponent);
1128       return SCIP_OKAY;
1129    }
1130 
1131    if( polynomialdata->nmonomials == 0 )
1132    {
1133       /* polynomial is a constant */
1134       polynomialdata->constant = pow(polynomialdata->constant, (SCIP_Real)exponent);
1135       return SCIP_OKAY;
1136    }
1137 
1138    assert(exponent >= 2); /* negative exponents not allowed if more than one monom */
1139 
1140    /* todo improve, look how SCIPintervalPowerScalar in intervalarith.c does it */
1141 
1142    /* get copy of our polynomial */
1143    SCIP_CALL( polynomialdataCopy(blkmem, &factor, polynomialdata) );
1144 
1145    /* do repeated multiplication */
1146    for( i = 2; i <= exponent; ++i )
1147    {
1148       SCIP_CALL( polynomialdataMultiplyByPolynomial(blkmem, polynomialdata, factor, NULL) );
1149       polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
1150    }
1151 
1152    /* free copy again */
1153    polynomialdataFree(blkmem, &factor);
1154 
1155    return SCIP_OKAY;
1156 }
1157 
1158 /** applies a mapping of child indices to the indices used in polynomial monomials */
1159 static
polynomialdataApplyChildmap(SCIP_EXPRDATA_POLYNOMIAL * polynomialdata,int * childmap)1160 void polynomialdataApplyChildmap(
1161    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1162    int*                  childmap            /**< mapping of child indices */
1163    )
1164 {
1165    SCIP_EXPRDATA_MONOMIAL* monomial;
1166    int i;
1167    int j;
1168 
1169    assert(polynomialdata != NULL);
1170 
1171    for( i = 0; i < polynomialdata->nmonomials; ++i )
1172    {
1173       monomial = polynomialdata->monomials[i];
1174       assert(monomial != NULL);
1175 
1176       for( j = 0; j < monomial->nfactors; ++j )
1177       {
1178          monomial->childidxs[j] = childmap[monomial->childidxs[j]];
1179          assert(monomial->childidxs[j] >= 0);
1180       }
1181       monomial->sorted = FALSE;
1182    }
1183 
1184    polynomialdata->sorted = FALSE;
1185 }
1186 
1187 /** replaces a factor in a monomial by a polynomial and expands the result */
1188 static
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)1189 SCIP_RETCODE polynomialdataExpandMonomialFactor(
1190    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
1191    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
1192    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data where to expand a monomial */
1193    int                   monomialpos,        /**< position of monomial which factor to expand */
1194    int                   factorpos,          /**< position of factor in monomial to expand */
1195    SCIP_EXPRDATA_POLYNOMIAL* factorpolynomial,/**< polynomial that should replace factor */
1196    int*                  childmap,           /**< map of child indices in factorpolynomial to children of polynomial */
1197    int                   maxexpansionexponent,/**< maximal exponent for which polynomials (with > 1 summands) are expanded */
1198    SCIP_Bool*            success             /**< buffer to store whether expansion has been done */
1199    )
1200 {
1201    SCIP_EXPRDATA_POLYNOMIAL* factorpolynomialcopy;
1202    SCIP_EXPRDATA_MONOMIAL* monomial;
1203    int i;
1204 
1205    assert(blkmem != NULL);
1206    assert(polynomialdata != NULL);
1207    assert(factorpolynomial != NULL);
1208    assert(childmap != NULL || factorpolynomial->nmonomials == 0);
1209    assert(success != NULL);
1210    assert(monomialpos >= 0);
1211    assert(monomialpos < polynomialdata->nmonomials);
1212    assert(factorpos >= 0);
1213 
1214    monomial = polynomialdata->monomials[monomialpos];
1215    assert(monomial != NULL);
1216    assert(factorpos < monomial->nfactors);
1217 
1218    *success = TRUE;
1219 
1220    if( factorpolynomial->nmonomials == 0 )
1221    {
1222       /* factorpolynomial is a constant */
1223 
1224       if( !EPSISINT(monomial->exponents[factorpos], 0.0) && factorpolynomial->constant < 0.0 )  /*lint !e835*/
1225       {
1226          /* if polynomial is a negative constant and our exponent is not integer, then cannot do expansion */
1227          SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", factorpolynomial->constant, monomial->exponents[factorpos]);
1228          *success = FALSE;
1229          return SCIP_OKAY;
1230       }
1231       monomial->coef *= pow(factorpolynomial->constant, monomial->exponents[factorpos]);
1232 
1233       /* move last factor to position factorpos */
1234       if( factorpos < monomial->nfactors-1 )
1235       {
1236          monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1237          monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1238       }
1239       --monomial->nfactors;
1240       monomial->sorted = FALSE;
1241       polynomialdata->sorted = FALSE;
1242 
1243       return SCIP_OKAY;
1244    }
1245 
1246    if( factorpolynomial->constant == 0.0 && factorpolynomial->nmonomials == 1 )
1247    {
1248       /* factorpolynomial is a single monomial */
1249       SCIP_EXPRDATA_MONOMIAL* factormonomial;
1250       int childidx;
1251       SCIP_Real exponent;
1252 
1253       factormonomial = factorpolynomial->monomials[0];
1254       assert(factormonomial != NULL);
1255 
1256       if( !EPSISINT(monomial->exponents[factorpos], 0.0) )  /*lint !e835*/
1257       {
1258          if( factormonomial->coef < 0.0 )
1259          {
1260             /* if coefficient of monomial is negative and our exponent is not integer, then do not do expansion
1261              * @todo the only case where this could make sense is if the factors can be negative, i.e., when we have negative arguments with an odd exponent: (-x^a)^b = (-x)^(ab) for a odd
1262              */
1263             *success = FALSE;
1264             return SCIP_OKAY;
1265          }
1266          if( factormonomial->nfactors > 1 )
1267          {
1268             /* @todo if there is an even number of factors in factormonomial that are negative, then they always multiply to something positive
1269              * however, we cannot expand them as below, since we cannot compute the single powers
1270              * since we do not have the bounds on the factors here, we skip expansion in this case
1271              * MINLPLib instances tls2,4,6 are examples where we are loosing here (do not recognize convexity)
1272              */
1273             *success = FALSE;
1274             return SCIP_OKAY;
1275          }
1276       }
1277 
1278       SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + factormonomial->nfactors) );
1279 
1280       for( i = 0; i < factormonomial->nfactors; ++i )
1281       {
1282          childidx = childmap[factormonomial->childidxs[i]];  /*lint !e613*/
1283          /* can do this because monomial->exponents[factorpos] is assumed to be integer or factormonomial has positive coefficient and only one factor
1284           * thus, if factormonomial->exponents[i] is fractional, then we can assume that it's argument is positive
1285           */
1286          exponent = factormonomial->exponents[i] * monomial->exponents[factorpos];
1287          SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
1288       }
1289 
1290       monomial->coef *= pow(factormonomial->coef, monomial->exponents[factorpos]);
1291 
1292       /* move last factor to position factorpos */
1293       if( factorpos < monomial->nfactors-1 )
1294       {
1295          monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1296          monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1297       }
1298       --monomial->nfactors;
1299       monomial->sorted = FALSE;
1300       polynomialdata->sorted = FALSE;
1301 
1302       return SCIP_OKAY;
1303    }
1304 
1305    /* if exponent is negative or fractional and the polynomial is not just a monomial, then we cannot do expansion */
1306    if( !EPSISINT(monomial->exponents[factorpos], 0.0) || monomial->exponents[factorpos] < 0.0 )  /*lint !e835*/
1307    {
1308       *success = FALSE;
1309       return SCIP_OKAY;
1310    }
1311 
1312    /* if exponent is too large, skip expansion */
1313    if( monomial->exponents[factorpos] > maxexpansionexponent )
1314    {
1315       *success = FALSE;
1316       return SCIP_OKAY;
1317    }
1318 
1319    /* check whether maximal degree of expansion would exceed maxexpansionexponent
1320     * that is, assume monomial is f1^a1 f2^a2 ... and we want to expand f1 = (g11^beta11 g12^beta12... + g21^beta21 g22^beta22 ... + ...)
1321     * then we do this only if all ai and all beta are > 0.0 and a1 max(beta11+beta12+..., beta21+beta22+..., ...) + a2 + ... < maxexpansionexponent
1322     * exception (there need to be one) is if monomial is just f1
1323     */
1324    if( maxexpansionexponent < INT_MAX && (monomial->nfactors > 1 || monomial->exponents[factorpos] != 1.0) )
1325    {
1326       SCIP_Real restdegree;
1327       SCIP_Real degree;
1328       int j;
1329 
1330       restdegree = -monomial->exponents[factorpos];
1331       for( i = 0; i < monomial->nfactors; ++i )
1332       {
1333          if( monomial->exponents[i] < 0.0 )
1334          {
1335             /* ai < 0.0 */
1336             SCIPdebugMessage("skip expansion because factor %d in monomial has negative exponent\n", i);
1337             *success = FALSE;
1338             return SCIP_OKAY;
1339          }
1340          restdegree += monomial->exponents[i];
1341       }
1342 
1343       for( i = 0; i < factorpolynomial->nmonomials; ++i )
1344       {
1345          degree = 0.0;
1346          for( j = 0; j < factorpolynomial->monomials[i]->nfactors; ++j )
1347          {
1348             if( factorpolynomial->monomials[i]->exponents[j] < 0.0 )
1349             {
1350                /* beta_ij < 0.0 */
1351                SCIPdebugMessage("skip expansion because %d'th factor in %d'th monomial of factorpolynomial is negative\n", i, j);
1352                *success = FALSE;
1353                return SCIP_OKAY;
1354             }
1355             degree += factorpolynomial->monomials[i]->exponents[j];
1356          }
1357          if( degree * monomial->exponents[factorpos] + restdegree > maxexpansionexponent )
1358          {
1359             /* (beta_i1+beta_i2+...)*monomial->exponents[factorpos] + rest > maxexpansion */
1360             SCIPdebugMessage("skip expansion because degree of %d'th monomial would yield degree %g > max = %d in expansion\n",
1361                i, degree * monomial->exponents[factorpos] + restdegree, maxexpansionexponent);
1362             *success = FALSE;
1363             return SCIP_OKAY;
1364          }
1365       }
1366    }
1367 
1368    /* create a copy of factor */
1369    SCIP_CALL( polynomialdataCopy(blkmem, &factorpolynomialcopy, factorpolynomial) );
1370    /* apply childmap to copy */
1371    polynomialdataApplyChildmap(factorpolynomialcopy, childmap);
1372    /* create power of factor */
1373    SCIP_CALL( polynomialdataPower(blkmem, factorpolynomialcopy, (int)EPSFLOOR(monomial->exponents[factorpos], 0.0)) );  /*lint !e835*/
1374 
1375    /* remove factor from monomial by moving last factor to position factorpos */
1376    if( factorpos < monomial->nfactors-1 )
1377    {
1378       monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1379       monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1380    }
1381    --monomial->nfactors;
1382    monomial->sorted = FALSE;
1383 
1384    /* multiply factor with this reduced monomial */
1385    SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, factorpolynomialcopy, monomial, NULL) );
1386 
1387    /* remove monomial from polynomial and move last monomial to monomialpos */
1388    SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[monomialpos]);
1389    if( monomialpos < polynomialdata->nmonomials-1 )
1390       polynomialdata->monomials[monomialpos] = polynomialdata->monomials[polynomialdata->nmonomials-1];
1391    --polynomialdata->nmonomials;
1392    polynomialdata->sorted = FALSE;
1393 
1394    /* add factorpolynomialcopy to polynomial */
1395    SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, factorpolynomialcopy->nmonomials, factorpolynomialcopy->monomials, FALSE) );
1396    polynomialdata->constant += factorpolynomialcopy->constant;
1397 
1398    factorpolynomialcopy->nmonomials = 0;
1399    polynomialdataFree(blkmem, &factorpolynomialcopy);
1400 
1401    return SCIP_OKAY;
1402 }
1403 
1404 /**@} */
1405 
1406 /**@name Expression operand private methods */
1407 /**@{ */
1408 
1409 /** a default implementation of expression interval evaluation that always gives a correct result */
1410 static
SCIP_DECL_EXPRINTEVAL(exprevalIntDefault)1411 SCIP_DECL_EXPRINTEVAL( exprevalIntDefault )
1412 {   /*lint --e{715}*/
1413    SCIPintervalSetEntire(infinity, result);
1414 
1415    return SCIP_OKAY;
1416 }
1417 
1418 /** a default implementation of expression curvature check that always gives a correct result */
1419 static
SCIP_DECL_EXPRCURV(exprcurvDefault)1420 SCIP_DECL_EXPRCURV( exprcurvDefault )
1421 {   /*lint --e{715}*/
1422    *result = SCIP_EXPRCURV_UNKNOWN;
1423 
1424    return SCIP_OKAY;
1425 }
1426 
1427 /** point evaluation for EXPR_VAR */
1428 static
SCIP_DECL_EXPREVAL(exprevalVar)1429 SCIP_DECL_EXPREVAL( exprevalVar )
1430 {   /*lint --e{715}*/
1431    assert(result  != NULL);
1432    assert(varvals != NULL);
1433 
1434    *result = varvals[opdata.intval];
1435 
1436    return SCIP_OKAY;
1437 }
1438 
1439 /** interval evaluation for EXPR_VAR */
1440 static
SCIP_DECL_EXPRINTEVAL(exprevalIntVar)1441 SCIP_DECL_EXPRINTEVAL( exprevalIntVar )
1442 {   /*lint --e{715}*/
1443    assert(result  != NULL);
1444    assert(varvals != NULL);
1445 
1446    *result = varvals[opdata.intval];
1447 
1448    return SCIP_OKAY;
1449 }
1450 
1451 /** curvature for EXPR_VAR */
1452 static
SCIP_DECL_EXPRCURV(exprcurvVar)1453 SCIP_DECL_EXPRCURV( exprcurvVar )
1454 {   /*lint --e{715}*/
1455    assert(result  != NULL);
1456 
1457    *result = SCIP_EXPRCURV_LINEAR;
1458 
1459    return SCIP_OKAY;
1460 }
1461 
1462 /** point evaluation for EXPR_CONST */
1463 static
SCIP_DECL_EXPREVAL(exprevalConst)1464 SCIP_DECL_EXPREVAL( exprevalConst )
1465 {   /*lint --e{715}*/
1466    assert(result != NULL);
1467 
1468    *result = opdata.dbl;
1469 
1470    return SCIP_OKAY;
1471 }
1472 
1473 /** interval evaluation for EXPR_CONST */
1474 static
SCIP_DECL_EXPRINTEVAL(exprevalIntConst)1475 SCIP_DECL_EXPRINTEVAL( exprevalIntConst )
1476 {   /*lint --e{715}*/
1477    assert(result != NULL);
1478 
1479    SCIPintervalSet(result, opdata.dbl);
1480 
1481    return SCIP_OKAY;
1482 }
1483 
1484 /** curvature for EXPR_CONST */
1485 static
SCIP_DECL_EXPRCURV(exprcurvConst)1486 SCIP_DECL_EXPRCURV( exprcurvConst )
1487 {   /*lint --e{715}*/
1488    assert(result  != NULL);
1489 
1490    *result = SCIP_EXPRCURV_LINEAR;
1491 
1492    return SCIP_OKAY;
1493 }
1494 
1495 /** point evaluation for EXPR_PARAM */
1496 static
SCIP_DECL_EXPREVAL(exprevalParam)1497 SCIP_DECL_EXPREVAL( exprevalParam )
1498 {   /*lint --e{715}*/
1499    assert(result    != NULL);
1500    assert(paramvals != NULL );
1501 
1502    *result = paramvals[opdata.intval];
1503 
1504    return SCIP_OKAY;
1505 }
1506 
1507 /** interval evaluation for EXPR_PARAM */
1508 static
SCIP_DECL_EXPRINTEVAL(exprevalIntParam)1509 SCIP_DECL_EXPRINTEVAL( exprevalIntParam )
1510 {   /*lint --e{715}*/
1511    assert(result    != NULL);
1512    assert(paramvals != NULL );
1513 
1514    SCIPintervalSet(result, paramvals[opdata.intval]);
1515 
1516    return SCIP_OKAY;
1517 }
1518 
1519 /** curvature for EXPR_PARAM */
1520 static
SCIP_DECL_EXPRCURV(exprcurvParam)1521 SCIP_DECL_EXPRCURV( exprcurvParam )
1522 {   /*lint --e{715}*/
1523    assert(result  != NULL);
1524 
1525    *result = SCIP_EXPRCURV_LINEAR;
1526 
1527    return SCIP_OKAY;
1528 }
1529 
1530 /** point evaluation for EXPR_PLUS */
1531 static
SCIP_DECL_EXPREVAL(exprevalPlus)1532 SCIP_DECL_EXPREVAL( exprevalPlus )
1533 {   /*lint --e{715}*/
1534    assert(result  != NULL);
1535    assert(argvals != NULL);
1536 
1537    *result = argvals[0] + argvals[1];
1538 
1539    return SCIP_OKAY;
1540 }
1541 
1542 /** interval evaluation for EXPR_PLUS */
1543 static
SCIP_DECL_EXPRINTEVAL(exprevalIntPlus)1544 SCIP_DECL_EXPRINTEVAL( exprevalIntPlus )
1545 {   /*lint --e{715}*/
1546    assert(result  != NULL);
1547    assert(argvals != NULL);
1548 
1549    SCIPintervalAdd(infinity, result, argvals[0], argvals[1]);
1550 
1551    return SCIP_OKAY;
1552 }
1553 
1554 /** curvature for EXPR_PLUS */
1555 static
SCIP_DECL_EXPRCURV(exprcurvPlus)1556 SCIP_DECL_EXPRCURV( exprcurvPlus )
1557 {   /*lint --e{715}*/
1558    assert(result  != NULL);
1559    assert(argcurv != NULL);
1560 
1561    *result = SCIPexprcurvAdd(argcurv[0], argcurv[1]);
1562 
1563    return SCIP_OKAY;
1564 }
1565 
1566 /** point evaluation for EXPR_MINUS */
1567 static
SCIP_DECL_EXPREVAL(exprevalMinus)1568 SCIP_DECL_EXPREVAL( exprevalMinus )
1569 {   /*lint --e{715}*/
1570    assert(result  != NULL);
1571    assert(argvals != NULL);
1572 
1573    *result = argvals[0] - argvals[1];
1574 
1575    return SCIP_OKAY;
1576 }
1577 
1578 /** interval evaluation for EXPR_MINUS */
1579 static
SCIP_DECL_EXPRINTEVAL(exprevalIntMinus)1580 SCIP_DECL_EXPRINTEVAL( exprevalIntMinus )
1581 {   /*lint --e{715}*/
1582    assert(result  != NULL);
1583    assert(argvals != NULL);
1584 
1585    SCIPintervalSub(infinity, result, argvals[0], argvals[1]);
1586 
1587    return SCIP_OKAY;
1588 }
1589 
1590 /** curvature for EXPR_MINUS */
1591 static
SCIP_DECL_EXPRCURV(exprcurvMinus)1592 SCIP_DECL_EXPRCURV( exprcurvMinus )
1593 {   /*lint --e{715}*/
1594    assert(result  != NULL);
1595    assert(argcurv != NULL);
1596 
1597    *result = SCIPexprcurvAdd(argcurv[0], SCIPexprcurvNegate(argcurv[1]));
1598 
1599    return SCIP_OKAY;
1600 }
1601 
1602 /** point evaluation for EXPR_MUL */
1603 static
SCIP_DECL_EXPREVAL(exprevalMult)1604 SCIP_DECL_EXPREVAL( exprevalMult )
1605 {   /*lint --e{715}*/
1606    assert(result  != NULL);
1607    assert(argvals != NULL);
1608 
1609    *result = argvals[0] * argvals[1];
1610 
1611    return SCIP_OKAY;
1612 }
1613 
1614 /** interval evaluation for EXPR_MUL */
1615 static
SCIP_DECL_EXPRINTEVAL(exprevalIntMult)1616 SCIP_DECL_EXPRINTEVAL( exprevalIntMult )
1617 {   /*lint --e{715}*/
1618    assert(result  != NULL);
1619    assert(argvals != NULL);
1620 
1621    SCIPintervalMul(infinity, result, argvals[0], argvals[1]);
1622 
1623    return SCIP_OKAY;
1624 }
1625 
1626 /** curvature for EXPR_MUL */
1627 static
SCIP_DECL_EXPRCURV(exprcurvMult)1628 SCIP_DECL_EXPRCURV( exprcurvMult )
1629 {   /*lint --e{715}*/
1630    assert(result    != NULL);
1631    assert(argcurv   != NULL);
1632    assert(argbounds != NULL);
1633 
1634    /* if one factor is constant, then product is
1635     * - linear, if constant is 0.0
1636     * - same curvature as other factor, if constant is positive
1637     * - negated curvature of other factor, if constant is negative
1638     *
1639     * if both factors are not constant, then product may not be convex nor concave
1640     */
1641    if( argbounds[1].inf == argbounds[1].sup )  /*lint !e777*/
1642       *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1643    else if( argbounds[0].inf == argbounds[0].sup )  /*lint !e777*/
1644       *result = SCIPexprcurvMultiply(argbounds[0].inf, argcurv[1]);
1645    else
1646       *result = SCIP_EXPRCURV_UNKNOWN;
1647 
1648    return SCIP_OKAY;
1649 }
1650 
1651 /** point evaluation for EXPR_DIV */
1652 static
1653 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1654 __attribute__((no_sanitize_undefined))
1655 #endif
SCIP_DECL_EXPREVAL(exprevalDiv)1656 SCIP_DECL_EXPREVAL( exprevalDiv )
1657 {   /*lint --e{715}*/
1658    assert(result  != NULL);
1659    assert(argvals != NULL);
1660 
1661    *result = argvals[0] / argvals[1];
1662 
1663    return SCIP_OKAY;
1664 }
1665 
1666 /** interval evaluation for EXPR_DIV */
1667 static
SCIP_DECL_EXPRINTEVAL(exprevalIntDiv)1668 SCIP_DECL_EXPRINTEVAL( exprevalIntDiv )
1669 {   /*lint --e{715}*/
1670    assert(result  != NULL);
1671    assert(argvals != NULL);
1672 
1673    SCIPintervalDiv(infinity, result, argvals[0], argvals[1]);
1674 
1675    return SCIP_OKAY;
1676 }
1677 
1678 /** curvature for EXPR_DIV */
1679 static
SCIP_DECL_EXPRCURV(exprcurvDiv)1680 SCIP_DECL_EXPRCURV( exprcurvDiv )
1681 {   /*lint --e{715}*/
1682    assert(result    != NULL);
1683    assert(argcurv   != NULL);
1684    assert(argbounds != NULL);
1685 
1686    /* if denominator is constant, then quotient has curvature sign(denominator) * curv(nominator)
1687     *
1688     * if nominator is a constant, then quotient is
1689     * - sign(nominator) * convex, if denominator is concave and positive
1690     * - sign(nominator) * concave, if denominator is convex and negative
1691     *
1692     * if denominator is positive but convex, then we don't know, e.g.,
1693     *   - 1/x^2 is convex for x>=0
1694     *   - 1/(1+(x-1)^2) is neither convex nor concave for x >= 0
1695     *
1696     * if both nominator and denominator are not constant, then quotient may not be convex nor concave
1697     */
1698    if( argbounds[1].inf == argbounds[1].sup )  /*lint !e777*/
1699    {
1700       /* denominator is constant */
1701       *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1702    }
1703    else if( argbounds[0].inf == argbounds[0].sup )  /*lint !e777*/
1704    {
1705       /* nominator is constant */
1706       if( argbounds[1].inf >= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
1707          *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONVEX);
1708       else if( argbounds[1].sup <= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
1709          *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONCAVE);
1710       else
1711          *result = SCIP_EXPRCURV_UNKNOWN;
1712    }
1713    else
1714    {
1715       /* denominator and nominator not constant */
1716       *result = SCIP_EXPRCURV_UNKNOWN;
1717    }
1718 
1719    return SCIP_OKAY;
1720 }
1721 
1722 /** point evaluation for EXPR_SQUARE */
1723 static
SCIP_DECL_EXPREVAL(exprevalSquare)1724 SCIP_DECL_EXPREVAL( exprevalSquare )
1725 {   /*lint --e{715}*/
1726    assert(result  != NULL);
1727    assert(argvals != NULL);
1728 
1729    *result = argvals[0] * argvals[0];
1730 
1731    return SCIP_OKAY;
1732 }
1733 
1734 /** interval evaluation for EXPR_SQUARE */
1735 static
SCIP_DECL_EXPRINTEVAL(exprevalIntSquare)1736 SCIP_DECL_EXPRINTEVAL( exprevalIntSquare )
1737 {   /*lint --e{715}*/
1738    assert(result  != NULL);
1739    assert(argvals != NULL);
1740 
1741    SCIPintervalSquare(infinity, result, argvals[0]);
1742 
1743    return SCIP_OKAY;
1744 }
1745 
1746 /** curvature for EXPR_SQUARE */
1747 static
SCIP_DECL_EXPRCURV(exprcurvSquare)1748 SCIP_DECL_EXPRCURV( exprcurvSquare )
1749 {   /*lint --e{715}*/
1750    assert(result    != NULL);
1751    assert(argcurv   != NULL);
1752    assert(argbounds != NULL);
1753 
1754    *result = SCIPexprcurvPower(argbounds[0], argcurv[0], 2.0);
1755 
1756    return SCIP_OKAY;
1757 }
1758 
1759 /** point evaluation for EXPR_SQRT */
1760 static
SCIP_DECL_EXPREVAL(exprevalSquareRoot)1761 SCIP_DECL_EXPREVAL( exprevalSquareRoot )
1762 {   /*lint --e{715}*/
1763    assert(result  != NULL);
1764    assert(argvals != NULL);
1765 
1766    *result = sqrt(argvals[0]);
1767 
1768    return SCIP_OKAY;
1769 }
1770 
1771 /** interval evaluation for EXPR_SQRT */
1772 static
SCIP_DECL_EXPRINTEVAL(exprevalIntSquareRoot)1773 SCIP_DECL_EXPRINTEVAL( exprevalIntSquareRoot )
1774 {   /*lint --e{715}*/
1775    assert(result  != NULL);
1776    assert(argvals != NULL);
1777 
1778    SCIPintervalSquareRoot(infinity, result, argvals[0]);
1779 
1780    return SCIP_OKAY;
1781 }
1782 
1783 /** curvature for EXPR_SQRT */
1784 static
SCIP_DECL_EXPRCURV(exprcurvSquareRoot)1785 SCIP_DECL_EXPRCURV( exprcurvSquareRoot )
1786 {   /*lint --e{715}*/
1787    assert(result    != NULL);
1788    assert(argcurv   != NULL);
1789 
1790    /* square-root is concave, if child is concave
1791     * otherwise, we don't know
1792     */
1793 
1794    if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
1795       *result = SCIP_EXPRCURV_CONCAVE;
1796    else
1797       *result = SCIP_EXPRCURV_UNKNOWN;
1798 
1799    return SCIP_OKAY;
1800 }
1801 
1802 /** point evaluation for EXPR_REALPOWER */
1803 static
SCIP_DECL_EXPREVAL(exprevalRealPower)1804 SCIP_DECL_EXPREVAL( exprevalRealPower )
1805 {   /*lint --e{715}*/
1806    assert(result  != NULL);
1807    assert(argvals != NULL);
1808 
1809    *result = pow(argvals[0], opdata.dbl);
1810 
1811    return SCIP_OKAY;
1812 }
1813 
1814 /** interval evaluation for EXPR_REALPOWER */
1815 static
SCIP_DECL_EXPRINTEVAL(exprevalIntRealPower)1816 SCIP_DECL_EXPRINTEVAL( exprevalIntRealPower )
1817 {   /*lint --e{715}*/
1818    assert(result  != NULL);
1819    assert(argvals != NULL);
1820 
1821    SCIPintervalPowerScalar(infinity, result, argvals[0], opdata.dbl);
1822 
1823    return SCIP_OKAY;
1824 }
1825 
1826 /** curvature for EXPR_REALPOWER */
1827 static
SCIP_DECL_EXPRCURV(exprcurvRealPower)1828 SCIP_DECL_EXPRCURV( exprcurvRealPower )
1829 {   /*lint --e{715}*/
1830    assert(result    != NULL);
1831    assert(argcurv   != NULL);
1832    assert(argbounds != NULL);
1833 
1834    *result = SCIPexprcurvPower(argbounds[0], argcurv[0], opdata.dbl);
1835 
1836    return SCIP_OKAY;
1837 }
1838 
1839 /** point evaluation for EXPR_INTPOWER */
1840 static
1841 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1842 __attribute__((no_sanitize_undefined))
1843 #endif
SCIP_DECL_EXPREVAL(exprevalIntPower)1844 SCIP_DECL_EXPREVAL( exprevalIntPower )
1845 {   /*lint --e{715}*/
1846    assert(result  != NULL);
1847    assert(argvals != NULL);
1848 
1849    switch( opdata.intval )
1850    {
1851    case -1:
1852       *result = 1.0 / argvals[0];
1853       return SCIP_OKAY;
1854 
1855    case 0:
1856       *result = 1.0;
1857       return SCIP_OKAY;
1858 
1859    case 1:
1860       *result = argvals[0];
1861       return SCIP_OKAY;
1862 
1863    case 2:
1864       *result = argvals[0] * argvals[0];
1865       return SCIP_OKAY;
1866 
1867    default:
1868       *result = pow(argvals[0], (SCIP_Real)opdata.intval);
1869    }
1870 
1871    return SCIP_OKAY;
1872 }
1873 
1874 /** interval evaluation for EXPR_INTPOWER */
1875 static
SCIP_DECL_EXPRINTEVAL(exprevalIntIntPower)1876 SCIP_DECL_EXPRINTEVAL( exprevalIntIntPower )
1877 {   /*lint --e{715}*/
1878    assert(result  != NULL);
1879    assert(argvals != NULL);
1880 
1881    SCIPintervalPowerScalar(infinity, result, argvals[0], (SCIP_Real)opdata.intval);
1882 
1883    return SCIP_OKAY;
1884 }
1885 
1886 /** curvature for EXPR_INTPOWER */
1887 static
SCIP_DECL_EXPRCURV(exprcurvIntPower)1888 SCIP_DECL_EXPRCURV( exprcurvIntPower )
1889 {   /*lint --e{715}*/
1890    assert(result    != NULL);
1891    assert(argcurv   != NULL);
1892    assert(argbounds != NULL);
1893 
1894    *result = SCIPexprcurvPower(argbounds[0], argcurv[0], (SCIP_Real)opdata.intval);
1895 
1896    return SCIP_OKAY;
1897 }
1898 
1899 /** point evaluation for EXPR_SIGNPOWER */
1900 static
SCIP_DECL_EXPREVAL(exprevalSignPower)1901 SCIP_DECL_EXPREVAL( exprevalSignPower )
1902 {   /*lint --e{715}*/
1903    assert(result  != NULL);
1904    assert(argvals != NULL);
1905 
1906    if( argvals[0] > 0 )
1907       *result =  pow( argvals[0], opdata.dbl);
1908    else
1909       *result = -pow(-argvals[0], opdata.dbl);
1910 
1911    return SCIP_OKAY;
1912 }
1913 
1914 /** interval evaluation for EXPR_SIGNPOWER */
1915 static
SCIP_DECL_EXPRINTEVAL(exprevalIntSignPower)1916 SCIP_DECL_EXPRINTEVAL( exprevalIntSignPower )
1917 {   /*lint --e{715}*/
1918    assert(result  != NULL);
1919    assert(argvals != NULL);
1920 
1921    SCIPintervalSignPowerScalar(infinity, result, argvals[0], opdata.dbl);
1922 
1923    return SCIP_OKAY;
1924 }
1925 
1926 /** curvature for EXPR_SIGNPOWER */
1927 static
SCIP_DECL_EXPRCURV(exprcurvSignPower)1928 SCIP_DECL_EXPRCURV( exprcurvSignPower )
1929 {   /*lint --e{715}*/
1930    SCIP_INTERVAL tmp;
1931    SCIP_EXPRCURV left;
1932    SCIP_EXPRCURV right;
1933 
1934    assert(result    != NULL);
1935    assert(argcurv   != NULL);
1936    assert(argbounds != NULL);
1937 
1938    /* for x <= 0, signpower(x,c) = -(-x)^c
1939     * for x >= 0, signpower(x,c) =  ( x)^c
1940     *
1941     * thus, get curvatures for both parts and "intersect" them
1942     */
1943 
1944    if( argbounds[0].inf < 0 )
1945    {
1946       SCIPintervalSetBounds(&tmp, 0.0, -argbounds[0].inf);
1947       left = SCIPexprcurvNegate(SCIPexprcurvPower(tmp, SCIPexprcurvNegate(argcurv[0]), opdata.dbl));
1948    }
1949    else
1950    {
1951       left = SCIP_EXPRCURV_LINEAR;
1952    }
1953 
1954    if( argbounds[0].sup > 0 )
1955    {
1956       SCIPintervalSetBounds(&tmp, 0.0,  argbounds[0].sup);
1957       right = SCIPexprcurvPower(tmp, argcurv[0], opdata.dbl);
1958    }
1959    else
1960    {
1961       right = SCIP_EXPRCURV_LINEAR;
1962    }
1963 
1964    *result = (SCIP_EXPRCURV) (left & right);
1965 
1966    return SCIP_OKAY;
1967 }
1968 
1969 /** point evaluation for EXPR_EXP */
1970 static
SCIP_DECL_EXPREVAL(exprevalExp)1971 SCIP_DECL_EXPREVAL( exprevalExp )
1972 {   /*lint --e{715}*/
1973    assert(result  != NULL);
1974    assert(argvals != NULL);
1975 
1976    *result = exp(argvals[0]);
1977 
1978    return SCIP_OKAY;
1979 }
1980 
1981 /** interval evaluation for EXPR_EXP */
1982 static
SCIP_DECL_EXPRINTEVAL(exprevalIntExp)1983 SCIP_DECL_EXPRINTEVAL( exprevalIntExp )
1984 {   /*lint --e{715}*/
1985    assert(result  != NULL);
1986    assert(argvals != NULL);
1987 
1988    SCIPintervalExp(infinity, result, argvals[0]);
1989 
1990    return SCIP_OKAY;
1991 }
1992 
1993 /** curvature for EXPR_EXP */
1994 static
SCIP_DECL_EXPRCURV(exprcurvExp)1995 SCIP_DECL_EXPRCURV( exprcurvExp )
1996 {   /*lint --e{715}*/
1997    assert(result    != NULL);
1998    assert(argcurv   != NULL);
1999 
2000    /* expression is convex if child is convex
2001     * otherwise, we don't know
2002     */
2003    if( argcurv[0] & SCIP_EXPRCURV_CONVEX )
2004       *result = SCIP_EXPRCURV_CONVEX;
2005    else
2006       *result = SCIP_EXPRCURV_UNKNOWN;
2007 
2008    return SCIP_OKAY;
2009 }
2010 
2011 /** point evaluation for EXPR_LOG */
2012 static
SCIP_DECL_EXPREVAL(exprevalLog)2013 SCIP_DECL_EXPREVAL( exprevalLog )
2014 {   /*lint --e{715}*/
2015    assert(result  != NULL);
2016    assert(argvals != NULL);
2017 
2018    *result = log(argvals[0]);
2019 
2020    return SCIP_OKAY;
2021 }
2022 
2023 /** interval evaluation for EXPR_LOG */
2024 static
SCIP_DECL_EXPRINTEVAL(exprevalIntLog)2025 SCIP_DECL_EXPRINTEVAL( exprevalIntLog )
2026 {   /*lint --e{715}*/
2027    assert(result  != NULL);
2028    assert(argvals != NULL);
2029 
2030    SCIPintervalLog(infinity, result, argvals[0]);
2031 
2032    return SCIP_OKAY;
2033 }
2034 
2035 /** curvature for EXPR_LOG */
2036 static
SCIP_DECL_EXPRCURV(exprcurvLog)2037 SCIP_DECL_EXPRCURV( exprcurvLog )
2038 {   /*lint --e{715}*/
2039    assert(result    != NULL);
2040    assert(argcurv   != NULL);
2041 
2042    /* expression is concave if child is concave
2043     * otherwise, we don't know
2044     */
2045    if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
2046       *result = SCIP_EXPRCURV_CONCAVE;
2047    else
2048       *result = SCIP_EXPRCURV_UNKNOWN;
2049 
2050    return SCIP_OKAY;
2051 }
2052 
2053 /** point evaluation for EXPR_SIN */
2054 static
SCIP_DECL_EXPREVAL(exprevalSin)2055 SCIP_DECL_EXPREVAL( exprevalSin )
2056 {   /*lint --e{715}*/
2057    assert(result  != NULL);
2058    assert(argvals != NULL);
2059 
2060    *result = sin(argvals[0]);
2061 
2062    return SCIP_OKAY;
2063 }
2064 
2065 /** interval evaluation for EXPR_SIN */
2066 static
SCIP_DECL_EXPRINTEVAL(exprevalIntSin)2067 SCIP_DECL_EXPRINTEVAL( exprevalIntSin )
2068 {   /*lint --e{715}*/
2069    assert(result != NULL);
2070    assert(argvals != NULL);
2071    assert(nargs == 1);
2072 
2073    SCIPintervalSin(infinity, result, *argvals);
2074 
2075    return SCIP_OKAY;
2076 }
2077 
2078 /* @todo implement exprcurvSin */
2079 #define exprcurvSin exprcurvDefault
2080 
2081 /** point evaluation for EXPR_COS */
2082 static
SCIP_DECL_EXPREVAL(exprevalCos)2083 SCIP_DECL_EXPREVAL( exprevalCos )
2084 {   /*lint --e{715}*/
2085    assert(result  != NULL);
2086    assert(argvals != NULL);
2087 
2088    *result = cos(argvals[0]);
2089 
2090    return SCIP_OKAY;
2091 }
2092 
2093 /** interval evaluation for EXPR_COS */
2094 static
SCIP_DECL_EXPRINTEVAL(exprevalIntCos)2095 SCIP_DECL_EXPRINTEVAL( exprevalIntCos )
2096 {   /*lint --e{715}*/
2097    assert(result != NULL);
2098    assert(argvals != NULL);
2099    assert(nargs == 1);
2100 
2101    SCIPintervalCos(infinity, result, *argvals);
2102 
2103    return SCIP_OKAY;
2104 }
2105 
2106 /* @todo implement exprcurvCos */
2107 #define exprcurvCos exprcurvDefault
2108 
2109 /** point evaluation for EXPR_TAN */
2110 static
SCIP_DECL_EXPREVAL(exprevalTan)2111 SCIP_DECL_EXPREVAL( exprevalTan )
2112 {   /*lint --e{715}*/
2113    assert(result  != NULL);
2114    assert(argvals != NULL);
2115 
2116    *result = tan(argvals[0]);
2117 
2118    return SCIP_OKAY;
2119 }
2120 
2121 /* @todo implement SCIPintervalTan */
2122 #define exprevalIntTan exprevalIntDefault
2123 
2124 /* @todo implement exprcurvTan */
2125 #define exprcurvTan exprcurvDefault
2126 
2127 /* erf and erfi do not seem to exist on every system, and we cannot really handle them anyway, so they are currently disabled */
2128 #ifdef SCIP_DISABLED_CODE
2129 static
SCIP_DECL_EXPREVAL(exprevalErf)2130 SCIP_DECL_EXPREVAL( exprevalErf )
2131 {   /*lint --e{715}*/
2132    assert(result  != NULL);
2133    assert(argvals != NULL);
2134 
2135    *result = erf(argvals[0]);
2136 
2137    return SCIP_OKAY;
2138 }
2139 
2140 /* @todo implement SCIPintervalErf */
2141 #define exprevalIntErf exprevalIntDefault
2142 
2143 /* @todo implement SCIPintervalErf */
2144 #define exprcurvErf exprcurvDefault
2145 
2146 static
SCIP_DECL_EXPREVAL(exprevalErfi)2147 SCIP_DECL_EXPREVAL( exprevalErfi )
2148 {   /*lint --e{715}*/
2149    assert(result  != NULL);
2150    assert(argvals != NULL);
2151 
2152    /* @TODO implement erfi evaluation */
2153    SCIPerrorMessage("erfi not implemented");
2154 
2155    return SCIP_ERROR;
2156 }
2157 
2158 /* @todo implement SCIPintervalErfi */
2159 #define exprevalIntErfi NULL
2160 
2161 #define exprcurvErfi exprcurvDefault
2162 #endif
2163 
2164 /** point evaluation for EXPR_MIN */
2165 static
SCIP_DECL_EXPREVAL(exprevalMin)2166 SCIP_DECL_EXPREVAL( exprevalMin )
2167 {   /*lint --e{715}*/
2168    assert(result  != NULL);
2169    assert(argvals != NULL);
2170 
2171    *result = MIN(argvals[0], argvals[1]);
2172 
2173    return SCIP_OKAY;
2174 }
2175 
2176 /** interval evaluation for EXPR_MIN */
2177 static
SCIP_DECL_EXPRINTEVAL(exprevalIntMin)2178 SCIP_DECL_EXPRINTEVAL( exprevalIntMin )
2179 {   /*lint --e{715}*/
2180    assert(result  != NULL);
2181    assert(argvals != NULL);
2182 
2183    SCIPintervalMin(infinity, result, argvals[0], argvals[1]);
2184 
2185    return SCIP_OKAY;
2186 }
2187 
2188 /** curvature for EXPR_MIN */
2189 static
SCIP_DECL_EXPRCURV(exprcurvMin)2190 SCIP_DECL_EXPRCURV( exprcurvMin )
2191 {   /*lint --e{715}*/
2192    assert(result  != NULL);
2193    assert(argcurv != NULL);
2194 
2195    /* the minimum of two concave functions is concave
2196     * otherwise, we don't know
2197     */
2198 
2199    if( (argcurv[0] & SCIP_EXPRCURV_CONCAVE) && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
2200       *result = SCIP_EXPRCURV_CONCAVE;
2201    else
2202       *result = SCIP_EXPRCURV_UNKNOWN;
2203 
2204    return SCIP_OKAY;
2205 }
2206 
2207 /** point evaluation for EXPR_MAX */
2208 static
SCIP_DECL_EXPREVAL(exprevalMax)2209 SCIP_DECL_EXPREVAL( exprevalMax )
2210 {   /*lint --e{715}*/
2211    assert(result  != NULL);
2212    assert(argvals != NULL);
2213 
2214    *result = MAX(argvals[0], argvals[1]);
2215 
2216    return SCIP_OKAY;
2217 }
2218 
2219 /** interval evaluation for EXPR_MAX */
2220 static
SCIP_DECL_EXPRINTEVAL(exprevalIntMax)2221 SCIP_DECL_EXPRINTEVAL( exprevalIntMax )
2222 {   /*lint --e{715}*/
2223    assert(result  != NULL);
2224    assert(argvals != NULL);
2225 
2226    SCIPintervalMax(infinity, result, argvals[0], argvals[1]);
2227 
2228    return SCIP_OKAY;
2229 }
2230 
2231 /** curvature for EXPR_MAX */
2232 static
SCIP_DECL_EXPRCURV(exprcurvMax)2233 SCIP_DECL_EXPRCURV( exprcurvMax )
2234 {   /*lint --e{715}*/
2235    assert(result  != NULL);
2236    assert(argcurv != NULL);
2237 
2238    /* the maximum of two convex functions is convex
2239     * otherwise, we don't know
2240     */
2241    if( (argcurv[0] & SCIP_EXPRCURV_CONVEX) && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
2242       *result = SCIP_EXPRCURV_CONVEX;
2243    else
2244       *result = SCIP_EXPRCURV_UNKNOWN;
2245 
2246    return SCIP_OKAY;
2247 }
2248 
2249 /** point evaluation for EXPR_ABS */
2250 static
SCIP_DECL_EXPREVAL(exprevalAbs)2251 SCIP_DECL_EXPREVAL( exprevalAbs )
2252 {   /*lint --e{715}*/
2253    assert(result  != NULL);
2254    assert(argvals != NULL);
2255 
2256    *result = ABS(argvals[0]);
2257 
2258    return SCIP_OKAY;
2259 }
2260 
2261 /** interval evaluation for EXPR_ABS */
2262 static
SCIP_DECL_EXPRINTEVAL(exprevalIntAbs)2263 SCIP_DECL_EXPRINTEVAL( exprevalIntAbs )
2264 {   /*lint --e{715}*/
2265    assert(result  != NULL);
2266    assert(argvals != NULL);
2267 
2268    SCIPintervalAbs(infinity, result, argvals[0]);
2269 
2270    return SCIP_OKAY;
2271 }
2272 
2273 /** curvature for EXPR_ABS */
2274 static
SCIP_DECL_EXPRCURV(exprcurvAbs)2275 SCIP_DECL_EXPRCURV( exprcurvAbs )
2276 {   /*lint --e{715}*/
2277    assert(result    != NULL);
2278    assert(argcurv   != NULL);
2279    assert(argbounds != NULL);
2280 
2281    /* if child is only negative, then abs(child) = -child
2282     * if child is only positive, then abs(child) = child
2283     * if child is both positive and negative, but also linear, then abs(child) is convex
2284     * otherwise, we don't know
2285     */
2286    if( argbounds[0].sup <= 0.0 )
2287       *result = SCIPexprcurvMultiply(-1.0, argcurv[0]);
2288    else if( argbounds[0].inf >= 0.0 )
2289       *result = argcurv[0];
2290    else if( argcurv[0] == SCIP_EXPRCURV_LINEAR )
2291       *result = SCIP_EXPRCURV_CONVEX;
2292    else
2293       *result = SCIP_EXPRCURV_UNKNOWN;
2294 
2295    return SCIP_OKAY;
2296 }
2297 
2298 /** point evaluation for EXPR_SIGN */
2299 static
SCIP_DECL_EXPREVAL(exprevalSign)2300 SCIP_DECL_EXPREVAL( exprevalSign )
2301 {   /*lint --e{715}*/
2302    assert(result  != NULL);
2303    assert(argvals != NULL);
2304 
2305    *result = SIGN(argvals[0]);
2306 
2307    return SCIP_OKAY;
2308 }
2309 
2310 /** interval evaluation for EXPR_SIGN */
2311 static
SCIP_DECL_EXPRINTEVAL(exprevalIntSign)2312 SCIP_DECL_EXPRINTEVAL( exprevalIntSign )
2313 {   /*lint --e{715}*/
2314    assert(result  != NULL);
2315    assert(argvals != NULL);
2316 
2317    SCIPintervalSign(infinity, result, argvals[0]);
2318 
2319    return SCIP_OKAY;
2320 }
2321 
2322 /** curvature for EXPR_SIGN */
2323 static
SCIP_DECL_EXPRCURV(exprcurvSign)2324 SCIP_DECL_EXPRCURV( exprcurvSign )
2325 {   /*lint --e{715}*/
2326    assert(result    != NULL);
2327    assert(argbounds != NULL);
2328 
2329    /* if sign of child is clear, then sign is linear otherwise, we don't know */
2330    if( argbounds[0].sup <= 0.0 || argbounds[0].inf >= 0.0 )
2331       *result = SCIP_EXPRCURV_LINEAR;
2332    else
2333       *result = SCIP_EXPRCURV_UNKNOWN;
2334 
2335    return SCIP_OKAY;
2336 }
2337 
2338 /** point evaluation for EXPR_SUM */
2339 static
SCIP_DECL_EXPREVAL(exprevalSum)2340 SCIP_DECL_EXPREVAL( exprevalSum )
2341 {   /*lint --e{715}*/
2342    int i;
2343 
2344    assert(result  != NULL);
2345    assert(argvals != NULL);
2346 
2347    *result = 0.0;
2348    for( i = 0; i < nargs; ++i )
2349       *result += argvals[i];
2350 
2351    return SCIP_OKAY;
2352 }
2353 
2354 /** interval evaluation for EXPR_SUM */
2355 static
SCIP_DECL_EXPRINTEVAL(exprevalIntSum)2356 SCIP_DECL_EXPRINTEVAL( exprevalIntSum )
2357 {   /*lint --e{715}*/
2358    int i;
2359 
2360    assert(result  != NULL);
2361    assert(argvals != NULL);
2362 
2363    SCIPintervalSet(result, 0.0);
2364 
2365    for( i = 0; i < nargs; ++i )
2366       SCIPintervalAdd(infinity, result, *result, argvals[i]);
2367 
2368    return SCIP_OKAY;
2369 }
2370 
2371 /** curvature for EXPR_SUM */
2372 static
SCIP_DECL_EXPRCURV(exprcurvSum)2373 SCIP_DECL_EXPRCURV( exprcurvSum )
2374 {   /*lint --e{715}*/
2375    int i;
2376 
2377    assert(result  != NULL);
2378    assert(argcurv != NULL);
2379 
2380    *result = SCIP_EXPRCURV_LINEAR;
2381 
2382    for( i = 0; i < nargs; ++i )
2383       *result = SCIPexprcurvAdd(*result, argcurv[i]);
2384 
2385    return SCIP_OKAY;
2386 }
2387 
2388 /** point evaluation for EXPR_PRODUCT */
2389 static
SCIP_DECL_EXPREVAL(exprevalProduct)2390 SCIP_DECL_EXPREVAL( exprevalProduct )
2391 {   /*lint --e{715}*/
2392    int i;
2393 
2394    assert(result  != NULL);
2395    assert(argvals != NULL);
2396 
2397    *result = 1.0;
2398    for( i = 0; i < nargs; ++i )
2399       *result *= argvals[i];
2400 
2401    return SCIP_OKAY;
2402 }
2403 
2404 /** interval evaluation for EXPR_PRODUCT */
2405 static
SCIP_DECL_EXPRINTEVAL(exprevalIntProduct)2406 SCIP_DECL_EXPRINTEVAL( exprevalIntProduct )
2407 {   /*lint --e{715}*/
2408    int i;
2409 
2410    assert(result  != NULL);
2411    assert(argvals != NULL);
2412 
2413    SCIPintervalSet(result, 1.0);
2414 
2415    for( i = 0; i < nargs; ++i )
2416       SCIPintervalMul(infinity, result, *result, argvals[i]);
2417 
2418    return SCIP_OKAY;
2419 }
2420 
2421 /** curvature for EXPR_PRODUCT */
2422 static
SCIP_DECL_EXPRCURV(exprcurvProduct)2423 SCIP_DECL_EXPRCURV( exprcurvProduct )
2424 {   /*lint --e{715}*/
2425    SCIP_Bool hadnonconst;
2426    SCIP_Real constants;
2427    int i;
2428 
2429    assert(result    != NULL);
2430    assert(argcurv   != NULL);
2431    assert(argbounds != NULL);
2432 
2433    /* if all factors are constant, then product is linear (even constant)
2434     * if only one factor is not constant, then product is curvature of this factor, multiplied by sign of product of remaining factors
2435     */
2436    *result = SCIP_EXPRCURV_LINEAR;
2437    hadnonconst = FALSE;
2438    constants = 1.0;
2439 
2440    for( i = 0; i < nargs; ++i )
2441    {
2442       if( argbounds[i].inf == argbounds[i].sup )  /*lint !e777*/
2443       {
2444          constants *= argbounds[i].inf;
2445       }
2446       else if( !hadnonconst )
2447       {
2448          /* first non-constant child */
2449          *result = argcurv[i];
2450          hadnonconst = TRUE;
2451       }
2452       else
2453       {
2454          /* more than one non-constant child, thus don't know curvature */
2455          *result = SCIP_EXPRCURV_UNKNOWN;
2456          break;
2457       }
2458    }
2459 
2460    *result = SCIPexprcurvMultiply(constants, *result);
2461 
2462    return SCIP_OKAY;
2463 }
2464 
2465 /** point evaluation for EXPR_LINEAR */
2466 static
SCIP_DECL_EXPREVAL(exprevalLinear)2467 SCIP_DECL_EXPREVAL( exprevalLinear )
2468 {   /*lint --e{715}*/
2469    SCIP_Real* coef;
2470    int i;
2471 
2472    assert(result  != NULL);
2473    assert(argvals != NULL || nargs == 0);
2474    assert(opdata.data != NULL);
2475 
2476    coef = &((SCIP_Real*)opdata.data)[nargs];
2477 
2478    *result = *coef;
2479    for( i = nargs-1, --coef; i >= 0; --i, --coef )
2480       *result += *coef * argvals[i];  /*lint !e613*/
2481 
2482    assert(++coef == (SCIP_Real*)opdata.data);
2483 
2484    return SCIP_OKAY;
2485 }
2486 
2487 /** interval evaluation for EXPR_LINEAR */
2488 static
SCIP_DECL_EXPRINTEVAL(exprevalIntLinear)2489 SCIP_DECL_EXPRINTEVAL( exprevalIntLinear )
2490 {   /*lint --e{715}*/
2491    assert(result  != NULL);
2492    assert(argvals != NULL || nargs == 0);
2493    assert(opdata.data != NULL);
2494 
2495    SCIPintervalScalprodScalars(infinity, result, nargs, argvals, (SCIP_Real*)opdata.data);
2496    SCIPintervalAddScalar(infinity, result, *result, ((SCIP_Real*)opdata.data)[nargs]);
2497 
2498    return SCIP_OKAY;
2499 }
2500 
2501 /** curvature for EXPR_LINEAR */
2502 static
SCIP_DECL_EXPRCURV(exprcurvLinear)2503 SCIP_DECL_EXPRCURV( exprcurvLinear )
2504 {   /*lint --e{715}*/
2505    SCIP_Real* data;
2506    int i;
2507 
2508    assert(result  != NULL);
2509    assert(argcurv != NULL);
2510 
2511    data = (SCIP_Real*)opdata.data;
2512    assert(data != NULL);
2513 
2514    *result = SCIP_EXPRCURV_LINEAR;
2515 
2516    for( i = 0; i < nargs; ++i )
2517       *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(data[i], argcurv[i]));
2518 
2519    return SCIP_OKAY;
2520 }
2521 
2522 /** expression data copy for EXPR_LINEAR */
2523 static
SCIP_DECL_EXPRCOPYDATA(exprCopyDataLinear)2524 SCIP_DECL_EXPRCOPYDATA( exprCopyDataLinear )
2525 {  /*lint --e{715}*/
2526    SCIP_Real* targetdata;
2527 
2528    assert(blkmem != NULL);
2529    assert(nchildren >= 0);
2530    assert(opdatatarget != NULL);
2531 
2532    /* for a linear expression, we need to copy the array that holds the coefficients and constant term */
2533    assert(opdatasource.data != NULL);
2534    SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &targetdata, (SCIP_Real*)opdatasource.data, nchildren + 1) );  /*lint !e866*/
2535    opdatatarget->data = targetdata;
2536 
2537    return SCIP_OKAY;
2538 }
2539 
2540 /** expression data free for EXPR_LINEAR */
2541 static
SCIP_DECL_EXPRFREEDATA(exprFreeDataLinear)2542 SCIP_DECL_EXPRFREEDATA( exprFreeDataLinear )
2543 {  /*lint --e{715}*/
2544    SCIP_Real* freedata;
2545 
2546    assert(blkmem != NULL);
2547    assert(nchildren >= 0);
2548 
2549    freedata = (SCIP_Real*)opdata.data;
2550    assert(freedata != NULL);
2551 
2552    BMSfreeBlockMemoryArray(blkmem, &freedata, nchildren + 1);  /*lint !e866*/
2553 }
2554 
2555 /** point evaluation for EXPR_QUADRATIC */
2556 static
SCIP_DECL_EXPREVAL(exprevalQuadratic)2557 SCIP_DECL_EXPREVAL( exprevalQuadratic )
2558 {   /*lint --e{715}*/
2559    SCIP_EXPRDATA_QUADRATIC* quaddata;
2560    SCIP_Real* lincoefs;
2561    SCIP_QUADELEM* quadelems;
2562    int nquadelems;
2563    int i;
2564 
2565    assert(result  != NULL);
2566    assert(argvals != NULL || nargs == 0);
2567 
2568    quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2569    assert(quaddata != NULL);
2570 
2571    lincoefs   = quaddata->lincoefs;
2572    nquadelems = quaddata->nquadelems;
2573    quadelems  = quaddata->quadelems;
2574 
2575    assert(quadelems != NULL || nquadelems == 0);
2576    assert(argvals != NULL || nquadelems == 0);
2577 
2578    *result = quaddata->constant;
2579 
2580    if( lincoefs != NULL )
2581    {
2582       for( i = nargs-1; i >= 0; --i )
2583          *result += lincoefs[i] * argvals[i];  /*lint !e613*/
2584    }
2585 
2586    for( i = 0; i < nquadelems; ++i, ++quadelems )  /*lint !e613*/
2587       *result += quadelems->coef * argvals[quadelems->idx1] * argvals[quadelems->idx2];  /*lint !e613*/
2588 
2589    return SCIP_OKAY;
2590 }
2591 
2592 /** interval evaluation for EXPR_QUADRATIC */
2593 static
SCIP_DECL_EXPRINTEVAL(exprevalIntQuadratic)2594 SCIP_DECL_EXPRINTEVAL( exprevalIntQuadratic )
2595 {   /*lint --e{715}*/
2596    SCIP_EXPRDATA_QUADRATIC* quaddata;
2597    SCIP_Real* lincoefs;
2598    SCIP_QUADELEM* quadelems;
2599    int nquadelems;
2600    int i;
2601    int argidx;
2602    SCIP_Real sqrcoef;
2603    SCIP_INTERVAL lincoef;
2604    SCIP_INTERVAL tmp;
2605 
2606    assert(result  != NULL);
2607    assert(argvals != NULL || nargs == 0);
2608 
2609    quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2610    assert(quaddata != NULL);
2611 
2612    lincoefs   = quaddata->lincoefs;
2613    nquadelems = quaddata->nquadelems;
2614    quadelems  = quaddata->quadelems;
2615 
2616    assert(quadelems != NULL || nquadelems == 0);
2617    assert(argvals   != NULL || nargs == 0);
2618 
2619    /* something fast for case of only one child */
2620    if( nargs == 1 )
2621    {
2622       SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[0] : 0.0);
2623 
2624       sqrcoef = 0.0;
2625       for( i = 0; i < nquadelems; ++i )
2626       {
2627          assert(quadelems[i].idx1 == 0);  /*lint !e613*/
2628          assert(quadelems[i].idx2 == 0);  /*lint !e613*/
2629          sqrcoef += quadelems[i].coef;    /*lint !e613*/
2630       }
2631 
2632       SCIPintervalQuad(infinity, result, sqrcoef, lincoef, argvals[0]);  /*lint !e613*/
2633       SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2634 
2635       return SCIP_OKAY;
2636    }
2637 
2638    if( nargs == 2 && nquadelems > 0 )
2639    {
2640       /* if it's a bivariate quadratic expression with bilinear term, do something special */
2641       SCIP_Real ax;  /* square coefficient of first  child */
2642       SCIP_Real ay;  /* square coefficient of second child */
2643       SCIP_Real axy; /* bilinear coefficient */
2644 
2645       ax = 0.0;
2646       ay = 0.0;
2647       axy = 0.0;
2648       for( i = 0; i < nquadelems; ++i )
2649          if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )       /*lint !e613*/
2650             ax += quadelems[i].coef;                                  /*lint !e613*/
2651          else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )  /*lint !e613*/
2652             ay += quadelems[i].coef;                                  /*lint !e613*/
2653          else
2654             axy += quadelems[i].coef;                                 /*lint !e613*/
2655 
2656       SCIPintervalQuadBivar(infinity, result, ax, ay, axy,
2657          lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2658          argvals[0], argvals[1]);                                     /*lint !e613*/
2659       SCIPdebugMessage("%g x^2 + %g y^2 + %g x y + %g x + %g y = [%g,%g] for x = [%g,%g], y = [%g,%g]\n",
2660          ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2661          result->inf, result->sup, argvals[0].inf, argvals[0].sup, argvals[1].inf, argvals[1].sup);  /*lint !e613*/
2662 
2663       SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2664 
2665       return SCIP_OKAY;
2666    }
2667 
2668    /* make sure coefficients are sorted */
2669    quadraticdataSort(quaddata);
2670 
2671    SCIPintervalSet(result, quaddata->constant);
2672 
2673    /* for each argument, we collect it's linear index from lincoefs, it's square coefficients and all factors from bilinear terms
2674     * then we compute the interval sqrcoef*x^2 + lincoef*x and add it to result
2675     * @todo split quadratic expression into bivariate quadratic terms and apply the above method
2676     */
2677    i = 0;
2678    for( argidx = 0; argidx < nargs; ++argidx )
2679    {
2680       if( i == nquadelems || quadelems[i].idx1 > argidx )  /*lint !e613*/
2681       {
2682          /* there are no quadratic terms with argidx in its first argument, that should be easy to handle */
2683          if( lincoefs != NULL )
2684          {
2685             SCIPintervalMulScalar(infinity, &tmp, argvals[argidx], lincoefs[argidx]);  /*lint !e613*/
2686             SCIPintervalAdd(infinity, result, *result, tmp);
2687          }
2688          continue;
2689       }
2690 
2691       sqrcoef = 0.0;
2692       SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[argidx] : 0.0);
2693 
2694       assert(i < nquadelems && quadelems[i].idx1 == argidx);  /*lint !e613*/
2695       do
2696       {
2697          if( quadelems[i].idx2 == argidx )  /*lint !e613*/
2698          {
2699             sqrcoef += quadelems[i].coef;   /*lint !e613*/
2700          }
2701          else
2702          {
2703             SCIPintervalMulScalar(infinity, &tmp, argvals[quadelems[i].idx2], quadelems[i].coef);  /*lint !e613*/
2704             SCIPintervalAdd(infinity, &lincoef, lincoef, tmp);
2705          }
2706          ++i;
2707       }
2708       while( i < nquadelems && quadelems[i].idx1 == argidx );  /*lint !e613*/
2709       assert(i == nquadelems || quadelems[i].idx1 > argidx);   /*lint !e613*/
2710 
2711       SCIPintervalQuad(infinity, &tmp, sqrcoef, lincoef, argvals[argidx]);  /*lint !e613*/
2712       SCIPintervalAdd(infinity, result, *result, tmp);
2713    }
2714    assert(i == nquadelems);
2715 
2716    return SCIP_OKAY;
2717 }
2718 
2719 /** curvature for EXPR_QUADRATIC */
2720 static
SCIP_DECL_EXPRCURV(exprcurvQuadratic)2721 SCIP_DECL_EXPRCURV( exprcurvQuadratic )
2722 {   /*lint --e{715}*/
2723    SCIP_EXPRDATA_QUADRATIC* data;
2724    SCIP_QUADELEM* quadelems;
2725    int nquadelems;
2726    SCIP_Real* lincoefs;
2727    int i;
2728 
2729    assert(result    != NULL);
2730    assert(argcurv   != NULL);
2731    assert(argbounds != NULL);
2732 
2733    data = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2734    assert(data != NULL);
2735 
2736    lincoefs   = data->lincoefs;
2737    quadelems  = data->quadelems;
2738    nquadelems = data->nquadelems;
2739 
2740    *result = SCIP_EXPRCURV_LINEAR;
2741 
2742    if( lincoefs != NULL )
2743       for( i = 0; i < nargs; ++i )
2744          *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(lincoefs[i], argcurv[i]));
2745 
2746    /* @todo could try cholesky factorization if all children linear...
2747     * @todo should then cache the result
2748     */
2749    for( i = 0; i < nquadelems && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
2750    {
2751       if( quadelems[i].coef == 0.0 )
2752          continue;
2753 
2754       if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup &&  /*lint !e777*/
2755          +argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup
2756          )  /*lint !e777*/
2757       {
2758          /* both factors are constants -> curvature does not change */
2759          continue;
2760       }
2761 
2762       if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup )  /*lint !e777*/
2763       {
2764          /* first factor is constant, second is not -> add curvature of second */
2765          *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx1].inf, argcurv[quadelems[i].idx2]));
2766       }
2767       else if( argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup )  /*lint !e777*/
2768       {
2769          /* first factor is not constant, second is -> add curvature of first */
2770          *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx2].inf, argcurv[quadelems[i].idx1]));
2771       }
2772       else if( quadelems[i].idx1 == quadelems[i].idx2 )
2773       {
2774          /* both factors not constant, but the same (square term) */
2775          *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef, SCIPexprcurvPower(argbounds[quadelems[i].idx1], argcurv[quadelems[i].idx1], 2.0)));
2776       }
2777       else
2778       {
2779          /* two different non-constant factors -> can't tell about curvature */
2780          *result = SCIP_EXPRCURV_UNKNOWN;
2781       }
2782    }
2783 
2784    return SCIP_OKAY;
2785 }
2786 
2787 /** expression data copy for EXPR_QUADRATIC */
2788 static
SCIP_DECL_EXPRCOPYDATA(exprCopyDataQuadratic)2789 SCIP_DECL_EXPRCOPYDATA( exprCopyDataQuadratic )
2790 {  /*lint --e{715}*/
2791    SCIP_EXPRDATA_QUADRATIC* sourcedata;
2792 
2793    assert(blkmem != NULL);
2794    assert(opdatatarget != NULL);
2795 
2796    sourcedata = (SCIP_EXPRDATA_QUADRATIC*)opdatasource.data;
2797    assert(sourcedata != NULL);
2798 
2799    SCIP_CALL( quadraticdataCreate(blkmem, (SCIP_EXPRDATA_QUADRATIC**)&opdatatarget->data,
2800          sourcedata->constant, nchildren, sourcedata->lincoefs, sourcedata->nquadelems, sourcedata->quadelems) );
2801 
2802    return SCIP_OKAY;
2803 }
2804 
2805 /** expression data free for EXPR_QUADRATIC */
2806 static
SCIP_DECL_EXPRFREEDATA(exprFreeDataQuadratic)2807 SCIP_DECL_EXPRFREEDATA( exprFreeDataQuadratic )
2808 {  /*lint --e{715}*/
2809    SCIP_EXPRDATA_QUADRATIC* quadraticdata;
2810 
2811    assert(blkmem != NULL);
2812    assert(nchildren >= 0);
2813 
2814    quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2815    assert(quadraticdata != NULL);
2816 
2817    if( quadraticdata->lincoefs != NULL )
2818    {
2819       BMSfreeBlockMemoryArray(blkmem, &quadraticdata->lincoefs, nchildren);
2820    }
2821 
2822    if( quadraticdata->nquadelems > 0 )
2823    {
2824       assert(quadraticdata->quadelems != NULL);
2825       BMSfreeBlockMemoryArray(blkmem, &quadraticdata->quadelems, quadraticdata->nquadelems);
2826    }
2827 
2828    BMSfreeBlockMemory(blkmem, &quadraticdata);
2829 }
2830 
2831 /** point evaluation for EXPR_POLYNOMIAL */
2832 static
SCIP_DECL_EXPREVAL(exprevalPolynomial)2833 SCIP_DECL_EXPREVAL( exprevalPolynomial )
2834 {   /*lint --e{715}*/
2835    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2836    SCIP_EXPRDATA_MONOMIAL*   monomialdata;
2837    SCIP_Real childval;
2838    SCIP_Real exponent;
2839    SCIP_Real monomialval;
2840    int i;
2841    int j;
2842 
2843    assert(result != NULL);
2844    assert(argvals != NULL || nargs == 0);
2845    assert(opdata.data != NULL);
2846 
2847    polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2848    assert(polynomialdata != NULL);
2849 
2850    *result = polynomialdata->constant;
2851 
2852    for( i = 0; i < polynomialdata->nmonomials; ++i )
2853    {
2854       monomialdata = polynomialdata->monomials[i];
2855       assert(monomialdata != NULL);
2856 
2857       monomialval = monomialdata->coef;
2858       for( j = 0; j < monomialdata->nfactors; ++j )
2859       {
2860          assert(monomialdata->childidxs[j] >= 0);
2861          assert(monomialdata->childidxs[j] < nargs);
2862 
2863          childval = argvals[monomialdata->childidxs[j]];  /*lint !e613*/
2864          if( childval == 1.0 )  /* 1^anything == 1 */
2865             continue;
2866 
2867          exponent = monomialdata->exponents[j];
2868 
2869          if( childval == 0.0 )
2870          {
2871             if( exponent > 0.0 )
2872             {
2873                /* 0^positive == 0 */
2874                monomialval = 0.0;
2875                break;
2876             }
2877             else if( exponent < 0.0 )
2878             {
2879                /* 0^negative = nan (or should it be +inf?, doesn't really matter) */
2880 #ifdef NAN
2881                *result = NAN;
2882 #else
2883                /* cppcheck-suppress wrongmathcall */
2884                *result = pow(0.0, -1.0);
2885 #endif
2886                return SCIP_OKAY;
2887             }
2888             /* 0^0 == 1 */
2889             continue;
2890          }
2891 
2892          /* cover some special exponents separately to avoid calling expensive pow function */
2893          if( exponent == 0.0 )
2894             continue;
2895          if( exponent == 1.0 )
2896          {
2897             monomialval *= childval;
2898             continue;
2899          }
2900          if( exponent == 2.0 )
2901          {
2902             monomialval *= childval * childval;
2903             continue;
2904          }
2905          if( exponent == 0.5 )
2906          {
2907             monomialval *= sqrt(childval);
2908             continue;
2909          }
2910          if( exponent == -1.0 )
2911          {
2912             monomialval /= childval;
2913             continue;
2914          }
2915          if( exponent == -2.0 )
2916          {
2917             monomialval /= childval * childval;
2918             continue;
2919          }
2920          monomialval *= pow(childval, exponent);
2921       }
2922 
2923       *result += monomialval;
2924    }
2925 
2926    return SCIP_OKAY;
2927 }
2928 
2929 /** interval evaluation for EXPR_POLYNOMIAL */
2930 static
SCIP_DECL_EXPRINTEVAL(exprevalIntPolynomial)2931 SCIP_DECL_EXPRINTEVAL( exprevalIntPolynomial )
2932 {   /*lint --e{715}*/
2933    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2934    SCIP_EXPRDATA_MONOMIAL*   monomialdata;
2935    SCIP_INTERVAL childval;
2936    SCIP_INTERVAL monomialval;
2937    SCIP_Real exponent;
2938    int i;
2939    int j;
2940 
2941    assert(result != NULL);
2942    assert(argvals != NULL || nargs == 0);
2943    assert(opdata.data != NULL);
2944 
2945    polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2946    assert(polynomialdata != NULL);
2947 
2948    SCIPintervalSet(result, polynomialdata->constant);
2949 
2950    for( i = 0; i < polynomialdata->nmonomials; ++i )
2951    {
2952       monomialdata = polynomialdata->monomials[i];
2953       assert(monomialdata != NULL);
2954 
2955       SCIPintervalSet(&monomialval, monomialdata->coef);
2956       for( j = 0; j < monomialdata->nfactors && !SCIPintervalIsEntire(infinity, monomialval); ++j )
2957       {
2958          assert(monomialdata->childidxs[j] >= 0);
2959          assert(monomialdata->childidxs[j] < nargs);
2960 
2961          childval = argvals[monomialdata->childidxs[j]];  /*lint !e613*/
2962 
2963          exponent = monomialdata->exponents[j];
2964 
2965          /* cover some special exponents separately to avoid calling expensive pow function */
2966          if( exponent == 0.0 )
2967             continue;
2968 
2969          if( exponent == 1.0 )
2970          {
2971             SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2972             continue;
2973          }
2974 
2975          if( exponent == 2.0 )
2976          {
2977             SCIPintervalSquare(infinity, &childval, childval);
2978             SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2979             continue;
2980          }
2981 
2982          if( exponent == 0.5 )
2983          {
2984             SCIPintervalSquareRoot(infinity, &childval, childval);
2985             if( SCIPintervalIsEmpty(infinity, childval) )
2986             {
2987                SCIPintervalSetEmpty(result);
2988                return SCIP_OKAY;
2989             }
2990             SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2991             continue;
2992          }
2993          else if( exponent == -1.0 )
2994          {
2995             SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2996          }
2997          else if( exponent == -2.0 )
2998          {
2999             SCIPintervalSquare(infinity, &childval, childval);
3000             SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
3001          }
3002          else
3003          {
3004             SCIPintervalPowerScalar(infinity, &childval, childval, exponent);
3005             if( SCIPintervalIsEmpty(infinity, childval) )
3006             {
3007                SCIPintervalSetEmpty(result);
3008                return SCIP_OKAY;
3009             }
3010             SCIPintervalMul(infinity, &monomialval, monomialval, childval);
3011          }
3012 
3013          /* the cases in which monomialval gets empty should have been catched */
3014          assert(!SCIPintervalIsEmpty(infinity, monomialval));
3015       }
3016 
3017       SCIPintervalAdd(infinity, result, *result, monomialval);
3018    }
3019 
3020    return SCIP_OKAY;
3021 }
3022 
3023 /** curvature for EXPR_POLYNOMIAL */
3024 static
SCIP_DECL_EXPRCURV(exprcurvPolynomial)3025 SCIP_DECL_EXPRCURV( exprcurvPolynomial )
3026 {   /*lint --e{715}*/
3027    SCIP_EXPRDATA_POLYNOMIAL* data;
3028    SCIP_EXPRDATA_MONOMIAL** monomials;
3029    SCIP_EXPRDATA_MONOMIAL* monomial;
3030    int nmonomials;
3031    int i;
3032 
3033    assert(result    != NULL);
3034    assert(argcurv   != NULL);
3035    assert(argbounds != NULL);
3036 
3037    data = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3038    assert(data != NULL);
3039 
3040    monomials  = data->monomials;
3041    nmonomials = data->nmonomials;
3042 
3043    *result = SCIP_EXPRCURV_LINEAR;
3044 
3045    for( i = 0; i < nmonomials && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
3046    {
3047       /* we assume that some simplifier was running, so that monomials do not have constants in their factors and such that all factors are different
3048        * (result would still be correct)
3049        */
3050       monomial = monomials[i];
3051       *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(monomial->coef, SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, monomial->childidxs, argcurv, argbounds)));
3052    }
3053 
3054    return SCIP_OKAY;
3055 }
3056 
3057 /** expression data copy for EXPR_POLYNOMIAL */
3058 static
SCIP_DECL_EXPRCOPYDATA(exprCopyDataPolynomial)3059 SCIP_DECL_EXPRCOPYDATA( exprCopyDataPolynomial )
3060 {  /*lint --e{715}*/
3061    SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata;
3062    SCIP_EXPRDATA_POLYNOMIAL* targetpolynomialdata;
3063 
3064    assert(blkmem != NULL);
3065    assert(opdatatarget != NULL);
3066 
3067    sourcepolynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdatasource.data;
3068    assert(sourcepolynomialdata != NULL);
3069 
3070    SCIP_CALL( polynomialdataCopy(blkmem, &targetpolynomialdata, sourcepolynomialdata) );
3071 
3072    opdatatarget->data = (void*)targetpolynomialdata;
3073 
3074    return SCIP_OKAY;
3075 }
3076 
3077 /** expression data free for EXPR_POLYNOMIAL */
3078 static
SCIP_DECL_EXPRFREEDATA(exprFreeDataPolynomial)3079 SCIP_DECL_EXPRFREEDATA( exprFreeDataPolynomial )
3080 {  /*lint --e{715}*/
3081    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3082 
3083    assert(blkmem != NULL);
3084 
3085    polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3086    assert(polynomialdata != NULL);
3087 
3088    polynomialdataFree(blkmem, &polynomialdata);
3089 }
3090 
3091 /** point evaluation for user expression */
3092 static
SCIP_DECL_EXPREVAL(exprevalUser)3093 SCIP_DECL_EXPREVAL( exprevalUser )
3094 {  /*lint --e{715}*/
3095    SCIP_EXPRDATA_USER* exprdata;
3096 
3097    exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3098 
3099    SCIP_CALL( exprdata->eval(exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3100 
3101    return SCIP_OKAY;
3102 }
3103 
3104 /** interval evaluation for user expression */
3105 static
SCIP_DECL_EXPRINTEVAL(exprevalIntUser)3106 SCIP_DECL_EXPRINTEVAL( exprevalIntUser )
3107 {  /*lint --e{715}*/
3108    SCIP_EXPRDATA_USER* exprdata;
3109 
3110    exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3111 
3112    if( exprdata->inteval != NULL )
3113    {
3114       SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3115    }
3116    else
3117    {
3118       /* if user does not provide interval evaluation, then return a result that is always correct */
3119       SCIPintervalSetEntire(infinity, result);
3120    }
3121 
3122    return SCIP_OKAY;
3123 }
3124 
3125 /** curvature check for user expression */
3126 static
SCIP_DECL_EXPRCURV(exprcurvUser)3127 SCIP_DECL_EXPRCURV( exprcurvUser )
3128 {
3129    SCIP_EXPRDATA_USER* exprdata;
3130 
3131    exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3132 
3133    if( exprdata->curv != NULL )
3134    {
3135       SCIP_CALL( exprdata->curv(infinity, exprdata->userdata, nargs, argbounds, argcurv, result) );
3136    }
3137    else
3138    {
3139       /* if user does not provide curvature check, then return unknown (which is handled like indefinite) */
3140       *result = SCIP_EXPRCURV_UNKNOWN;
3141    }
3142 
3143    return SCIP_OKAY;
3144 }
3145 
3146 /** data copy for user expression */
3147 static
SCIP_DECL_EXPRCOPYDATA(exprCopyDataUser)3148 SCIP_DECL_EXPRCOPYDATA( exprCopyDataUser )
3149 {
3150    SCIP_EXPRDATA_USER* exprdatasource;
3151    SCIP_EXPRDATA_USER* exprdatatarget;
3152 
3153    assert(blkmem != NULL);
3154    assert(opdatatarget != NULL);
3155 
3156    exprdatasource = (SCIP_EXPRDATA_USER*)opdatasource.data;
3157    assert(exprdatasource != NULL);
3158 
3159    /* duplicate expression data */
3160    SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, &exprdatatarget, exprdatasource) );
3161 
3162    /* duplicate user expression data, if any */
3163    if( exprdatasource->copydata != NULL )
3164    {
3165       SCIP_CALL( exprdatasource->copydata(blkmem, nchildren, exprdatasource->userdata, &exprdatatarget->userdata) );
3166    }
3167    else
3168    {
3169       /* if no copy function for data, then there has to be no data */
3170       assert(exprdatatarget->userdata == NULL);
3171    }
3172 
3173    opdatatarget->data = (void*)exprdatatarget;
3174 
3175    return SCIP_OKAY;
3176 }
3177 
3178 /** data free for user expression */
3179 static
SCIP_DECL_EXPRFREEDATA(exprFreeDataUser)3180 SCIP_DECL_EXPRFREEDATA( exprFreeDataUser )
3181 {
3182    SCIP_EXPRDATA_USER* exprdata;
3183 
3184    assert(blkmem != NULL);
3185 
3186    exprdata = (SCIP_EXPRDATA_USER*)opdata.data;
3187 
3188    /* free user expression data, if any */
3189    if( exprdata->freedata != NULL )
3190    {
3191       exprdata->freedata(blkmem, nchildren, exprdata->userdata);
3192    }
3193    else
3194    {
3195       assert(exprdata->userdata == NULL);
3196    }
3197 
3198    /* free expression data */
3199    BMSfreeBlockMemory(blkmem, &exprdata);
3200 }
3201 
3202 /** element in table of expression operands */
3203 struct exprOpTableElement
3204 {
3205    const char*           name;               /**< name of operand (used for printing) */
3206    int                   nargs;              /**< number of arguments (negative if not fixed) */
3207    SCIP_DECL_EXPREVAL    ((*eval));          /**< evaluation function */
3208    SCIP_DECL_EXPRINTEVAL ((*inteval));       /**< interval evaluation function */
3209    SCIP_DECL_EXPRCURV    ((*curv));          /**< curvature check function */
3210    SCIP_DECL_EXPRCOPYDATA ((*copydata));     /**< expression data copy function, or NULL to only opdata union */
3211    SCIP_DECL_EXPRFREEDATA ((*freedata));     /**< expression data free function, or NULL if nothing to free */
3212 };
3213 
3214 #define EXPROPEMPTY {NULL, -1, NULL, NULL, NULL, NULL, NULL}
3215 
3216 /** table containing for each operand the name, the number of children, and some evaluation functions */
3217 static
3218 struct exprOpTableElement exprOpTable[] =
3219    {
3220       EXPROPEMPTY,
3221       { "variable",          0, exprevalVar,        exprevalIntVar,        exprcurvVar,        NULL, NULL  },
3222       { "constant",          0, exprevalConst,      exprevalIntConst,      exprcurvConst,      NULL, NULL  },
3223       { "parameter",         0, exprevalParam,      exprevalIntParam,      exprcurvParam,      NULL, NULL  },
3224       EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY,
3225       { "plus",              2, exprevalPlus,       exprevalIntPlus,       exprcurvPlus,       NULL, NULL  },
3226       { "minus",             2, exprevalMinus,      exprevalIntMinus,      exprcurvMinus,      NULL, NULL  },
3227       { "mul",               2, exprevalMult,       exprevalIntMult,       exprcurvMult,       NULL, NULL  },
3228       { "div",               2, exprevalDiv,        exprevalIntDiv,        exprcurvDiv,        NULL, NULL  },
3229       { "sqr",               1, exprevalSquare,     exprevalIntSquare,     exprcurvSquare,     NULL, NULL  },
3230       { "sqrt",              1, exprevalSquareRoot, exprevalIntSquareRoot, exprcurvSquareRoot, NULL, NULL  },
3231       { "realpower",         1, exprevalRealPower,  exprevalIntRealPower,  exprcurvRealPower,  NULL, NULL  },
3232       { "intpower",          1, exprevalIntPower,   exprevalIntIntPower,   exprcurvIntPower,   NULL, NULL  },
3233       { "signpower",         1, exprevalSignPower,  exprevalIntSignPower,  exprcurvSignPower,  NULL, NULL  },
3234       { "exp",               1, exprevalExp,        exprevalIntExp,        exprcurvExp,        NULL, NULL  },
3235       { "log",               1, exprevalLog,        exprevalIntLog,        exprcurvLog,        NULL, NULL  },
3236       { "sin",               1, exprevalSin,        exprevalIntSin,        exprcurvSin,        NULL, NULL  },
3237       { "cos",               1, exprevalCos,        exprevalIntCos,        exprcurvCos,        NULL, NULL  },
3238       { "tan",               1, exprevalTan,        exprevalIntTan,        exprcurvTan,        NULL, NULL  },
3239       /* { "erf",               1, exprevalErf,        exprevalIntErf,        exprcurvErf,        NULL, NULL  }, */
3240       /* { "erfi",              1, exprevalErfi,       exprevalIntErfi        exprcurvErfi,       NULL, NULL  }, */
3241       EXPROPEMPTY, EXPROPEMPTY,
3242       { "min",               2, exprevalMin,        exprevalIntMin,        exprcurvMin,        NULL, NULL  },
3243       { "max",               2, exprevalMax,        exprevalIntMax,        exprcurvMax,        NULL, NULL  },
3244       { "abs",               1, exprevalAbs,        exprevalIntAbs,        exprcurvAbs,        NULL, NULL  },
3245       { "sign",              1, exprevalSign,       exprevalIntSign,       exprcurvSign,       NULL, NULL  },
3246       EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY,
3247       EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY,
3248       EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY,
3249       EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY,
3250       EXPROPEMPTY, EXPROPEMPTY, EXPROPEMPTY,
3251       { "sum",              -2, exprevalSum,        exprevalIntSum,        exprcurvSum,        NULL, NULL  },
3252       { "prod",             -2, exprevalProduct,    exprevalIntProduct,    exprcurvProduct,    NULL, NULL  },
3253       { "linear",           -2, exprevalLinear,     exprevalIntLinear,     exprcurvLinear,     exprCopyDataLinear,     exprFreeDataLinear     },
3254       { "quadratic",        -2, exprevalQuadratic,  exprevalIntQuadratic,  exprcurvQuadratic,  exprCopyDataQuadratic,  exprFreeDataQuadratic  },
3255       { "polynomial",       -2, exprevalPolynomial, exprevalIntPolynomial, exprcurvPolynomial, exprCopyDataPolynomial, exprFreeDataPolynomial },
3256       { "user",             -2, exprevalUser,       exprevalIntUser,       exprcurvUser,       exprCopyDataUser,       exprFreeDataUser       }
3257    };
3258 
3259 /**@} */
3260 
3261 /**@name Expression operand methods */
3262 /**@{ */
3263 
3264 /** gives the name of an operand as string */
SCIPexpropGetName(SCIP_EXPROP op)3265 const char* SCIPexpropGetName(
3266    SCIP_EXPROP           op                  /**< expression operand */
3267    )
3268 {
3269    assert(op < SCIP_EXPR_LAST);
3270 
3271    return exprOpTable[op].name;
3272 }
3273 
3274 /** gives the number of children of a simple operand */
SCIPexpropGetNChildren(SCIP_EXPROP op)3275 int SCIPexpropGetNChildren(
3276    SCIP_EXPROP           op                  /**< expression operand */
3277    )
3278 {
3279    assert(op < SCIP_EXPR_LAST);
3280 
3281    return exprOpTable[op].nargs;
3282 }
3283 
3284 /**@} */
3285 
3286 /**@name Expressions private methods */
3287 /**@{ */
3288 
3289 /** creates an expression
3290  *
3291  *  Note, that the expression is allocated but for the children only the pointer is copied.
3292  */
3293 static
exprCreate(BMS_BLKMEM * blkmem,SCIP_EXPR ** expr,SCIP_EXPROP op,int nchildren,SCIP_EXPR ** children,SCIP_EXPROPDATA opdata)3294 SCIP_RETCODE exprCreate(
3295    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
3296    SCIP_EXPR**           expr,               /**< pointer to buffer for expression address */
3297    SCIP_EXPROP           op,                 /**< operand of expression */
3298    int                   nchildren,          /**< number of children */
3299    SCIP_EXPR**           children,           /**< children */
3300    SCIP_EXPROPDATA       opdata              /**< operand data */
3301    )
3302 {
3303    assert(blkmem != NULL);
3304    assert(expr   != NULL);
3305    assert(children != NULL || nchildren == 0);
3306    assert(children == NULL || nchildren >  0);
3307 
3308    SCIP_ALLOC( BMSallocBlockMemory(blkmem, expr) );
3309 
3310    (*expr)->op        = op;
3311    (*expr)->nchildren = nchildren;
3312    (*expr)->children  = children;
3313    (*expr)->data      = opdata;
3314 
3315    return SCIP_OKAY;
3316 }
3317 
3318 /** tries to convert a given (operator,operatordata) pair into a polynomial operator with corresponding data
3319  *
3320  *  Does not do this for constants.
3321  *  If conversion is not possible or operator is already polynomial, *op and *data are
3322  *  left untouched.
3323  */
3324 static
exprConvertToPolynomial(BMS_BLKMEM * blkmem,SCIP_EXPROP * op,SCIP_EXPROPDATA * data,int nchildren)3325 SCIP_RETCODE exprConvertToPolynomial(
3326    BMS_BLKMEM*           blkmem,             /**< block memory */
3327    SCIP_EXPROP*          op,                 /**< pointer to expression operator */
3328    SCIP_EXPROPDATA*      data,               /**< pointer to expression data */
3329    int                   nchildren           /**< number of children of operator */
3330    )
3331 {
3332    assert(blkmem != NULL);
3333    assert(op != NULL);
3334    assert(data != NULL);
3335 
3336    switch( *op )
3337    {
3338    case SCIP_EXPR_VARIDX:
3339    case SCIP_EXPR_PARAM:
3340    case SCIP_EXPR_CONST:
3341       break;
3342 
3343    case SCIP_EXPR_PLUS:
3344    {
3345       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3346       SCIP_EXPRDATA_MONOMIAL* monomials[2];
3347       int childidx;
3348       SCIP_Real exponent;
3349 
3350       assert(nchildren == 2);
3351 
3352       /* create monomial for first child */
3353       childidx = 0;
3354       exponent = 1.0;
3355       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3356 
3357       /* create monomial for second child */
3358       childidx = 1;
3359       exponent = 1.0;
3360       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], 1.0, 1, &childidx, &exponent) );
3361 
3362       /* create polynomial for sum of children */
3363       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3364 
3365       *op = SCIP_EXPR_POLYNOMIAL;
3366       data->data = (void*)polynomialdata;
3367 
3368       break;
3369    }
3370 
3371    case SCIP_EXPR_MINUS:
3372    {
3373       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3374       SCIP_EXPRDATA_MONOMIAL* monomials[2];
3375       int childidx;
3376       SCIP_Real exponent;
3377 
3378       assert(nchildren == 2);
3379 
3380       /* create monomial for first child */
3381       childidx = 0;
3382       exponent = 1.0;
3383       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0],  1.0, 1, &childidx, &exponent) );
3384 
3385       /* create monomial for second child */
3386       childidx = 1;
3387       exponent = 1.0;
3388       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], -1.0, 1, &childidx, &exponent) );
3389 
3390       /* create polynomial for difference of children */
3391       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3392 
3393       *op = SCIP_EXPR_POLYNOMIAL;
3394       data->data = (void*)polynomialdata;
3395 
3396       break;
3397    }
3398 
3399    case SCIP_EXPR_MUL:
3400    {
3401       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3402       SCIP_EXPRDATA_MONOMIAL* monomial;
3403       int childidx[2];
3404       SCIP_Real exponent[2];
3405 
3406       assert(nchildren == 2);
3407 
3408       /* create monomial for product of children */
3409       childidx[0] = 0;
3410       childidx[1] = 1;
3411       exponent[0] = 1.0;
3412       exponent[1] = 1.0;
3413       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3414 
3415       /* create polynomial */
3416       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3417 
3418       *op = SCIP_EXPR_POLYNOMIAL;
3419       data->data = (void*)polynomialdata;
3420 
3421       break;
3422    }
3423 
3424    case SCIP_EXPR_DIV:
3425    {
3426       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3427       SCIP_EXPRDATA_MONOMIAL* monomial;
3428       int childidx[2];
3429       SCIP_Real exponent[2];
3430 
3431       assert(nchildren == 2);
3432 
3433       /* create monomial for division of children */
3434       childidx[0] = 0;
3435       childidx[1] = 1;
3436       exponent[0] =  1.0;
3437       exponent[1] = -1.0;
3438       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3439 
3440       /* create polynomial */
3441       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3442 
3443       *op = SCIP_EXPR_POLYNOMIAL;
3444       data->data = (void*)polynomialdata;
3445 
3446       break;
3447    }
3448 
3449    case SCIP_EXPR_SQUARE:
3450    {
3451       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3452       SCIP_EXPRDATA_MONOMIAL* monomial;
3453       int childidx;
3454       SCIP_Real exponent;
3455 
3456       assert(nchildren == 1);
3457 
3458       /* create monomial for square of child */
3459       childidx = 0;
3460       exponent = 2.0;
3461       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3462 
3463       /* create polynomial */
3464       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3465 
3466       *op = SCIP_EXPR_POLYNOMIAL;
3467       data->data = (void*)polynomialdata;
3468 
3469       break;
3470    }
3471 
3472    case SCIP_EXPR_SQRT:
3473    {
3474       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3475       SCIP_EXPRDATA_MONOMIAL* monomial;
3476       int childidx;
3477       SCIP_Real exponent;
3478 
3479       assert(nchildren == 1);
3480 
3481       /* create monomial for square root of child */
3482       childidx = 0;
3483       exponent = 0.5;
3484       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3485 
3486       /* create polynomial */
3487       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3488 
3489       *op = SCIP_EXPR_POLYNOMIAL;
3490       data->data = (void*)polynomialdata;
3491 
3492       break;
3493    }
3494 
3495    case SCIP_EXPR_REALPOWER:
3496    {
3497       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3498       SCIP_EXPRDATA_MONOMIAL* monomial;
3499       int childidx;
3500 
3501       assert(nchildren == 1);
3502 
3503       /* convert to child0 to the power of exponent */
3504 
3505       /* create monomial for power of first child */
3506       childidx = 0;
3507       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &data->dbl) );
3508 
3509       /* create polynomial */
3510       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3511 
3512       *op = SCIP_EXPR_POLYNOMIAL;
3513       data->data = (void*)polynomialdata;
3514 
3515       break;
3516    }
3517 
3518    case SCIP_EXPR_SIGNPOWER:
3519    {
3520       SCIP_Real exponent;
3521 
3522       assert(nchildren == 1);
3523 
3524       /* check if exponent is an odd integer */
3525       exponent = data->dbl;
3526       if( EPSISINT(exponent, 0.0) && (int)exponent % 2 != 0 )  /*lint !e835*/
3527       {
3528          /* convert to child0 to the power of exponent, since sign is kept by taking power */
3529          SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3530          SCIP_EXPRDATA_MONOMIAL* monomial;
3531          int childidx;
3532 
3533          /* create monomial for power of first child */
3534          childidx = 0;
3535          SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3536 
3537          /* create polynomial */
3538          SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3539 
3540          *op = SCIP_EXPR_POLYNOMIAL;
3541          data->data = (void*)polynomialdata;
3542       }
3543       /* if exponent is not an odd integer constant, then keep it as signpower expression */
3544       break;
3545    }
3546 
3547    case SCIP_EXPR_INTPOWER:
3548    {
3549       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3550       SCIP_EXPRDATA_MONOMIAL* monomial;
3551       int childidx;
3552       SCIP_Real exponent;
3553 
3554       assert(nchildren == 1);
3555 
3556       /* create monomial for power of child */
3557       childidx = 0;
3558       exponent = data->intval;
3559       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3560 
3561       /* create polynomial */
3562       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3563 
3564       *op = SCIP_EXPR_POLYNOMIAL;
3565       data->data = (void*)polynomialdata;
3566 
3567       break;
3568    }
3569 
3570    case SCIP_EXPR_EXP:
3571    case SCIP_EXPR_LOG:
3572    case SCIP_EXPR_SIN:
3573    case SCIP_EXPR_COS:
3574    case SCIP_EXPR_TAN:
3575       /* case SCIP_EXPR_ERF: */
3576       /* case SCIP_EXPR_ERFI: */
3577    case SCIP_EXPR_MIN:
3578    case SCIP_EXPR_MAX:
3579    case SCIP_EXPR_ABS:
3580    case SCIP_EXPR_SIGN:
3581    case SCIP_EXPR_USER:
3582       break;
3583 
3584    case SCIP_EXPR_SUM:
3585    {
3586       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3587       SCIP_EXPRDATA_MONOMIAL* monomial;
3588       int childidx;
3589       int i;
3590       SCIP_Real exponent;
3591 
3592       /* create empty polynomial */
3593       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, 0.0, FALSE) );
3594       SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3595       assert(polynomialdata->monomialssize >= nchildren);
3596 
3597       /* add summands as monomials */
3598       childidx = 0;
3599       exponent = 1.0;
3600       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3601       for( i = 0; i < nchildren; ++i )
3602       {
3603          monomial->childidxs[0] = i;
3604          SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3605       }
3606       SCIPexprFreeMonomial(blkmem, &monomial);
3607 
3608       *op = SCIP_EXPR_POLYNOMIAL;
3609       data->data = (void*)polynomialdata;
3610 
3611       break;
3612    }
3613 
3614    case SCIP_EXPR_PRODUCT:
3615    {
3616       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3617       SCIP_EXPRDATA_MONOMIAL* monomial;
3618       int childidx;
3619       int i;
3620       SCIP_Real exponent;
3621 
3622       /* create monomial */
3623       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 0, NULL, NULL) );
3624       SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, nchildren) );
3625       exponent = 1.0;
3626       for( i = 0; i < nchildren; ++i )
3627       {
3628          childidx = i;
3629          SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
3630       }
3631 
3632       /* create polynomial */
3633       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3634 
3635       *op = SCIP_EXPR_POLYNOMIAL;
3636       data->data = (void*)polynomialdata;
3637 
3638       break;
3639    }
3640 
3641    case SCIP_EXPR_LINEAR:
3642    {
3643       SCIP_Real* lineardata;
3644       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3645       SCIP_EXPRDATA_MONOMIAL* monomial;
3646       int childidx;
3647       int i;
3648       SCIP_Real exponent;
3649 
3650       /* get coefficients of linear term */
3651       lineardata = (SCIP_Real*)data->data;
3652       assert(lineardata != NULL);
3653 
3654       /* create polynomial consisting of constant from linear term */
3655       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, lineardata[nchildren], FALSE) );
3656       /* ensure space for linear coefficients */
3657       SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3658       assert(polynomialdata->monomialssize >= nchildren);
3659 
3660       /* add summands as monomials */
3661       childidx = 0;
3662       exponent = 1.0;
3663       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3664       for( i = 0; i < nchildren; ++i )
3665       {
3666          monomial->coef = lineardata[i];
3667          monomial->childidxs[0] = i;
3668          SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3669       }
3670       SCIPexprFreeMonomial(blkmem, &monomial);
3671 
3672       /* free linear expression data */
3673       exprFreeDataLinear(blkmem, nchildren, *data);
3674 
3675       *op = SCIP_EXPR_POLYNOMIAL;
3676       data->data = (void*)polynomialdata;
3677 
3678       break;
3679    }
3680 
3681    case SCIP_EXPR_QUADRATIC:
3682    {
3683       SCIP_EXPRDATA_QUADRATIC* quaddata;
3684       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3685       SCIP_EXPRDATA_MONOMIAL* squaremonomial;
3686       SCIP_EXPRDATA_MONOMIAL* bilinmonomial;
3687       SCIP_EXPRDATA_MONOMIAL* linmonomial;
3688       int childidx[2];
3689       SCIP_Real exponent[2];
3690       int i;
3691 
3692       /* get data of quadratic expression */
3693       quaddata = (SCIP_EXPRDATA_QUADRATIC*)data->data;
3694       assert(quaddata != NULL);
3695 
3696       /* create empty polynomial */
3697       SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, quaddata->constant, FALSE) );
3698       /* ensure space for linear and quadratic terms */
3699       SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, (quaddata->lincoefs != NULL ? nchildren : 0) + quaddata->nquadelems) );
3700       assert(polynomialdata->monomialssize >= quaddata->nquadelems);
3701 
3702       childidx[0] = 0;
3703       childidx[1] = 0;
3704 
3705       /* create monomial templates */
3706       exponent[0] = 2.0;
3707       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &squaremonomial, 1.0, 1, childidx, exponent) );
3708       exponent[0] = 1.0;
3709       exponent[1] = 1.0;
3710       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &bilinmonomial,  1.0, 2, childidx, exponent) );
3711       SCIP_CALL( SCIPexprCreateMonomial(blkmem, &linmonomial,    1.0, 1, childidx, exponent) );
3712 
3713       /* add linear terms as monomials */
3714       if( quaddata->lincoefs != NULL )
3715          for( i = 0; i < nchildren; ++i )
3716             if( quaddata->lincoefs[i] != 0.0 )
3717             {
3718                linmonomial->childidxs[0] = i;
3719                linmonomial->coef         = quaddata->lincoefs[i];
3720                SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &linmonomial, TRUE) );
3721             }
3722 
3723       /* add quadratic terms as monomials */
3724       for( i = 0; i < quaddata->nquadelems; ++i )
3725       {
3726          if( quaddata->quadelems[i].idx1 == quaddata->quadelems[i].idx2 )
3727          {
3728             squaremonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3729             squaremonomial->coef         = quaddata->quadelems[i].coef;
3730             SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &squaremonomial, TRUE) );
3731          }
3732          else
3733          {
3734             bilinmonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3735             bilinmonomial->childidxs[1] = quaddata->quadelems[i].idx2;
3736             bilinmonomial->coef         = quaddata->quadelems[i].coef;
3737             SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &bilinmonomial, TRUE) );
3738          }
3739       }
3740       SCIPexprFreeMonomial(blkmem, &squaremonomial);
3741       SCIPexprFreeMonomial(blkmem, &bilinmonomial);
3742       SCIPexprFreeMonomial(blkmem, &linmonomial);
3743 
3744       /* free quadratic expression data */
3745       exprFreeDataQuadratic(blkmem, nchildren, *data);
3746 
3747       *op = SCIP_EXPR_POLYNOMIAL;
3748       data->data = (void*)polynomialdata;
3749 
3750       break;
3751    }
3752 
3753    case SCIP_EXPR_POLYNOMIAL:
3754    case SCIP_EXPR_LAST:
3755       break;
3756    }  /*lint !e788*/
3757 
3758    return SCIP_OKAY;
3759 }
3760 
3761 /** converts polynomial expression back into simpler expression, if possible */
3762 static
exprUnconvertPolynomial(BMS_BLKMEM * blkmem,SCIP_EXPROP * op,SCIP_EXPROPDATA * data,int nchildren,void ** children)3763 SCIP_RETCODE exprUnconvertPolynomial(
3764    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
3765    SCIP_EXPROP*          op,                 /**< pointer to expression operator */
3766    SCIP_EXPROPDATA*      data,               /**< pointer to expression data holding polynomial data */
3767    int                   nchildren,          /**< number of children of operator */
3768    void**                children            /**< children array */
3769    )
3770 {
3771    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3772    SCIP_EXPRDATA_MONOMIAL* monomial;
3773    int maxdegree;
3774    int nlinmonomials;
3775    int i;
3776    int j;
3777 
3778    assert(blkmem != NULL);
3779    assert(op != NULL);
3780    assert(*op == SCIP_EXPR_POLYNOMIAL);
3781    assert(data != NULL);
3782    assert(children != NULL || nchildren == 0);
3783 
3784    polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)data->data;
3785    assert(polynomialdata != NULL);
3786 
3787    /* make sure monomials are sorted and merged */
3788    polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
3789 
3790    /* if no monomials, then leave as it is */
3791    if( polynomialdata->nmonomials == 0 )
3792       return SCIP_OKAY;
3793 
3794    /* check maximal degree of polynomial only - not considering children expressions
3795     * check number of linear monomials */
3796    maxdegree = 0;
3797    nlinmonomials = 0;
3798    for( i = 0; i < polynomialdata->nmonomials; ++i )
3799    {
3800       int monomialdegree;
3801 
3802       monomial = polynomialdata->monomials[i];
3803       assert(monomial != NULL);
3804 
3805       monomialdegree = 0;
3806       for(j = 0; j < monomial->nfactors; ++j )
3807       {
3808          if( !EPSISINT(monomial->exponents[j], 0.0) || monomial->exponents[j] < 0.0 )  /*lint !e835*/
3809          {
3810             monomialdegree = SCIP_EXPR_DEGREEINFINITY;
3811             break;
3812          }
3813 
3814          monomialdegree += (int)EPSROUND(monomial->exponents[j], 0.0);  /*lint !e835*/
3815       }
3816 
3817       if( monomialdegree == SCIP_EXPR_DEGREEINFINITY )
3818       {
3819          maxdegree = SCIP_EXPR_DEGREEINFINITY;
3820          break;
3821       }
3822 
3823       if( monomialdegree == 1 )
3824          ++nlinmonomials;
3825 
3826       if( monomialdegree > maxdegree )
3827          maxdegree = monomialdegree;
3828    }
3829    assert(maxdegree > 0 );
3830 
3831    if( maxdegree == 1 )
3832    {
3833       /* polynomial is a linear expression in children */
3834 
3835       /* polynomial simplification and monomial merging should ensure that monomial i corresponds to child i and that there are not unused children */
3836       assert(polynomialdata->nmonomials == nchildren);
3837       assert(polynomialdata->nmonomials == nlinmonomials);
3838 
3839       if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3840       {
3841          /* polynomial is addition of two expressions, so turn into SCIP_EXPR_PLUS */
3842          assert(polynomialdata->monomials[0]->nfactors == 1);
3843          assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3844          assert(polynomialdata->monomials[1]->nfactors == 1);
3845          assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3846 
3847          polynomialdataFree(blkmem, &polynomialdata);
3848          data->data = NULL;
3849 
3850          /* change operator type to PLUS */
3851          *op = SCIP_EXPR_PLUS;
3852 
3853          return SCIP_OKAY;
3854       }
3855 
3856       if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == -1.0 )
3857       {
3858          /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3859          assert(polynomialdata->monomials[0]->nfactors == 1);
3860          assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3861          assert(polynomialdata->monomials[1]->nfactors == 1);
3862          assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3863 
3864          polynomialdataFree(blkmem, &polynomialdata);
3865          data->data = NULL;
3866 
3867          /* change operator type to MINUS */
3868          *op = SCIP_EXPR_MINUS;
3869 
3870          return SCIP_OKAY;
3871       }
3872 
3873       if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == -1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3874       {
3875          /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3876          void* tmp;
3877 
3878          assert(polynomialdata->monomials[0]->nfactors == 1);
3879          assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3880          assert(polynomialdata->monomials[1]->nfactors == 1);
3881          assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3882 
3883          polynomialdataFree(blkmem, &polynomialdata);
3884          data->data = NULL;
3885 
3886          /* swap children */
3887          tmp = children[1];           /*lint !e613*/
3888          children[1] = children[0];   /*lint !e613*/
3889          children[0] = tmp;           /*lint !e613*/
3890 
3891          /* change operator type to MINUS */
3892          *op = SCIP_EXPR_MINUS;
3893 
3894          return SCIP_OKAY;
3895       }
3896 
3897       if( polynomialdata->constant == 0.0 )
3898       {
3899          /* check if all monomials have coefficient 1.0 */
3900          for( i = 0; i < polynomialdata->nmonomials; ++i )
3901             if( polynomialdata->monomials[i]->coef != 1.0 )
3902                break;
3903 
3904          if( i == polynomialdata->nmonomials )
3905          {
3906             /* polynomial is sum of children, so turn into SCIP_EXPR_SUM */
3907 
3908             polynomialdataFree(blkmem, &polynomialdata);
3909             data->data = NULL;
3910 
3911             /* change operator type to MINUS */
3912             *op = SCIP_EXPR_SUM;
3913 
3914             return SCIP_OKAY;
3915          }
3916       }
3917 
3918       /* turn polynomial into linear expression */
3919       {
3920          SCIP_Real* lindata;
3921 
3922          /* monomial merging should ensure that each child appears in at most one monomial,
3923           * that monomials are ordered according to the child index, and that constant monomials have been removed
3924           */
3925 
3926          /* setup data of linear expression */
3927          SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &lindata, polynomialdata->nmonomials + 1) );
3928 
3929          for( i = 0; i < polynomialdata->nmonomials; ++i )
3930          {
3931             assert(polynomialdata->monomials[i]->childidxs[0] == i);
3932             assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3933             lindata[i] = polynomialdata->monomials[i]->coef;  /*lint !e644*/
3934          }
3935          lindata[i] = polynomialdata->constant;
3936 
3937          polynomialdataFree(blkmem, &polynomialdata);
3938          *op = SCIP_EXPR_LINEAR;
3939          data->data = (void*)lindata;
3940 
3941          return SCIP_OKAY;
3942       }
3943    }
3944 
3945    if( maxdegree == 2 && (polynomialdata->nmonomials > 1 || polynomialdata->constant != 0.0 || polynomialdata->monomials[0]->coef != 1.0) )
3946    {
3947       /* polynomial is quadratic expression with more than one summand or with a constant or a square or bilinear term with coefficient != 1.0, so turn into SCIP_EXPR_QUADRATIC */
3948       SCIP_EXPRDATA_QUADRATIC* quaddata;
3949       int quadelemidx;
3950 
3951       SCIP_ALLOC( BMSallocBlockMemory(blkmem, &quaddata) );
3952       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->quadelems, polynomialdata->nmonomials - nlinmonomials) );
3953       quaddata->nquadelems = polynomialdata->nmonomials - nlinmonomials;
3954       quaddata->constant = polynomialdata->constant;
3955       quaddata->sorted = FALSE; /* quadratic data is sorted different than polynomials */
3956 
3957       if( nlinmonomials > 0 )
3958       {
3959          SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->lincoefs, nchildren) );
3960          BMSclearMemoryArray(quaddata->lincoefs, nchildren);
3961       }
3962       else
3963          quaddata->lincoefs = NULL;
3964 
3965       quadelemidx = 0;
3966       for( i = 0; i < polynomialdata->nmonomials; ++i )
3967       {
3968          assert(polynomialdata->monomials[i]->nfactors == 1 || polynomialdata->monomials[i]->nfactors == 2);
3969          if( polynomialdata->monomials[i]->nfactors == 1 )
3970          {
3971             if( polynomialdata->monomials[i]->exponents[0] == 1.0 )
3972             {
3973                /* monomial is a linear term */
3974                assert(quaddata->lincoefs != NULL);
3975                /* coverity[var_deref_op] */
3976                quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3977             }
3978             else
3979             {
3980                /* monomial should be a square term */
3981                assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3982                assert(quadelemidx < quaddata->nquadelems);
3983                quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3984                quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3985                quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3986                ++quadelemidx;
3987             }
3988          }
3989          else
3990          {
3991             /* monomial should be a bilinear term */
3992             assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3993             assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3994             assert(quadelemidx < quaddata->nquadelems);
3995             quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3996             quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3997             quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3998             ++quadelemidx;
3999          }
4000       }
4001       assert(quadelemidx == quaddata->nquadelems);
4002 
4003       polynomialdataFree(blkmem, &polynomialdata);
4004 
4005       *op = SCIP_EXPR_QUADRATIC;
4006       data->data = (void*)quaddata;
4007 
4008       return SCIP_OKAY;
4009    }
4010 
4011    if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
4012    {
4013       /* polynomial is product of children */
4014       monomial = polynomialdata->monomials[0];
4015       assert(monomial->nfactors == nchildren);
4016 
4017       if( monomial->nfactors == 1 )
4018       {
4019          /* polynomial is x^k for some k */
4020          assert(monomial->exponents[0] != 1.0); /* should have been handled before */
4021          assert(monomial->childidxs[0] == 0);
4022 
4023          if( monomial->exponents[0] == 2.0 )
4024          {
4025             /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
4026 
4027             polynomialdataFree(blkmem, &polynomialdata);
4028             data->data = NULL;
4029 
4030             *op = SCIP_EXPR_SQUARE;
4031 
4032             return SCIP_OKAY;
4033          }
4034 
4035          if( EPSISINT(monomial->exponents[0], 0.0) )  /*lint !e835*/
4036          {
4037             /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
4038             int exponent;
4039 
4040             exponent = (int)EPSROUND(monomial->exponents[0], 0.0);  /*lint !e835*/
4041 
4042             polynomialdataFree(blkmem, &polynomialdata);
4043 
4044             *op = SCIP_EXPR_INTPOWER;
4045             data->intval = exponent;
4046 
4047             return SCIP_OKAY;
4048          }
4049 
4050          if( monomial->exponents[0] == 0.5 )
4051          {
4052             /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
4053 
4054             polynomialdataFree(blkmem, &polynomialdata);
4055             data->data = NULL;
4056 
4057             *op = SCIP_EXPR_SQRT;
4058 
4059             return SCIP_OKAY;
4060          }
4061 
4062          {
4063             /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
4064             SCIP_Real exponent;
4065 
4066             exponent = monomial->exponents[0];
4067 
4068             polynomialdataFree(blkmem, &polynomialdata);
4069 
4070             *op = SCIP_EXPR_REALPOWER;
4071             data->dbl = exponent;
4072 
4073             return SCIP_OKAY;
4074          }
4075       }
4076 
4077       if( maxdegree == 2 && monomial->nfactors == 2 )
4078       {
4079          /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
4080          assert(monomial->exponents[0] == 1.0);
4081          assert(monomial->exponents[1] == 1.0);
4082 
4083          polynomialdataFree(blkmem, &polynomialdata);
4084          data->data = NULL;
4085 
4086          *op = SCIP_EXPR_MUL;
4087 
4088          return SCIP_OKAY;
4089       }
4090 
4091       if( maxdegree == monomial->nfactors )
4092       {
4093          /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
4094 
4095          polynomialdataFree(blkmem, &polynomialdata);
4096          data->data = NULL;
4097 
4098          *op = SCIP_EXPR_PRODUCT;
4099 
4100          return SCIP_OKAY;
4101       }
4102 
4103       if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
4104       {
4105          /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
4106          assert(monomial->childidxs[0] == 0);
4107          assert(monomial->childidxs[1] == 1);
4108 
4109          polynomialdataFree(blkmem, &polynomialdata);
4110          data->data = NULL;
4111 
4112          *op = SCIP_EXPR_DIV;
4113 
4114          return SCIP_OKAY;
4115       }
4116 
4117       if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
4118       {
4119          /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
4120          void* tmp;
4121 
4122          assert(monomial->childidxs[0] == 0);
4123          assert(monomial->childidxs[1] == 1);
4124 
4125          polynomialdataFree(blkmem, &polynomialdata);
4126          data->data = NULL;
4127 
4128          /* swap children */
4129          tmp = children[1];           /*lint !e613*/
4130          children[1] = children[0];   /*lint !e613*/
4131          children[0] = tmp;           /*lint !e613*/
4132 
4133          *op = SCIP_EXPR_DIV;
4134 
4135          return SCIP_OKAY;
4136       }
4137    }
4138 
4139    return SCIP_OKAY;
4140 }
4141 
4142 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
4143  *
4144  *  For a sum or product expression, this corresponds to add additional summands and factors, resp.
4145  *  For a linear expression, this corresponds to add each expression with coefficient 1.0.
4146  *  For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
4147  */
4148 static
exprsimplifyAddChildren(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,int nexprs,SCIP_EXPR ** exprs,SCIP_Bool comparechildren,SCIP_Real eps,int * childmap)4149 SCIP_RETCODE exprsimplifyAddChildren(
4150    BMS_BLKMEM*           blkmem,             /**< block memory */
4151    SCIP_EXPR*            expr,               /**< quadratic or polynomial expression */
4152    int                   nexprs,             /**< number of expressions to add */
4153    SCIP_EXPR**           exprs,              /**< expressions to add */
4154    SCIP_Bool             comparechildren,    /**< whether to compare expressions with already existing children (no effect for sum and product) */
4155    SCIP_Real             eps,                /**< which epsilon to use when comparing expressions */
4156    int*                  childmap            /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4157    )
4158 {
4159    int i;
4160 
4161    assert(blkmem != NULL);
4162    assert(expr != NULL);
4163    assert(expr->op == SCIP_EXPR_SUM || expr->op == SCIP_EXPR_PRODUCT || expr->op == SCIP_EXPR_LINEAR || expr->op == SCIP_EXPR_QUADRATIC || expr->op == SCIP_EXPR_POLYNOMIAL);
4164    assert(exprs != NULL || nexprs == 0);
4165 
4166    if( nexprs == 0 )
4167       return SCIP_OKAY;
4168 
4169    switch( expr->op )
4170    {
4171    case SCIP_EXPR_SUM:
4172    case SCIP_EXPR_PRODUCT:
4173    {
4174       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4175       for( i = 0; i < nexprs; ++i )
4176       {
4177          SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) );  /*lint !e613*/
4178          if( childmap != NULL )
4179             childmap[i] = expr->nchildren + i;
4180       }
4181       expr->nchildren += nexprs;
4182 
4183       break;
4184    }
4185 
4186    case SCIP_EXPR_LINEAR:
4187    case SCIP_EXPR_QUADRATIC:
4188    case SCIP_EXPR_POLYNOMIAL:
4189    {
4190       int j;
4191       int orignchildren;
4192       SCIP_Bool existsalready;
4193 
4194       orignchildren = expr->nchildren;
4195       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4196 
4197       for( i = 0; i < nexprs; ++i )
4198       {
4199          existsalready = FALSE;
4200          if( comparechildren )
4201             for( j = 0; j < orignchildren; ++j )
4202                /* during simplification of polynomials, their may be NULL's in children array */
4203                if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) )  /*lint !e613*/
4204                {
4205                   existsalready = TRUE;
4206                   break;
4207                }
4208 
4209          if( !existsalready )
4210          {
4211             /* add copy of exprs[j] to children array */
4212             SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) );  /*lint !e613*/
4213             if( childmap != NULL )
4214                childmap[i] = expr->nchildren;
4215             ++expr->nchildren;
4216          }
4217          else
4218          {
4219             if( childmap != NULL )
4220                childmap[i] = j;  /*lint !e644*/
4221             if( expr->op == SCIP_EXPR_LINEAR )
4222             {
4223                /* if linear expression, increase coefficient by 1.0 */
4224                ((SCIP_Real*)expr->data.data)[j] += 1.0;
4225             }
4226          }
4227       }
4228 
4229       /* shrink children array to actually used size */
4230       assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4231       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4232 
4233       if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4234       {
4235          /* if linear expression, then add 1.0 coefficients for new expressions */
4236          SCIP_Real* data;
4237 
4238          data = (SCIP_Real*)expr->data.data;
4239          SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4240          data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4241          for( i = orignchildren; i < expr->nchildren; ++i )
4242             data[i] = 1.0;
4243          expr->data.data = (void*)data;
4244       }
4245       else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4246       {
4247          /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4248          SCIP_EXPRDATA_QUADRATIC* data;
4249 
4250          data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4251          SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4252          BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren);  /*lint !e866*/
4253       }
4254 
4255       break;
4256    }
4257 
4258    default:
4259       SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4260       return SCIP_INVALIDDATA;
4261    }  /*lint !e788*/
4262 
4263    return SCIP_OKAY;
4264 }
4265 
4266 /** converts expressions into polynomials, where possible and obvious */
4267 static
exprsimplifyConvertToPolynomials(BMS_BLKMEM * blkmem,SCIP_EXPR * expr)4268 SCIP_RETCODE exprsimplifyConvertToPolynomials(
4269    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
4270    SCIP_EXPR*            expr                /**< expression to convert */
4271    )
4272 {
4273    int i;
4274 
4275    assert(expr != NULL);
4276 
4277    for( i = 0; i < expr->nchildren; ++i )
4278    {
4279       SCIP_CALL( exprsimplifyConvertToPolynomials(blkmem, expr->children[i]) );
4280    }
4281 
4282    SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4283 
4284    return SCIP_OKAY;
4285 }
4286 
4287 /** removes duplicate children in a polynomial expression
4288  *
4289  *  Leaves NULL's in children array.
4290  */
4291 static
exprsimplifyRemoveDuplicatePolynomialChildren(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,SCIP_Real eps)4292 SCIP_RETCODE exprsimplifyRemoveDuplicatePolynomialChildren(
4293    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
4294    SCIP_EXPR*            expr,               /**< expression */
4295    SCIP_Real             eps                 /**< threshold for zero */
4296    )
4297 {
4298    SCIP_Bool foundduplicates;
4299    int* childmap;
4300    int i;
4301    int j;
4302 
4303    assert(blkmem != NULL);
4304    assert(expr != NULL);
4305    assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4306 
4307    if( expr->nchildren == 0 )
4308       return SCIP_OKAY;
4309 
4310    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4311 
4312    foundduplicates = FALSE;
4313    for( i = 0; i < expr->nchildren; ++i )
4314    {
4315       if( expr->children[i] == NULL )
4316          continue;
4317       childmap[i] = i;  /*lint !e644*/
4318 
4319       for( j = i+1; j < expr->nchildren; ++j )
4320       {
4321          if( expr->children[j] == NULL )
4322             continue;
4323 
4324          if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4325          {
4326             /* forget about expr j and remember that is to be replaced by i */
4327             SCIPexprFreeDeep(blkmem, &expr->children[j]);
4328             childmap[j] = i;
4329             foundduplicates = TRUE;
4330          }
4331       }
4332    }
4333 
4334    /* apply childmap to monomials */
4335    if( foundduplicates )
4336       polynomialdataApplyChildmap((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, childmap);
4337 
4338    /* free childmap */
4339    BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4340 
4341    return SCIP_OKAY;
4342 }
4343 
4344 /** eliminates NULL's in children array and shrinks it to actual size */
4345 static
exprsimplifyRemovePolynomialNullChildren(BMS_BLKMEM * blkmem,SCIP_EXPR * expr)4346 SCIP_RETCODE exprsimplifyRemovePolynomialNullChildren(
4347    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
4348    SCIP_EXPR*            expr                /**< expression */
4349    )
4350 {
4351    int* childmap;
4352    int lastnonnull;
4353    int i;
4354 
4355    assert(blkmem != NULL);
4356    assert(expr != NULL);
4357    assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4358 
4359    if( expr->nchildren == 0 )
4360       return SCIP_OKAY;
4361 
4362    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4363 
4364    /* close gaps in children array */
4365    lastnonnull = expr->nchildren-1;
4366    while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4367       --lastnonnull;
4368    for( i = 0; i <= lastnonnull; ++i )
4369    {
4370       if( expr->children[i] != NULL )
4371       {
4372          childmap[i] = i; /* child at index i is not moved */  /*lint !e644*/
4373          continue;
4374       }
4375       assert(expr->children[lastnonnull] != NULL);
4376 
4377       /* move child at lastnonnull to position i */
4378       expr->children[i] = expr->children[lastnonnull];
4379       expr->children[lastnonnull] = NULL;
4380       childmap[lastnonnull] = i;
4381 
4382       /* update lastnonnull */
4383       --lastnonnull;
4384       while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4385          --lastnonnull;
4386    }
4387    assert(i > lastnonnull);
4388 
4389    /* apply childmap to monomials */
4390    if( lastnonnull < expr->nchildren-1 )
4391       polynomialdataApplyChildmap((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, childmap);
4392 
4393    BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4394 
4395    /* shrink children array */
4396    if( lastnonnull >= 0 )
4397    {
4398       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4399       expr->nchildren = lastnonnull+1;
4400    }
4401    else
4402    {
4403       BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4404       expr->nchildren = 0;
4405    }
4406 
4407    return SCIP_OKAY;
4408 }
4409 
4410 /** checks which children are still in use and frees those which are not */
4411 static
exprsimplifyRemovePolynomialUnusedChildren(BMS_BLKMEM * blkmem,SCIP_EXPR * expr)4412 SCIP_RETCODE exprsimplifyRemovePolynomialUnusedChildren(
4413    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
4414    SCIP_EXPR*            expr                /**< polynomial expression */
4415    )
4416 {
4417    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4418    SCIP_EXPRDATA_MONOMIAL* monomial;
4419    SCIP_Bool* childinuse;
4420    int i;
4421    int j;
4422 
4423    assert(blkmem != NULL);
4424    assert(expr != NULL);
4425 
4426    if( expr->nchildren == 0 )
4427       return SCIP_OKAY;
4428 
4429    polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4430    assert(polynomialdata != NULL);
4431 
4432    /* check which children are still in use */
4433    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4434    BMSclearMemoryArray(childinuse, expr->nchildren);  /*lint !e644*/
4435    for( i = 0; i < polynomialdata->nmonomials; ++i )
4436    {
4437       monomial = polynomialdata->monomials[i];
4438       assert(monomial != NULL);
4439 
4440       for( j = 0; j < monomial->nfactors; ++j )
4441       {
4442          assert(monomial->childidxs[j] >= 0);
4443          assert(monomial->childidxs[j] < expr->nchildren);
4444          childinuse[monomial->childidxs[j]] = TRUE;
4445       }
4446    }
4447 
4448    /* free children that are not used in any monomial */
4449    for( i = 0; i < expr->nchildren; ++i )
4450       if( expr->children[i] != NULL && !childinuse[i] )
4451          SCIPexprFreeDeep(blkmem, &expr->children[i]);
4452 
4453    BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4454 
4455    return SCIP_OKAY;
4456 }
4457 
4458 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4459  *
4460  *  exprsimplifyConvertToPolynomials should have been called before to eliminate simple polynomial operands.
4461  */
4462 static
exprsimplifyFlattenPolynomials(BMS_BLKMEM * blkmem,SCIP_MESSAGEHDLR * messagehdlr,SCIP_EXPR * expr,SCIP_Real eps,int maxexpansionexponent)4463 SCIP_RETCODE exprsimplifyFlattenPolynomials(
4464    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
4465    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
4466    SCIP_EXPR*            expr,               /**< expression */
4467    SCIP_Real             eps,                /**< threshold, under which values are treat as 0 */
4468    int                   maxexpansionexponent/**< maximal exponent for which we still expand non-monomial polynomials */
4469    )
4470 {
4471    int i;
4472 
4473    assert(expr != NULL);
4474 
4475    for( i = 0; i < expr->nchildren; ++i )
4476    {
4477       SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr->children[i], eps, maxexpansionexponent) );
4478    }
4479 
4480    switch( SCIPexprGetOperator(expr) )
4481    {
4482    case SCIP_EXPR_VARIDX:
4483    case SCIP_EXPR_CONST:
4484    case SCIP_EXPR_PARAM:
4485    case SCIP_EXPR_PLUS:
4486    case SCIP_EXPR_MINUS:
4487    case SCIP_EXPR_MUL:
4488    case SCIP_EXPR_DIV:
4489    case SCIP_EXPR_SQUARE:
4490    case SCIP_EXPR_SQRT:
4491    case SCIP_EXPR_INTPOWER:
4492    case SCIP_EXPR_REALPOWER:
4493    case SCIP_EXPR_SIGNPOWER:
4494       break;
4495 
4496    case SCIP_EXPR_EXP:
4497    case SCIP_EXPR_LOG:
4498    case SCIP_EXPR_SIN:
4499    case SCIP_EXPR_COS:
4500    case SCIP_EXPR_TAN:
4501       /* case SCIP_EXPR_ERF: */
4502       /* case SCIP_EXPR_ERFI: */
4503    case SCIP_EXPR_ABS:
4504    case SCIP_EXPR_SIGN:
4505    {
4506       /* check if argument is a constant */
4507       if( (expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) ||
4508          expr->children[0]->op == SCIP_EXPR_CONST )
4509       {
4510          SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4511          SCIP_Real exprval;
4512 
4513          /* since child0 has no children and it's polynomial was flattened, it should have no monomials */
4514          assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4515 
4516          /* evaluate expression in constant polynomial */
4517          SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4518 
4519          /* create polynomial */
4520          SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4521 
4522          expr->op = SCIP_EXPR_POLYNOMIAL;
4523          expr->data.data = (void*)polynomialdata;
4524 
4525          /* forget child */
4526          SCIPexprFreeDeep(blkmem, &expr->children[0]);
4527          BMSfreeBlockMemoryArray(blkmem, &expr->children, 1);
4528          expr->nchildren = 0;
4529       }
4530 
4531       break;
4532    }
4533 
4534    case SCIP_EXPR_MIN:
4535    case SCIP_EXPR_MAX:
4536    {
4537       /* check if both arguments are constants */
4538       if( ((expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) || expr->children[0]->op == SCIP_EXPR_CONST) &&
4539          ((expr->children[1]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[1]) == 0) || expr->children[1]->op == SCIP_EXPR_CONST) )
4540       {
4541          SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4542          SCIP_Real exprval;
4543 
4544          /* since children have no children and it's polynomial was flattened, it should have no monomials */
4545          assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4546          assert(expr->children[1]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[1]) == 0);
4547 
4548          /* evaluate expression in constants */
4549          SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4550 
4551          /* create polynomial */
4552          SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4553 
4554          expr->op = SCIP_EXPR_POLYNOMIAL;
4555          expr->data.data = (void*)polynomialdata;
4556 
4557          /* forget children */
4558          SCIPexprFreeDeep(blkmem, &expr->children[0]);
4559          SCIPexprFreeDeep(blkmem, &expr->children[1]);
4560          BMSfreeBlockMemoryArray(blkmem, &expr->children, 2);
4561          expr->nchildren = 0;
4562       }
4563 
4564       break;
4565    }
4566 
4567    case SCIP_EXPR_SUM:
4568    case SCIP_EXPR_PRODUCT:
4569    case SCIP_EXPR_LINEAR:
4570    case SCIP_EXPR_QUADRATIC:
4571    case SCIP_EXPR_USER:
4572       break;
4573 
4574    case SCIP_EXPR_POLYNOMIAL:
4575    {
4576       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4577       SCIP_EXPRDATA_MONOMIAL* monomial;
4578       SCIP_Bool removechild;
4579       int* childmap;
4580       int childmapsize;
4581       int j;
4582 
4583       /* simplify current polynomial */
4584       SCIP_CALL( exprsimplifyRemoveDuplicatePolynomialChildren(blkmem, expr, eps) );
4585       SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4586 
4587       polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4588       assert(polynomialdata != NULL);
4589 
4590       SCIPdebugMessage("expand factors in expression ");
4591       SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4592       SCIPdebugPrintf("\n");
4593 
4594       childmap = NULL;
4595       childmapsize = 0;
4596 
4597       /* resolve children that are constants
4598        * we do this first, because it reduces the degree and number of factors in the monomials,
4599        *   thereby allowing some expansions of polynomials that may not be possible otherwise, e.g., turning c0*c1 with c0=quadratic and c1=constant into a single monomial
4600        */
4601       for( i = 0; i < expr->nchildren; ++i )
4602       {
4603          if( expr->children[i] == NULL )
4604             continue;
4605 
4606          if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_CONST )
4607             continue;
4608 
4609          removechild = TRUE; /* we intend to delete children[i] */
4610 
4611          if( childmapsize < expr->children[i]->nchildren )
4612          {
4613             int newsize;
4614 
4615             newsize = calcGrowSize(expr->children[i]->nchildren);
4616             SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4617             childmapsize = newsize;
4618          }
4619 
4620          /* put constant of child i into every monomial where child i is used */
4621          for( j = 0; j < polynomialdata->nmonomials; ++j )
4622          {
4623             int factorpos;
4624             SCIP_Bool success;
4625 
4626             monomial = polynomialdata->monomials[j];
4627             /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4628             assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4629 
4630             if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4631             {
4632                assert(factorpos >= 0);
4633                assert(factorpos < monomial->nfactors);
4634                /* assert that factors have been merged */
4635                assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4636                assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4637 
4638                /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4639                   SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4640                   SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4641 
4642                if( !EPSISINT(monomial->exponents[factorpos], 0.0) && SCIPexprGetOpReal(expr->children[i]) < 0.0 )  /*lint !e835*/
4643                {
4644                   /* if constant is negative and our exponent is not integer, then cannot do expansion */
4645                   SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n",
4646                      SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4647                   success = FALSE;
4648                }
4649                else
4650                {
4651                   monomial->coef *= pow(SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4652 
4653                   /* move last factor to position factorpos */
4654                   if( factorpos < monomial->nfactors-1 )
4655                   {
4656                      monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
4657                      monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
4658                   }
4659                   --monomial->nfactors;
4660                   monomial->sorted = FALSE;
4661                   polynomialdata->sorted = FALSE;
4662 
4663                   success = TRUE;
4664                }
4665 
4666                if( !success )
4667                   removechild = FALSE;
4668             }
4669          }
4670 
4671          /* forget about child i, if it is not used anymore */
4672          if( removechild )
4673             SCIPexprFreeDeep(blkmem, &expr->children[i]);
4674 
4675          /* simplify current polynomial again */
4676          SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4677       }
4678 
4679       /* try to resolve children that are polynomials itself */
4680       for( i = 0; i < expr->nchildren; ++i )
4681       {
4682          if( expr->children[i] == NULL )
4683             continue;
4684 
4685          if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_POLYNOMIAL )
4686             continue;
4687 
4688          removechild = TRUE; /* we intend to delete children[i] */
4689 
4690          if( childmapsize < expr->children[i]->nchildren )
4691          {
4692             int newsize;
4693 
4694             newsize = calcGrowSize(expr->children[i]->nchildren);
4695             SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4696             childmapsize = newsize;
4697          }
4698 
4699          /* add children of child i */
4700          SCIP_CALL( exprsimplifyAddChildren(blkmem, expr, expr->children[i]->nchildren, expr->children[i]->children, TRUE, eps, childmap) );
4701 
4702          /* put polynomial of child i into every monomial where child i is used */
4703          j = 0;
4704          while( j < polynomialdata->nmonomials )
4705          {
4706             int factorpos;
4707             SCIP_Bool success;
4708 
4709             monomial = polynomialdata->monomials[j];
4710             /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4711             assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4712 
4713             if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4714             {
4715                assert(factorpos >= 0);
4716                assert(factorpos < monomial->nfactors);
4717                /* assert that factors have been merged */
4718                assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4719                assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4720 
4721                /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4722                   SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4723                   SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4724 
4725                SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
4726                      (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4727 
4728                if( !success )
4729                {
4730                   removechild = FALSE;
4731                   ++j;
4732                }
4733             }
4734             else
4735                ++j;
4736 
4737             /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4738              * we thus repeat with index j, if a factor was successfully expanded
4739              */
4740          }
4741 
4742          /* forget about child i, if it is not used anymore */
4743          if( removechild )
4744             SCIPexprFreeDeep(blkmem, &expr->children[i]);
4745 
4746          /* simplify current polynomial again */
4747          SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4748       }
4749 
4750       BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4751 
4752       /* free children that are not in use anymore */
4753       SCIP_CALL( exprsimplifyRemovePolynomialUnusedChildren(blkmem, expr) );
4754 
4755       /* remove NULLs from children array */
4756       SCIP_CALL( exprsimplifyRemovePolynomialNullChildren(blkmem, expr) );
4757 
4758       /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4759       if( expr->nchildren == 0 )
4760       {
4761          SCIP_Real val;
4762 
4763          /* if no children, then it should also have no monomials */
4764          assert(polynomialdata->nmonomials == 0);
4765 
4766          val = polynomialdata->constant;
4767          polynomialdataFree(blkmem, &polynomialdata);
4768 
4769          expr->op = SCIP_EXPR_CONST;
4770          expr->data.dbl = val;
4771       }
4772 
4773       SCIPdebugMessage("-> ");
4774       SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4775       SCIPdebugPrintf("\n");
4776 
4777       break;
4778    }
4779 
4780    case SCIP_EXPR_LAST:
4781       break;
4782    }  /*lint !e788*/
4783 
4784    return SCIP_OKAY;
4785 }
4786 
4787 /** separates linear monomials from an expression, if it is a polynomial expression
4788  *
4789  *  Separates only those linear terms whose variable is not used otherwise in the expression.
4790  */
4791 static
exprsimplifySeparateLinearFromPolynomial(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,SCIP_Real eps,int nvars,int * nlinvars,int * linidxs,SCIP_Real * lincoefs)4792 SCIP_RETCODE exprsimplifySeparateLinearFromPolynomial(
4793    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
4794    SCIP_EXPR*            expr,               /**< expression */
4795    SCIP_Real             eps,                /**< threshold, under which positive values are treat as 0 */
4796    int                   nvars,              /**< number of variables in expression */
4797    int*                  nlinvars,           /**< buffer to store number of linear variables in linear part */
4798    int*                  linidxs,            /**< array to store indices of variables in expression tree which belong to linear part */
4799    SCIP_Real*            lincoefs            /**< array to store coefficients of linear part */
4800    )
4801 {
4802    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4803    SCIP_EXPRDATA_MONOMIAL* monomial;
4804    int* varsusage;
4805    int* childusage;
4806    int childidx;
4807    int i;
4808    int j;
4809 
4810    assert(blkmem != NULL);
4811    assert(expr != NULL);
4812    assert(nlinvars != NULL);
4813    assert(linidxs != NULL);
4814    assert(lincoefs != NULL);
4815 
4816    *nlinvars = 0;
4817 
4818    if( SCIPexprGetOperator(expr) != SCIP_EXPR_POLYNOMIAL )
4819       return SCIP_OKAY;
4820 
4821    if( SCIPexprGetNChildren(expr) == 0 )
4822       return SCIP_OKAY;
4823 
4824    polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4825    assert(polynomialdata != NULL);
4826 
4827    /* get variable usage */
4828    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4829    BMSclearMemoryArray(varsusage, nvars);  /*lint !e644*/
4830    SCIPexprGetVarsUsage(expr, varsusage);
4831 
4832    /* get child usage: how often each child is used in the polynomial */
4833    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4834    BMSclearMemoryArray(childusage, expr->nchildren);  /*lint !e644*/
4835    for( i = 0; i < polynomialdata->nmonomials; ++i )
4836    {
4837       monomial = polynomialdata->monomials[i];
4838       assert(monomial != NULL);
4839       for( j = 0; j < monomial->nfactors; ++j )
4840       {
4841          assert(monomial->childidxs[j] >= 0);
4842          assert(monomial->childidxs[j] < expr->nchildren);
4843          ++childusage[monomial->childidxs[j]];
4844       }
4845    }
4846 
4847    /* move linear monomials out of polynomial */
4848    for( i = 0; i < polynomialdata->nmonomials; ++i )
4849    {
4850       monomial = polynomialdata->monomials[i];
4851       assert(monomial != NULL);
4852       if( monomial->nfactors != 1 )
4853          continue;
4854       if( monomial->exponents[0] != 1.0 )
4855          continue;
4856       childidx = monomial->childidxs[0];
4857       if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4858          continue;
4859 
4860       /* we are at a linear monomial in a variable */
4861       assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4862       if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4863       {
4864          /* if the child expression is not used in another monomial (which would due to merging be not linear)
4865           * and if the variable is not used somewhere else in the tree,
4866           * then move this monomial into linear part and free child
4867           */
4868          linidxs[*nlinvars]  = SCIPexprGetOpIndex(expr->children[childidx]);
4869          lincoefs[*nlinvars] = monomial->coef;
4870          ++*nlinvars;
4871 
4872          SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4873          monomial->coef = 0.0;
4874          monomial->nfactors = 0;
4875       }
4876    }
4877 
4878    BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4879    BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4880 
4881    if( *nlinvars > 0 )
4882    {
4883       /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4884       polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4885       SCIP_CALL( exprsimplifyRemovePolynomialNullChildren(blkmem, expr) );
4886    }
4887 
4888    return SCIP_OKAY;
4889 }
4890 
4891 /** converts polynomial expressions back into simpler expressions, where possible */
4892 static
exprsimplifyUnconvertPolynomials(BMS_BLKMEM * blkmem,SCIP_EXPR * expr)4893 SCIP_RETCODE exprsimplifyUnconvertPolynomials(
4894    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
4895    SCIP_EXPR*            expr                /**< expression to convert back */
4896    )
4897 {
4898    int i;
4899 
4900    assert(blkmem != NULL);
4901    assert(expr != NULL);
4902 
4903    for( i = 0; i < expr->nchildren; ++i )
4904    {
4905       SCIP_CALL( exprsimplifyUnconvertPolynomials(blkmem, expr->children[i]) );
4906    }
4907 
4908    if( expr->op != SCIP_EXPR_POLYNOMIAL )
4909       return SCIP_OKAY;
4910 
4911    SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4912 
4913    return SCIP_OKAY;
4914 }
4915 
4916 static
SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)4917 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4918 {  /*lint --e{715}*/
4919    return (void*)((char*)elem + sizeof(int));
4920 }
4921 
4922 /** parses a variable name from a string and creates corresponding expression
4923  *
4924  *  Creates a new variable index if variable not seen before, updates varnames and vartable structures.
4925  */
4926 static
exprparseReadVariable(BMS_BLKMEM * blkmem,const char ** str,SCIP_EXPR ** expr,int * nvars,int ** varnames,int * varnameslength,SCIP_HASHTABLE * vartable,SCIP_Real coefficient,const char * varnameendptr)4927 SCIP_RETCODE exprparseReadVariable(
4928    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
4929    const char**          str,                /**< pointer to the string to be parsed */
4930    SCIP_EXPR**           expr,               /**< buffer to store pointer to created expression */
4931    int*                  nvars,              /**< running number of encountered variables so far */
4932    int**                 varnames,           /**< pointer to buffer to store new variable names */
4933    int*                  varnameslength,     /**< pointer to length of the varnames buffer array */
4934    SCIP_HASHTABLE*       vartable,           /**< hash table for variable names and corresponding expression index */
4935    SCIP_Real             coefficient,        /**< coefficient to be used when creating the expression */
4936    const char*           varnameendptr       /**< if a \<varname\> should be parsed, set this to NULL. Then, str points to the '<'
4937                                                   else, str should point to the first letter of the varname, and varnameendptr should
4938                                                   point one char behind the last char of the variable name */
4939    )
4940 {
4941    int namelength;
4942    int varidx;
4943    char varname[SCIP_MAXSTRLEN];
4944    void* element;
4945 
4946    assert(blkmem != NULL);
4947    assert(str != NULL);
4948    assert(expr != NULL);
4949    assert(nvars != NULL);
4950    assert(varnames != NULL);
4951    assert(vartable != NULL);
4952 
4953    if( varnameendptr == NULL )
4954    {
4955       ++*str;
4956       varnameendptr = *str;
4957       while( varnameendptr[0] != '>' )
4958          ++varnameendptr;
4959    }
4960 
4961    namelength = varnameendptr - *str; /*lint !e712*/
4962    if( namelength >= SCIP_MAXSTRLEN )
4963    {
4964       SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, *str);
4965       return SCIP_READERROR;
4966    }
4967 
4968    memcpy(varname, *str, namelength * sizeof(char));
4969    varname[namelength] = '\0';
4970 
4971    element = SCIPhashtableRetrieve(vartable, varname);
4972    if( element != NULL )
4973    {
4974       /* variable is old friend */
4975       assert(strcmp((char*)element + sizeof(int), varname) == 0);
4976 
4977       varidx = *(int*)element;
4978    }
4979    else
4980    {
4981       /* variable is new */
4982       varidx = *nvars;
4983 
4984       (*varnameslength) -= (int)(1 + (strlen(varname) + 1) / sizeof(int) + 1);
4985       if( *varnameslength < 0 )
4986       {
4987          SCIPerrorMessage("Buffer in exprparseReadVariable is too short for varaible name %.*s.\n", namelength, *str);
4988          return SCIP_READERROR;
4989       }
4990 
4991       /* store index of variable and variable name in varnames buffer */
4992       **varnames = varidx;
4993       (void) SCIPstrncpy((char*)(*varnames + 1), varname, (int)strlen(varname)+1);
4994 
4995       /* insert variable into hashtable */
4996       SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4997 
4998       ++*nvars;
4999       *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
5000    }
5001 
5002    /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
5003    SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) );  /*lint !e613*/
5004    if( coefficient != 1.0 )
5005    {
5006       SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
5007    }
5008 
5009    /* Move pointer to char behind end of variable */
5010    *str = varnameendptr + 1;
5011 
5012    /* consprint sometimes prints a variable type identifier which we don't need */
5013    if( (*str)[0] == '[' && (*str)[2] == ']' &&
5014        ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR  ||
5015         (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
5016         (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
5017         (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) )
5018       *str += 3;
5019 
5020    return SCIP_OKAY;
5021 }
5022 
5023 /** if str[0] points to an opening parenthesis, this function sets endptr to point to the matching closing bracket in str
5024  *
5025  *  Searches for at most length characters.
5026  */
5027 static
exprparseFindClosingParenthesis(const char * str,const char ** endptr,int length)5028 SCIP_RETCODE exprparseFindClosingParenthesis(
5029    const char*           str,                /**< pointer to the string to be parsed */
5030    const char**          endptr,             /**< pointer to point to the closing parenthesis */
5031    int                   length              /**< length of the string to be parsed */
5032    )
5033 {
5034    int nopenbrackets;
5035 
5036    assert(str[0] == '(');
5037 
5038    *endptr = str;
5039 
5040    /* find the end of this expression */
5041    nopenbrackets = 0;
5042    while( (*endptr - str ) < length && !(nopenbrackets == 1 && *endptr[0] == ')') )
5043    {
5044       if( *endptr[0] == '(')
5045          ++nopenbrackets;
5046       if( *endptr[0] == ')')
5047          --nopenbrackets;
5048       ++*endptr;
5049    }
5050 
5051    if( *endptr[0] != ')' )
5052    {
5053       SCIPerrorMessage("unable to find closing parenthesis in unbalanced expression %.*s\n", length, str);
5054       return SCIP_READERROR;
5055    }
5056 
5057    return SCIP_OKAY;
5058 }
5059 
5060 /** this function sets endptr to point to the next separating comma in str
5061  *
5062  *  That is, for a given string like "x+f(x,y),z", endptr will point to the comma before "z"
5063  *
5064  *  Searches for at most length characters.
5065  */
5066 static
exprparseFindSeparatingComma(const char * str,const char ** endptr,int length)5067 SCIP_RETCODE exprparseFindSeparatingComma(
5068    const char*           str,                /**< pointer to the string to be parsed */
5069    const char**          endptr,             /**< pointer to point to the comma */
5070    int                   length              /**< length of the string to be parsed */
5071    )
5072 {
5073    int nopenbrackets;
5074 
5075    *endptr = str;
5076 
5077    /* find a comma without open brackets */
5078    nopenbrackets = 0;
5079    while( (*endptr - str ) < length && !(nopenbrackets == 0 && *endptr[0] == ',') )
5080    {
5081       if( *endptr[0] == '(')
5082          ++nopenbrackets;
5083       if( *endptr[0] == ')')
5084          --nopenbrackets;
5085       ++*endptr;
5086    }
5087 
5088    if( *endptr[0] != ',' )
5089    {
5090       SCIPerrorMessage("unable to find separating comma in unbalanced expression %.*s\n", length, str);
5091       return SCIP_READERROR;
5092    }
5093 
5094    return SCIP_OKAY;
5095 }
5096 
5097 /** parses an expression from a string */
5098 static
exprParse(BMS_BLKMEM * blkmem,SCIP_MESSAGEHDLR * messagehdlr,SCIP_EXPR ** expr,const char * str,int length,const char * lastchar,int * nvars,int ** varnames,int * varnameslength,SCIP_HASHTABLE * vartable,int recursiondepth)5099 SCIP_RETCODE exprParse(
5100    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
5101    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
5102    SCIP_EXPR**           expr,               /**< buffer to store pointer to created expression */
5103    const char*           str,                /**< pointer to the string to be parsed */
5104    int                   length,             /**< length of the string to be parsed */
5105    const char*           lastchar,           /**< pointer to the last char of str that should be parsed */
5106    int*                  nvars,              /**< running number of encountered variables so far */
5107    int**                 varnames,           /**< pointer to buffer to store new variable names */
5108    int*                  varnameslength,     /**< pointer to length of the varnames buffer array */
5109    SCIP_HASHTABLE*       vartable,           /**< hash table for variable names and corresponding expression index */
5110    int                   recursiondepth      /**< current recursion depth */
5111    )
5112 {   /*lint --e{712,747}*/
5113    SCIP_EXPR* arg1;
5114    SCIP_EXPR* arg2;
5115    const char* subexpptr;
5116    const char* subexpendptr;
5117    const char* strstart;
5118    const char* endptr;
5119    char* nonconstendptr;
5120    SCIP_Real number;
5121    int subexplength;
5122    int nopenbrackets;
5123 
5124    assert(blkmem != NULL);
5125    assert(expr != NULL);
5126    assert(str != NULL);
5127    assert(lastchar >= str);
5128    assert(nvars != NULL);
5129    assert(varnames != NULL);
5130    assert(vartable != NULL);
5131 
5132    assert(recursiondepth < 100);
5133 
5134    strstart = str; /* might be needed for error message... */
5135 
5136    SCIPdebugMessage("exprParse (%i): parsing %.*s\n", recursiondepth, (int) (lastchar-str + 1), str);
5137 
5138    /* ignore whitespace */
5139    while( isspace((unsigned char)*str) )
5140       ++str;
5141 
5142    /* look for a sum or difference not contained in brackets */
5143    subexpptr = str;
5144    nopenbrackets = 0;
5145 
5146    /* find the end of this expression
5147     * a '+' right at the beginning indicates a coefficient, not treated here, or a summation
5148     * a '+' or '-' that follows an 'e' or 'E' indicates that we are in the middle of a number, so it doesn't separate terms
5149     */
5150    while( subexpptr != lastchar && !(nopenbrackets == 0 && (subexpptr[0] == '+' || subexpptr[0] == '-') && subexpptr != str && subexpptr[-1] != 'e' && subexpptr[-1] != 'E') )
5151    {
5152       if( subexpptr[0] == '(')
5153          ++nopenbrackets;
5154       if( subexpptr[0] == ')')
5155          --nopenbrackets;
5156       ++subexpptr;
5157    }
5158 
5159    if( subexpptr != lastchar )
5160    {
5161       SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str, (int) ((subexpptr - 1) - str + 1), subexpptr - 1, nvars,
5162             varnames, varnameslength, vartable, recursiondepth + 1) );
5163 
5164       if( subexpptr[0] == '+' )
5165          ++subexpptr;
5166       SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, subexpptr , (int) (lastchar - (subexpptr ) + 1), lastchar, nvars,
5167             varnames, varnameslength, vartable, recursiondepth + 1) );
5168 
5169       /* make new expression from two arguments
5170        * we always use add, because we leave the operator between the found expressions in the second argument
5171        * this way, we do not have to worry about ''minus brackets'' in the case of more then two summands:
5172        *   a - b - c = a + (-b -c)
5173        */
5174       SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5175 
5176       SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5177       SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5178       SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5179 
5180       return SCIP_OKAY;
5181    }
5182 
5183    /* check for a bracketed subexpression */
5184    if( str[0] == '(' )
5185    {
5186       nopenbrackets = 0;
5187 
5188       subexplength = -1;    /* we do not want the closing bracket in the string */
5189       subexpptr = str + 1;  /* leave out opening bracket */
5190 
5191       /* find the end of this expression */
5192       while( subexplength < length && !(nopenbrackets == 1 && str[0] == ')') )
5193       {
5194          if( str[0] == '(' )
5195             ++nopenbrackets;
5196          if( str[0] == ')' )
5197             --nopenbrackets;
5198          ++str;
5199          ++subexplength;
5200       }
5201       subexpendptr = str - 1; /* leave out closing bracket */
5202 
5203       SCIP_CALL( exprParse(blkmem, messagehdlr, expr, subexpptr, subexplength, subexpendptr, nvars, varnames,
5204             varnameslength, vartable, recursiondepth + 1) );
5205       ++str;
5206    }
5207    else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+')
5208          && (isdigit((unsigned char)str[1]) || str[1] == ' ')) )
5209    {
5210       /* check if there is a lonely minus coming, indicating a -1.0 */
5211       if( str[0] == '-'  && str[1] == ' ' )
5212       {
5213          number = -1.0;
5214          nonconstendptr = (char*) str + 1;
5215       }
5216       /* check if there is a number coming */
5217       else if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5218       {
5219          SCIPerrorMessage("error parsing number from <%s>\n", str);
5220          return SCIP_READERROR;
5221       }
5222       str = nonconstendptr;
5223 
5224       /* ignore whitespace */
5225       while( isspace((unsigned char)*str) && str != lastchar )
5226          ++str;
5227 
5228       if( str[0] != '*' && str[0] != '/' && str[0] != '+' && str[0] != '-' && str[0] != '^' )
5229       {
5230          if( str < lastchar )
5231          {
5232             SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int)(lastchar - str) + 1, lastchar, nvars, varnames,
5233                   varnameslength, vartable, recursiondepth + 1) );
5234             SCIP_CALL( SCIPexprMulConstant(blkmem, expr, *expr, number) );
5235          }
5236          else
5237          {
5238             SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5239          }
5240          str = lastchar + 1;
5241       }
5242       else
5243       {
5244          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5245       }
5246    }
5247    else if( str[0] == '<' )
5248    {
5249       /* check if expressions begins with a variable */
5250       SCIP_CALL( exprparseReadVariable(blkmem, &str, expr, nvars, varnames, varnameslength, vartable, 1.0, NULL) );
5251    }
5252    /* four character operators */
5253    else if( strncmp(str, "sqrt", 4) == 0 )
5254    {
5255       str += 4;
5256       SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5257       SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5258             varnameslength, vartable, recursiondepth + 1) );
5259       str = endptr + 1;
5260 
5261       SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQRT, arg1) );
5262    }
5263    /* three character operators with 1 argument */
5264    else if(
5265       strncmp(str, "abs", 3) == 0 ||
5266       strncmp(str, "cos", 3) == 0 ||
5267       strncmp(str, "exp", 3) == 0 ||
5268       strncmp(str, "log", 3) == 0 ||
5269       strncmp(str, "sin", 3) == 0 ||
5270       strncmp(str, "sqr", 3) == 0 ||
5271       strncmp(str, "tan", 3) == 0 )
5272    {
5273       const char* opname = str;
5274 
5275       str += 3;
5276       SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5277       SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5278             varnameslength, vartable, recursiondepth + 1) );
5279       str = endptr + 1;
5280 
5281       if( strncmp(opname, "abs", 3) == 0 )
5282       {
5283          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_ABS, arg1) );
5284       }
5285       else if( strncmp(opname, "cos", 3) == 0 )
5286       {
5287          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_COS, arg1) );
5288       }
5289       else if( strncmp(opname, "exp", 3) == 0 )
5290       {
5291          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, arg1) );
5292       }
5293       else if( strncmp(opname, "log", 3) == 0 )
5294       {
5295          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5296       }
5297       else if( strncmp(opname, "sin", 3) == 0 )
5298       {
5299          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIN, arg1) );
5300       }
5301       else if( strncmp(opname, "sqr", 3) == 0 )
5302       {
5303          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQUARE, arg1) );
5304       }
5305       else
5306       {
5307          assert(strncmp(opname, "tan", 3) == 0);
5308          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_TAN, arg1) );
5309       }
5310    }
5311    /* three character operators with 2 arguments */
5312    else if(
5313       strncmp(str, "max", 3) == 0 ||
5314       strncmp(str, "min", 3) == 0 )
5315    {
5316       /* we have a string of the form "min(...,...)" or "max(...,...)"
5317        * first find the closing parenthesis, then the comma
5318        */
5319       const char* comma;
5320       SCIP_EXPROP op;
5321 
5322       op = (str[1] == 'a' ? SCIP_EXPR_MAX : SCIP_EXPR_MIN);
5323 
5324       str += 3;
5325       SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5326 
5327       SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5328 
5329       /* parse first argument [str+1..comma-1] */
5330       SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5331             varnameslength, vartable, recursiondepth + 1) );
5332 
5333       /* parse second argument [comma+1..endptr] */
5334       ++comma;
5335       while( comma < endptr && *comma == ' ' )
5336          ++comma;
5337 
5338       SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, comma, endptr - comma, endptr - 1, nvars, varnames,
5339             varnameslength, vartable, recursiondepth + 1) );
5340 
5341       SCIP_CALL( SCIPexprCreate(blkmem, expr, op, arg1, arg2) );
5342 
5343       str = endptr + 1;
5344    }
5345    else if( strncmp(str, "power", 5) == 0 )
5346    {
5347       /* we have a string of the form "power(...,integer)" (thus, intpower)
5348        * first find the closing parenthesis, then the comma
5349        */
5350       const char* comma;
5351       int exponent;
5352 
5353       str += 5;
5354       SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5355 
5356       SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5357 
5358       /* parse first argument [str+1..comma-1] */
5359       SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5360             varnameslength, vartable, recursiondepth + 1) );
5361 
5362       ++comma;
5363       /* parse second argument [comma, endptr-1]: it needs to be an integer */
5364       while( comma < endptr && *comma == ' ' )
5365          ++comma;
5366       if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5367       {
5368          SCIPerrorMessage("error parsing integer exponent from <%s>\n", comma);
5369       }
5370       if( !SCIPstrToIntValue(comma, &exponent, &nonconstendptr) )
5371       {
5372          SCIPerrorMessage("error parsing integer from <%s>\n", comma);
5373          return SCIP_READERROR;
5374       }
5375 
5376       SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, exponent) );
5377 
5378       str = endptr + 1;
5379    }
5380    else if( strncmp(str, "realpower", 9) == 0 || strncmp(str, "signpower", 9) == 0 )
5381    {
5382       /* we have a string of the form "realpower(...,double)" or "signpower(...,double)"
5383        * first find the closing parenthesis, then the comma
5384        */
5385       const char* opname = str;
5386       const char* comma;
5387 
5388       str += 9;
5389       SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5390 
5391       SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5392 
5393       /* parse first argument [str+1..comma-1] */
5394       SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5395             varnameslength, vartable, recursiondepth + 1) );
5396 
5397       ++comma;
5398       /* parse second argument [comma, endptr-1]: it needs to be an number */
5399       while( comma < endptr && *comma == ' ' )
5400          ++comma;
5401       if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5402       {
5403          SCIPerrorMessage("error parsing number exponent from <%s>\n", comma);
5404       }
5405       if( !SCIPstrToRealValue(comma, &number, &nonconstendptr) )
5406       {
5407          SCIPerrorMessage("error parsing number from <%s>\n", comma);
5408          return SCIP_READERROR;
5409       }
5410 
5411       if( strncmp(opname, "realpower", 9) == 0 )
5412       {
5413          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, number) );
5414       }
5415       else
5416       {
5417          assert(strncmp(opname, "signpower", 9) == 0);
5418          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIGNPOWER, arg1, number) );
5419       }
5420 
5421       str = endptr + 1;
5422    }
5423    else if( isalpha(*str) || *str == '_' || *str == '#' )
5424    {
5425       /* check for a variable, that was not recognized earlier because somebody omitted the '<' and '>' we need for
5426        * SCIPparseVarName, making everyones life harder;
5427        * we allow only variable names starting with a character or underscore here
5428        */
5429       const char* varnamestartptr = str;
5430 
5431       /* allow only variable names containing characters, digits, hash marks, and underscores here */
5432       while( isalnum(str[0]) || str[0] == '_' || str[0] == '#' )
5433          ++str;
5434 
5435       SCIP_CALL( exprparseReadVariable(blkmem, &varnamestartptr, expr, nvars, varnames, varnameslength,
5436             vartable, 1.0, str) );
5437    }
5438    else
5439    {
5440       SCIPerrorMessage("parsing of invalid expression %.*s.\n", (int) (lastchar - str + 1), str);
5441       return SCIP_READERROR;
5442    }
5443 
5444    /* if we are one char behind lastchar, we are done */
5445    if( str == lastchar + 1)
5446    {
5447       SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5448       SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5449       SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5450 
5451       return SCIP_OKAY;
5452    }
5453 
5454    /* check if we are still in bounds */
5455    if( str > lastchar + 1)
5456    {
5457       SCIPerrorMessage("error finding first expression in \"%.*s\" took us outside of given subexpression length\n", length, strstart);
5458       return SCIP_READERROR;
5459    }
5460 
5461    /* ignore whitespace */
5462    while( isspace((unsigned char)*str) && str != lastchar + 1 )
5463       ++str;
5464 
5465    /* maybe now we're done? */
5466    if( str >= lastchar + 1)
5467    {
5468       SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5469       SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5470       SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5471 
5472       return SCIP_OKAY;
5473    }
5474 
5475    if( str[0] == '^' )
5476    {
5477       /* a '^' behind the found expression indicates a power */
5478       SCIP_Real constant;
5479 
5480       arg1 = *expr;
5481       ++str;
5482       while( isspace((unsigned char)*str) && str != lastchar + 1 )
5483          ++str;
5484 
5485       if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5486       {
5487          /* there is a number coming */
5488          if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5489          {
5490             SCIPerrorMessage("error parsing number from <%s>\n", str);
5491             return SCIP_READERROR;
5492          }
5493 
5494          SCIP_CALL( SCIPexprCreate(blkmem, &arg2, SCIP_EXPR_CONST, number) );
5495          str = nonconstendptr;
5496 
5497          constant = SCIPexprGetOpReal(arg2);
5498          SCIPexprFreeDeep(blkmem, &arg2);
5499 
5500          /* expr^number is intpower or realpower */
5501          if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5502          {
5503             SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5504          }
5505          else
5506          {
5507             SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5508          }
5509       }
5510       else if( str[0] == '(' )
5511       {
5512          /* we use exprParse to evaluate the exponent */
5513 
5514          SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5515          SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5516                varnameslength, vartable, recursiondepth + 1) );
5517 
5518          if( SCIPexprGetOperator(arg2) != SCIP_EXPR_CONST )
5519          {
5520             /* reformulate arg1^arg2 as exp(arg2 * log(arg1)) */
5521             SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5522             SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, *expr, arg2) );
5523             SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, *expr) );
5524          }
5525          else
5526          {
5527             /* expr^number is intpower or realpower */
5528             constant = SCIPexprGetOpReal(arg2);
5529             SCIPexprFreeDeep(blkmem, &arg2);
5530             if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5531             {
5532                SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5533             }
5534             else
5535             {
5536                SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5537             }
5538          }
5539          str = endptr + 1;
5540       }
5541       else
5542       {
5543          SCIPerrorMessage("unexpected string following ^ in  %.*s\n", length, str);
5544          return SCIP_READERROR;
5545       }
5546 
5547       /* ignore whitespace */
5548       while( isspace((unsigned char)*str) && str != lastchar + 1 )
5549          ++str;
5550    }
5551 
5552    /* check for a two argument operator that is not a multiplication */
5553    if( str <= lastchar && (str[0] == '+' || str[0] == '-' || str[0] == '/') )
5554    {
5555       char op;
5556 
5557       op = str[0];
5558       arg1 = *expr;
5559 
5560       /* step forward over the operator to go to the beginning of the second argument */
5561       ++str;
5562 
5563       SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5564             varnameslength, vartable, recursiondepth + 1) );
5565       str = lastchar + 1;
5566 
5567       /* make new expression from two arguments */
5568       if( op == '+')
5569       {
5570          SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5571       }
5572       else if( op == '-')
5573       {
5574          SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, -1.0, arg2, 0.0) );
5575       }
5576       else if( op == '*' )
5577       {
5578          if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5579          {
5580             SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5581          }
5582          else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5583          {
5584             SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5585          }
5586          else
5587          {
5588             SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5589          }
5590       }
5591       else
5592       {
5593          assert(op == '/');
5594 
5595          if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5596          {
5597             SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, 1.0 / SCIPexprGetOpReal(arg2)) );
5598             SCIPexprFreeShallow(blkmem, &arg2);
5599          }
5600          else
5601          {
5602             SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_DIV, arg1, arg2) );
5603          }
5604       }
5605    }
5606 
5607    /* ignore whitespace */
5608    while( isspace((unsigned char)*str) )
5609       ++str;
5610 
5611    /* we are either done or we have a multiplication? */
5612    if( str >= lastchar + 1 )
5613    {
5614       SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5615       SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5616       SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5617 
5618       return SCIP_OKAY;
5619    }
5620 
5621    /* if there is a part of the string left to be parsed, we assume that this as a multiplication */
5622    arg1 = *expr;
5623 
5624    /* stepping over multiplication operator if needed */
5625    if( str[0] == '*' )
5626    {
5627       ++str;
5628    }
5629    else if( str[0] != '(' )
5630    {
5631       SCIPdebugMessage("No operator found, assuming a multiplication before %.*s\n", (int) (lastchar - str + 1), str);
5632    }
5633 
5634    SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5635          varnameslength, vartable, recursiondepth + 1) );
5636 
5637    if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5638    {
5639       SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5640       SCIPexprFreeDeep(blkmem, &arg1);
5641    }
5642    else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5643    {
5644       SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5645       SCIPexprFreeDeep(blkmem, &arg2);
5646    }
5647    else
5648    {
5649       SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5650    }
5651 
5652    SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5653    SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5654    SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5655 
5656    return SCIP_OKAY;
5657 }
5658 
5659 /**@} */
5660 
5661 /**@name Expression methods */
5662 /**@{ */
5663 
5664 /* In debug mode, the following methods are implemented as function calls to ensure
5665  * type validity.
5666  * In optimized mode, the methods are implemented as defines to improve performance.
5667  * However, we want to have them in the library anyways, so we have to undef the defines.
5668  */
5669 
5670 #undef SCIPexprGetOperator
5671 #undef SCIPexprGetNChildren
5672 #undef SCIPexprGetChildren
5673 #undef SCIPexprGetOpIndex
5674 #undef SCIPexprGetOpReal
5675 #undef SCIPexprGetOpData
5676 #undef SCIPexprGetRealPowerExponent
5677 #undef SCIPexprGetIntPowerExponent
5678 #undef SCIPexprGetSignPowerExponent
5679 #undef SCIPexprGetLinearCoefs
5680 #undef SCIPexprGetLinearConstant
5681 #undef SCIPexprGetQuadElements
5682 #undef SCIPexprGetQuadConstant
5683 #undef SCIPexprGetQuadLinearCoefs
5684 #undef SCIPexprGetNQuadElements
5685 #undef SCIPexprGetMonomials
5686 #undef SCIPexprGetNMonomials
5687 #undef SCIPexprGetPolynomialConstant
5688 #undef SCIPexprGetMonomialCoef
5689 #undef SCIPexprGetMonomialNFactors
5690 #undef SCIPexprGetMonomialChildIndices
5691 #undef SCIPexprGetMonomialExponents
5692 #undef SCIPexprGetUserData
5693 #undef SCIPexprHasUserEstimator
5694 #undef SCIPexprGetUserEvalCapability
5695 
5696 /** gives operator of expression */
SCIPexprGetOperator(SCIP_EXPR * expr)5697 SCIP_EXPROP SCIPexprGetOperator(
5698    SCIP_EXPR*            expr                /**< expression */
5699    )
5700 {
5701    assert(expr != NULL);
5702 
5703    return expr->op;
5704 }
5705 
5706 /** gives number of children of an expression */
SCIPexprGetNChildren(SCIP_EXPR * expr)5707 int SCIPexprGetNChildren(
5708    SCIP_EXPR*            expr                /**< expression */
5709    )
5710 {
5711    assert(expr != NULL);
5712 
5713    return expr->nchildren;
5714 }
5715 
5716 /** gives pointer to array with children of an expression */
SCIPexprGetChildren(SCIP_EXPR * expr)5717 SCIP_EXPR** SCIPexprGetChildren(
5718    SCIP_EXPR*            expr                /**< expression */
5719    )
5720 {
5721    assert(expr != NULL);
5722 
5723    return expr->children;
5724 }
5725 
5726 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
SCIPexprGetOpIndex(SCIP_EXPR * expr)5727 int SCIPexprGetOpIndex(
5728    SCIP_EXPR*            expr                /**< expression */
5729    )
5730 {
5731    assert(expr != NULL);
5732    assert(expr->op == SCIP_EXPR_VARIDX || expr->op == SCIP_EXPR_PARAM);
5733 
5734    return expr->data.intval;
5735 }
5736 
5737 /** gives real belonging to a SCIP_EXPR_CONST operand */
SCIPexprGetOpReal(SCIP_EXPR * expr)5738 SCIP_Real SCIPexprGetOpReal(
5739    SCIP_EXPR*            expr                /**< expression */
5740    )
5741 {
5742    assert(expr != NULL);
5743    assert(expr->op == SCIP_EXPR_CONST);
5744 
5745    return expr->data.dbl;
5746 }
5747 
5748 /** gives void* belonging to a complex operand */
SCIPexprGetOpData(SCIP_EXPR * expr)5749 void* SCIPexprGetOpData(
5750    SCIP_EXPR*            expr                /**< expression */
5751    )
5752 {
5753    assert(expr != NULL);
5754    assert(expr->op >= SCIP_EXPR_SUM); /* only complex operands store their data as void* */
5755 
5756    return expr->data.data;
5757 }
5758 
5759 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
SCIPexprGetRealPowerExponent(SCIP_EXPR * expr)5760 SCIP_Real SCIPexprGetRealPowerExponent(
5761    SCIP_EXPR*            expr                /**< expression */
5762    )
5763 {
5764    assert(expr != NULL);
5765    assert(expr->op == SCIP_EXPR_REALPOWER);
5766 
5767    return expr->data.dbl;
5768 }
5769 
5770 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
SCIPexprGetIntPowerExponent(SCIP_EXPR * expr)5771 int SCIPexprGetIntPowerExponent(
5772    SCIP_EXPR*            expr                /**< expression */
5773    )
5774 {
5775    assert(expr != NULL);
5776    assert(expr->op == SCIP_EXPR_INTPOWER);
5777 
5778    return expr->data.intval;
5779 }
5780 
5781 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
SCIPexprGetSignPowerExponent(SCIP_EXPR * expr)5782 SCIP_Real SCIPexprGetSignPowerExponent(
5783    SCIP_EXPR*            expr                /**< expression */
5784    )
5785 {
5786    assert(expr != NULL);
5787    assert(expr->op == SCIP_EXPR_SIGNPOWER);
5788 
5789    return expr->data.dbl;
5790 }
5791 
5792 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
SCIPexprGetLinearCoefs(SCIP_EXPR * expr)5793 SCIP_Real* SCIPexprGetLinearCoefs(
5794    SCIP_EXPR*            expr                /**< expression */
5795    )
5796 {
5797    assert(expr != NULL);
5798    assert(expr->op == SCIP_EXPR_LINEAR);
5799    assert(expr->data.data != NULL);
5800 
5801    /* the coefficients are stored in the first nchildren elements of the array stored as expression data */
5802    return (SCIP_Real*)expr->data.data;
5803 }
5804 
5805 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
SCIPexprGetLinearConstant(SCIP_EXPR * expr)5806 SCIP_Real SCIPexprGetLinearConstant(
5807    SCIP_EXPR*            expr                /**< expression */
5808    )
5809 {
5810    assert(expr != NULL);
5811    assert(expr->op == SCIP_EXPR_LINEAR);
5812    assert(expr->data.data != NULL);
5813 
5814    /* the constant is stored in the nchildren's element of the array stored as expression data */
5815    return ((SCIP_Real*)expr->data.data)[expr->nchildren];
5816 }
5817 
5818 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
SCIPexprGetQuadElements(SCIP_EXPR * expr)5819 SCIP_QUADELEM* SCIPexprGetQuadElements(
5820    SCIP_EXPR*            expr                /**< quadratic expression */
5821    )
5822 {
5823    assert(expr != NULL);
5824    assert(expr->op == SCIP_EXPR_QUADRATIC);
5825    assert(expr->data.data != NULL);
5826 
5827    return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->quadelems;
5828 }
5829 
5830 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
SCIPexprGetQuadConstant(SCIP_EXPR * expr)5831 SCIP_Real SCIPexprGetQuadConstant(
5832    SCIP_EXPR*            expr                /**< quadratic expression */
5833    )
5834 {
5835    assert(expr != NULL);
5836    assert(expr->op == SCIP_EXPR_QUADRATIC);
5837    assert(expr->data.data != NULL);
5838 
5839    return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->constant;
5840 }
5841 
5842 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression
5843  * can be NULL if all coefficients are 0.0 */
SCIPexprGetQuadLinearCoefs(SCIP_EXPR * expr)5844 SCIP_Real* SCIPexprGetQuadLinearCoefs(
5845    SCIP_EXPR*            expr                /**< quadratic expression */
5846    )
5847 {
5848    assert(expr != NULL);
5849    assert(expr->op == SCIP_EXPR_QUADRATIC);
5850    assert(expr->data.data != NULL);
5851 
5852    return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->lincoefs;
5853 }
5854 
5855 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
SCIPexprGetNQuadElements(SCIP_EXPR * expr)5856 int SCIPexprGetNQuadElements(
5857    SCIP_EXPR*            expr                /**< quadratic expression */
5858    )
5859 {
5860    assert(expr != NULL);
5861    assert(expr->op == SCIP_EXPR_QUADRATIC);
5862    assert(expr->data.data != NULL);
5863 
5864    return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->nquadelems;
5865 }
5866 
5867 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
SCIPexprGetMonomials(SCIP_EXPR * expr)5868 SCIP_EXPRDATA_MONOMIAL** SCIPexprGetMonomials(
5869    SCIP_EXPR*            expr                /**< expression */
5870    )
5871 {
5872    assert(expr != NULL);
5873    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5874    assert(expr->data.data != NULL);
5875 
5876    return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->monomials;
5877 }
5878 
5879 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
SCIPexprGetNMonomials(SCIP_EXPR * expr)5880 int SCIPexprGetNMonomials(
5881    SCIP_EXPR*            expr                /**< expression */
5882    )
5883 {
5884    assert(expr != NULL);
5885    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5886    assert(expr->data.data != NULL);
5887 
5888    return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->nmonomials;
5889 }
5890 
5891 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
SCIPexprGetPolynomialConstant(SCIP_EXPR * expr)5892 SCIP_Real SCIPexprGetPolynomialConstant(
5893    SCIP_EXPR*            expr                /**< expression */
5894    )
5895 {
5896    assert(expr != NULL);
5897    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5898    assert(expr->data.data != NULL);
5899 
5900    return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant;
5901 }
5902 
5903 /** gets coefficient of a monomial */
SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL * monomial)5904 SCIP_Real SCIPexprGetMonomialCoef(
5905    SCIP_EXPRDATA_MONOMIAL* monomial          /**< monomial */
5906    )
5907 {
5908    assert(monomial != NULL);
5909 
5910    return monomial->coef;
5911 }
5912 
5913 /** gets number of factors of a monomial */
SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL * monomial)5914 int SCIPexprGetMonomialNFactors(
5915    SCIP_EXPRDATA_MONOMIAL* monomial          /**< monomial */
5916    )
5917 {
5918    assert(monomial != NULL);
5919 
5920    return monomial->nfactors;
5921 }
5922 
5923 /** gets indices of children corresponding to factors of a monomial */
SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL * monomial)5924 int* SCIPexprGetMonomialChildIndices(
5925    SCIP_EXPRDATA_MONOMIAL* monomial          /**< monomial */
5926    )
5927 {
5928    assert(monomial != NULL);
5929 
5930    return monomial->childidxs;
5931 }
5932 
5933 /** gets exponents in factors of a monomial */
SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL * monomial)5934 SCIP_Real* SCIPexprGetMonomialExponents(
5935    SCIP_EXPRDATA_MONOMIAL* monomial          /**< monomial */
5936    )
5937 {
5938    assert(monomial != NULL);
5939 
5940    return monomial->exponents;
5941 }
5942 
5943 /** gets user data of a user expression */
SCIPexprGetUserData(SCIP_EXPR * expr)5944 SCIP_USEREXPRDATA* SCIPexprGetUserData(
5945    SCIP_EXPR*              expr
5946    )
5947 {
5948    assert(expr != NULL);
5949    assert(expr->data.data != NULL);
5950 
5951    return ((SCIP_EXPRDATA_USER*)expr->data.data)->userdata;
5952 }
5953 
5954 /** indicates whether a user expression has the estimator callback defined */
SCIPexprHasUserEstimator(SCIP_EXPR * expr)5955 SCIP_Bool SCIPexprHasUserEstimator(
5956    SCIP_EXPR*              expr
5957    )
5958 {
5959    assert(expr != NULL);
5960    assert(expr->data.data != NULL);
5961 
5962    return ((SCIP_EXPRDATA_USER*)expr->data.data)->estimate != NULL;
5963 }
5964 
5965 /** gives the evaluation capability of a user expression */
SCIPexprGetUserEvalCapability(SCIP_EXPR * expr)5966 SCIP_EXPRINTCAPABILITY SCIPexprGetUserEvalCapability(
5967    SCIP_EXPR*              expr
5968    )
5969 {
5970    assert(expr != NULL);
5971    assert(expr->data.data != NULL);
5972 
5973    return ((SCIP_EXPRDATA_USER*)expr->data.data)->evalcapability;
5974 }
5975 
5976 /** creates a simple expression */
SCIPexprCreate(BMS_BLKMEM * blkmem,SCIP_EXPR ** expr,SCIP_EXPROP op,...)5977 SCIP_RETCODE SCIPexprCreate(
5978    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
5979    SCIP_EXPR**           expr,               /**< pointer to buffer for expression address */
5980    SCIP_EXPROP           op,                 /**< operand of expression */
5981    ...                                       /**< arguments of operand */
5982    )
5983 {
5984    va_list         ap;
5985    SCIP_EXPR**     children;
5986    SCIP_EXPROPDATA opdata;
5987 
5988    assert(blkmem != NULL);
5989    assert(expr   != NULL);
5990 
5991    switch( op )
5992    {
5993    case SCIP_EXPR_VARIDX:
5994    case SCIP_EXPR_PARAM:
5995    {
5996       va_start( ap, op );  /*lint !e838*/
5997       opdata.intval = va_arg( ap, int );  /*lint !e416 !e826*/
5998       va_end( ap );  /*lint !e826*/
5999 
6000       assert( opdata.intval >= 0 );
6001 
6002       SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
6003       break;
6004    }
6005 
6006    case SCIP_EXPR_CONST:
6007    {
6008       va_start(ap, op );  /*lint !e838*/
6009       opdata.dbl = va_arg( ap, SCIP_Real );  /*lint !e416 !e826*/
6010       va_end( ap );  /*lint !e826*/
6011 
6012       SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
6013       break;
6014    }
6015 
6016    /* operands with two children */
6017    case SCIP_EXPR_PLUS     :
6018    case SCIP_EXPR_MINUS    :
6019    case SCIP_EXPR_MUL      :
6020    case SCIP_EXPR_DIV      :
6021    case SCIP_EXPR_MIN      :
6022    case SCIP_EXPR_MAX      :
6023    {
6024       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) );  /*lint !e506*/
6025 
6026       va_start(ap, op );  /*lint !e838*/
6027       children[0] = va_arg( ap, SCIP_EXPR* );  /*lint !e416 !e826*/
6028       children[1] = va_arg( ap, SCIP_EXPR* );  /*lint !e416 !e826*/
6029       assert(children[0] != NULL);
6030       assert(children[1] != NULL);
6031       va_end( ap );  /*lint !e826*/
6032       opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6033 
6034       SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
6035       break;
6036    }
6037 
6038    /* operands with one child */
6039    case SCIP_EXPR_SQUARE:
6040    case SCIP_EXPR_SQRT  :
6041    case SCIP_EXPR_EXP   :
6042    case SCIP_EXPR_LOG   :
6043    case SCIP_EXPR_SIN   :
6044    case SCIP_EXPR_COS   :
6045    case SCIP_EXPR_TAN   :
6046       /* case SCIP_EXPR_ERF   : */
6047       /* case SCIP_EXPR_ERFI  : */
6048    case SCIP_EXPR_ABS   :
6049    case SCIP_EXPR_SIGN  :
6050    {
6051       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) );  /*lint !e506*/
6052 
6053       va_start(ap, op );  /*lint !e838*/
6054       children[0] = va_arg( ap, SCIP_EXPR* );  /*lint !e416 !e826*/
6055       assert(children[0] != NULL);
6056       va_end( ap );  /*lint !e826*/
6057       opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6058 
6059       SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6060       break;
6061    }
6062 
6063    case SCIP_EXPR_REALPOWER:
6064    case SCIP_EXPR_SIGNPOWER:
6065    {
6066       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) );  /*lint !e506*/
6067 
6068       va_start(ap, op );  /*lint !e838*/
6069       children[0] = va_arg( ap, SCIP_EXPR* );  /*lint !e416 !e826*/
6070       assert(children[0] != NULL);
6071       opdata.dbl = va_arg( ap, SCIP_Real);  /*lint !e416 !e826*/
6072       va_end( ap );  /*lint !e826*/
6073 
6074       SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6075       break;
6076    }
6077 
6078    case SCIP_EXPR_INTPOWER:
6079    {
6080       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) );  /*lint !e506*/
6081 
6082       va_start(ap, op );  /*lint !e838*/
6083       children[0] = va_arg( ap, SCIP_EXPR* );  /*lint !e416 !e826*/
6084       assert(children[0] != NULL);
6085       opdata.intval = va_arg( ap, int);  /*lint !e416 !e826*/
6086       va_end( ap );  /*lint !e826*/
6087 
6088       SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6089       break;
6090    }
6091 
6092    /* complex operands */
6093    case SCIP_EXPR_SUM    :
6094    case SCIP_EXPR_PRODUCT:
6095    {
6096       int nchildren;
6097       SCIP_EXPR** childrenarg;
6098 
6099       opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6100 
6101       va_start(ap, op );  /*lint !e838*/
6102       /* first argument should be number of children */
6103       nchildren = va_arg( ap, int );  /*lint !e416 !e826*/
6104       assert(nchildren >= 0);
6105 
6106       /* for a sum or product of 0 terms we can finish here */
6107       if( nchildren == 0 )
6108       {
6109          SCIP_RETCODE retcode;
6110          retcode = exprCreate( blkmem, expr, op, 0, NULL, opdata);
6111          va_end( ap );  /*lint !e826*/
6112          SCIP_CALL( retcode );
6113          break;
6114       }
6115 
6116       /* next argument should be array of children expressions */
6117       childrenarg = va_arg( ap, SCIP_EXPR** );  /*lint !e416 !e826*/
6118       assert(childrenarg != NULL);
6119       va_end( ap );  /*lint !e826*/
6120 
6121       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
6122 
6123       SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
6124       break;
6125    }
6126 
6127    case SCIP_EXPR_LINEAR :
6128    case SCIP_EXPR_QUADRATIC:
6129    case SCIP_EXPR_POLYNOMIAL:
6130    case SCIP_EXPR_USER:
6131    {
6132       SCIPerrorMessage("cannot create complex expression linear, quadratic, polynomial, or user with SCIPexprCreate\n");
6133       return SCIP_INVALIDDATA;
6134    }
6135 
6136    case SCIP_EXPR_LAST:
6137       SCIPABORT();
6138       break;
6139    }
6140 
6141    return SCIP_OKAY;
6142 }
6143 
6144 /** copies an expression including its children */
SCIPexprCopyDeep(BMS_BLKMEM * blkmem,SCIP_EXPR ** targetexpr,SCIP_EXPR * sourceexpr)6145 SCIP_RETCODE SCIPexprCopyDeep(
6146    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
6147    SCIP_EXPR**           targetexpr,         /**< buffer to store pointer to copied expression */
6148    SCIP_EXPR*            sourceexpr          /**< expression to copy */
6149    )
6150 {
6151    assert(blkmem     != NULL);
6152    assert(targetexpr != NULL);
6153    assert(sourceexpr != NULL);
6154 
6155    SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
6156 
6157    if( sourceexpr->nchildren )
6158    {
6159       int i;
6160 
6161       /* alloc memory for children expressions */
6162       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
6163 
6164       /* copy children expressions */
6165       for( i = 0; i < sourceexpr->nchildren; ++i )
6166       {
6167          SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
6168       }
6169    }
6170    else
6171    {
6172       assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
6173    }
6174 
6175    /* call operands data copy callback for complex operands
6176     * for simple operands BMSduplicate above should have done the job
6177     */
6178    if( exprOpTable[sourceexpr->op].copydata != NULL )
6179    {
6180       SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
6181    }
6182 
6183    return SCIP_OKAY;
6184 }
6185 
6186 /** frees an expression including its children */
SCIPexprFreeDeep(BMS_BLKMEM * blkmem,SCIP_EXPR ** expr)6187 void SCIPexprFreeDeep(
6188    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
6189    SCIP_EXPR**           expr                /**< pointer to expression to free */
6190    )
6191 {
6192    assert(blkmem != NULL);
6193    assert(expr   != NULL);
6194    assert(*expr  != NULL);
6195 
6196    /* call operands data free callback, if given */
6197    if( exprOpTable[(*expr)->op].freedata != NULL )
6198    {
6199       exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6200    }
6201 
6202    if( (*expr)->nchildren )
6203    {
6204       int i;
6205 
6206       assert( (*expr)->children != NULL );
6207 
6208       for( i = 0; i < (*expr)->nchildren; ++i )
6209       {
6210          SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
6211          assert((*expr)->children[i] == NULL);
6212       }
6213 
6214       BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
6215    }
6216    else
6217    {
6218       assert( (*expr)->children == NULL );
6219    }
6220 
6221    BMSfreeBlockMemory(blkmem, expr);
6222 }
6223 
6224 /** frees an expression but not its children */
SCIPexprFreeShallow(BMS_BLKMEM * blkmem,SCIP_EXPR ** expr)6225 void SCIPexprFreeShallow(
6226    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
6227    SCIP_EXPR**           expr                /**< pointer to expression to free */
6228    )
6229 {
6230    assert(blkmem != NULL);
6231    assert(expr   != NULL);
6232    assert(*expr  != NULL);
6233 
6234    /* call operands data free callback, if given */
6235    if( exprOpTable[(*expr)->op].freedata != NULL )
6236    {
6237       exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6238    }
6239 
6240    BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
6241 
6242    BMSfreeBlockMemory(blkmem, expr);
6243 }
6244 
6245 /** creates an expression from the addition of two given expression, with coefficients, and a constant
6246  *
6247  *  The given expressions may be modified or freed, otherwise it will be used a child expression.
6248  *  Favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6249  */
SCIPexprAdd(BMS_BLKMEM * blkmem,SCIP_EXPR ** expr,SCIP_Real coef1,SCIP_EXPR * term1,SCIP_Real coef2,SCIP_EXPR * term2,SCIP_Real constant)6250 SCIP_RETCODE SCIPexprAdd(
6251    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
6252    SCIP_EXPR**           expr,               /**< pointer to store pointer to created expression */
6253    SCIP_Real             coef1,              /**< coefficient of first term */
6254    SCIP_EXPR*            term1,              /**< expression of first term, or NULL */
6255    SCIP_Real             coef2,              /**< coefficient of second term */
6256    SCIP_EXPR*            term2,              /**< expression of second term, or NULL */
6257    SCIP_Real             constant            /**< constant term to add */
6258    )
6259 {
6260    assert(blkmem != NULL);
6261    assert(expr != NULL);
6262 
6263    /* @todo could do something special with quadratic and polynomial expressions */
6264 
6265    if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
6266    {
6267       constant += coef1 * SCIPexprGetOpReal(term1);
6268       SCIPexprFreeDeep(blkmem, &term1);
6269    }
6270 
6271    if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
6272    {
6273       constant += coef2 * SCIPexprGetOpReal(term2);
6274       SCIPexprFreeDeep(blkmem, &term2);
6275    }
6276 
6277    if( term1 == NULL && term2 == NULL )
6278    {
6279       SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
6280       return SCIP_OKAY;
6281    }
6282 
6283    if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
6284    {
6285       /* multiply coefficients and constant of linear expression term1 by coef1 */
6286       SCIP_Real* data;
6287       int i;
6288 
6289       data = (SCIP_Real*)term1->data.data;
6290       assert(data != NULL);
6291 
6292       /* loop one more index to multiply also constant of linear expression */
6293       for( i = 0; i <= term1->nchildren; ++i )
6294          data[i] *= coef1;
6295 
6296       coef1 = 1.0;
6297    }
6298 
6299    if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
6300    {
6301       /* multiply coefficients and constant of linear expression term2 by coef2 */
6302       SCIP_Real* data;
6303       int i;
6304 
6305       data = (SCIP_Real*)term2->data.data;
6306       assert(data != NULL);
6307 
6308       /* loop one more index to multiply also constant of linear expression */
6309       for( i = 0; i <= term2->nchildren; ++i )
6310          data[i] *= coef2;
6311 
6312       coef2 = 1.0;
6313    }
6314 
6315    if( term1 == NULL || term2 == NULL )
6316    {
6317       if( term1 == NULL )
6318       {
6319          term1 = term2;
6320          coef1 = coef2;
6321       }
6322       if( constant != 0.0 || coef1 != 1.0 )
6323       {
6324          if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6325          {
6326             assert(coef1 == 1.0);
6327 
6328             /* add constant to existing linear expression */
6329             SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
6330             *expr = term1;
6331          }
6332          else
6333          {
6334             /* create new linear expression for coef1 * term1 + constant */
6335             SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
6336          }
6337       }
6338       else
6339       {
6340          assert(constant == 0.0);
6341          assert(coef1 == 1.0);
6342          *expr = term1;
6343       }
6344 
6345       return SCIP_OKAY;
6346    }
6347 
6348    if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
6349    {
6350       /* add 2nd linear expression to first one */
6351       assert(coef1 == 1.0);
6352       assert(coef2 == 1.0);
6353 
6354       SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, SCIPexprGetNChildren(term2), SCIPexprGetLinearCoefs(term2), SCIPexprGetChildren(term2), SCIPexprGetLinearConstant(term2) + constant) );
6355       SCIPexprFreeShallow(blkmem, &term2);
6356 
6357       *expr = term1;
6358 
6359       return SCIP_OKAY;
6360    }
6361 
6362    if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
6363    {
6364       /* if only term2 is linear, then swap */
6365       SCIP_EXPR* tmp;
6366 
6367       tmp = term2;
6368       assert(coef2 == 1.0);
6369 
6370       term2 = term1;
6371       coef2 = coef1;
6372       term1 = tmp;
6373       coef1 = 1.0;
6374    }
6375 
6376    if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6377    {
6378       /* add coef2*term2 as extra child to linear expression term1 */
6379       assert(coef1 == 1.0);
6380 
6381       SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6382       *expr = term1;
6383 
6384       return SCIP_OKAY;
6385    }
6386 
6387    /* both terms are not linear, then create new linear term for sum */
6388    {
6389       SCIP_Real coefs[2];
6390       SCIP_EXPR* children[2];
6391 
6392       coefs[0] = coef1;
6393       coefs[1] = coef2;
6394       children[0] = term1;
6395       children[1] = term2;
6396 
6397       SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6398    }
6399 
6400    return SCIP_OKAY;
6401 }
6402 
6403 /** creates an expression from the multiplication of an expression with a constant
6404  *
6405  *  The given expressions may be modified or freed, otherwise it will be used a child expression.
6406  *  Favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6407  */
SCIPexprMulConstant(BMS_BLKMEM * blkmem,SCIP_EXPR ** expr,SCIP_EXPR * term,SCIP_Real factor)6408 SCIP_RETCODE SCIPexprMulConstant(
6409    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
6410    SCIP_EXPR**           expr,               /**< buffer to store pointer to created expression */
6411    SCIP_EXPR*            term,               /**< term to multiply by factor */
6412    SCIP_Real             factor              /**< factor */
6413    )
6414 {
6415    assert(blkmem != NULL);
6416    assert(expr != NULL);
6417    assert(term != NULL);
6418 
6419    if( factor == 0.0 )
6420    {
6421       SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6422 
6423       SCIPexprFreeDeep(blkmem, &term);
6424 
6425       return SCIP_OKAY;
6426    }
6427    if( factor == 1.0 )
6428    {
6429       *expr = term;
6430       return SCIP_OKAY;
6431    }
6432 
6433    switch( SCIPexprGetOperator(term) )
6434    {
6435       case SCIP_EXPR_CONST :
6436       {
6437          SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6438          SCIPexprFreeDeep(blkmem, &term);
6439          break;
6440       }
6441 
6442       case SCIP_EXPR_LINEAR :
6443       {
6444          SCIP_Real* data;
6445          int i;
6446 
6447          data = (SCIP_Real*)term->data.data;
6448          assert(data != NULL);
6449 
6450          /* loop one more index to multiply also constant of linear expression */
6451          for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6452             data[i] *= factor;
6453 
6454          *expr = term;
6455          break;
6456       }
6457 
6458       case SCIP_EXPR_QUADRATIC :
6459       {
6460          SCIP_EXPRDATA_QUADRATIC* data;
6461          int i;
6462 
6463          data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6464 
6465          data->constant *= factor;
6466 
6467          if( data->lincoefs != NULL )
6468             for( i = 0; i < term->nchildren; ++i )
6469                data->lincoefs[i] *= factor;
6470 
6471          for( i = 0; i < data->nquadelems; ++i )
6472             data->quadelems[i].coef *= factor;
6473 
6474          *expr = term;
6475          break;
6476       }
6477 
6478       case SCIP_EXPR_POLYNOMIAL :
6479       {
6480          SCIP_EXPRDATA_POLYNOMIAL* data;
6481          int i;
6482 
6483          data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6484 
6485          data->constant *= factor;
6486 
6487          for( i = 0; i < data->nmonomials; ++i )
6488             data->monomials[i]->coef *= factor;
6489 
6490          *expr = term;
6491          break;
6492       }
6493 
6494       default:
6495       {
6496          SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6497          break;
6498       }
6499 
6500    } /*lint !e788 */
6501 
6502    return SCIP_OKAY;
6503 }
6504 
6505 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
SCIPexprCreateLinear(BMS_BLKMEM * blkmem,SCIP_EXPR ** expr,int nchildren,SCIP_EXPR ** children,SCIP_Real * coefs,SCIP_Real constant)6506 SCIP_RETCODE SCIPexprCreateLinear(
6507    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
6508    SCIP_EXPR**           expr,               /**< pointer to buffer for expression address */
6509    int                   nchildren,          /**< number of children */
6510    SCIP_EXPR**           children,           /**< children of expression */
6511    SCIP_Real*            coefs,              /**< coefficients of children */
6512    SCIP_Real             constant            /**< constant part */
6513    )
6514 {
6515    SCIP_EXPROPDATA opdata;
6516    SCIP_EXPR**     childrencopy;
6517    SCIP_Real*      data;
6518 
6519    assert(nchildren >= 0);
6520    assert(children != NULL || nchildren == 0);
6521    assert(coefs    != NULL || nchildren == 0);
6522 
6523    if( nchildren > 0 )
6524    {
6525       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6526    }
6527    else
6528       childrencopy = NULL;
6529 
6530    /* we store the coefficients and the constant in a single array and make this our operand data */
6531    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6532    BMScopyMemoryArray(data, coefs, nchildren);  /*lint !e644*/
6533    data[nchildren] = constant;
6534 
6535    opdata.data = (void*)data;
6536 
6537    SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6538 
6539    return SCIP_OKAY;
6540 }
6541 
6542 /** adds new terms to a linear expression */
SCIPexprAddToLinear(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,int nchildren,SCIP_Real * coefs,SCIP_EXPR ** children,SCIP_Real constant)6543 SCIP_RETCODE SCIPexprAddToLinear(
6544    BMS_BLKMEM*           blkmem,             /**< block memory */
6545    SCIP_EXPR*            expr,               /**< linear expression */
6546    int                   nchildren,          /**< number of children to add */
6547    SCIP_Real*            coefs,              /**< coefficients of additional children */
6548    SCIP_EXPR**           children,           /**< additional children expressions */
6549    SCIP_Real             constant            /**< constant to add */
6550    )
6551 {
6552    SCIP_Real* data;
6553 
6554    assert(blkmem != NULL);
6555    assert(expr != NULL);
6556    assert(expr->op == SCIP_EXPR_LINEAR);
6557    assert(nchildren >= 0);
6558    assert(coefs != NULL || nchildren == 0);
6559    assert(children != NULL || nchildren == 0);
6560 
6561    data = (SCIP_Real*)expr->data.data;
6562    assert(data != NULL);
6563 
6564    /* handle simple case of adding a constant */
6565    if( nchildren == 0 )
6566    {
6567       data[expr->nchildren] += constant;
6568 
6569       return SCIP_OKAY;
6570    }
6571 
6572    /* add new children to expr's children array */
6573    SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6574    BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren);  /*lint !e866*/
6575 
6576    /* add constant and new coefs to expr's data array */
6577    SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6578    data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6579    BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren);  /*lint !e866*/
6580    expr->data.data = (void*)data;
6581 
6582    expr->nchildren += nchildren;
6583 
6584    return SCIP_OKAY;
6585 }
6586 
6587 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
SCIPexprCreateQuadratic(BMS_BLKMEM * blkmem,SCIP_EXPR ** expr,int nchildren,SCIP_EXPR ** children,SCIP_Real constant,SCIP_Real * lincoefs,int nquadelems,SCIP_QUADELEM * quadelems)6588 SCIP_RETCODE SCIPexprCreateQuadratic(
6589    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
6590    SCIP_EXPR**           expr,               /**< pointer to buffer for expression address */
6591    int                   nchildren,          /**< number of children */
6592    SCIP_EXPR**           children,           /**< children of expression */
6593    SCIP_Real             constant,           /**< constant */
6594    SCIP_Real*            lincoefs,           /**< linear coefficients of children, or NULL if all 0.0 */
6595    int                   nquadelems,         /**< number of quadratic elements */
6596    SCIP_QUADELEM*        quadelems           /**< quadratic elements specifying coefficients and child indices */
6597    )
6598 {
6599    SCIP_EXPROPDATA opdata;
6600    SCIP_EXPR**     childrencopy;
6601    SCIP_EXPRDATA_QUADRATIC* data;
6602 
6603    assert(nchildren >= 0);
6604    assert(children  != NULL || nchildren == 0);
6605    assert(quadelems != NULL || nquadelems == 0);
6606 
6607    if( nchildren > 0 )
6608    {
6609       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6610    }
6611    else
6612       childrencopy = NULL;
6613 
6614    SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6615 
6616    opdata.data = (void*)data;
6617 
6618    SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6619 
6620    return SCIP_OKAY;
6621 }
6622 
6623 /** ensures that quadratic elements of a quadratic expression are sorted */
SCIPexprSortQuadElems(SCIP_EXPR * expr)6624 void SCIPexprSortQuadElems(
6625    SCIP_EXPR*            expr                /**< quadratic expression */
6626    )
6627 {
6628    assert(expr != NULL);
6629    assert(expr->op == SCIP_EXPR_QUADRATIC);
6630    assert(expr->data.data != NULL);
6631 
6632    quadraticdataSort((SCIP_EXPRDATA_QUADRATIC*)expr->data.data);
6633 }
6634 
6635 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
SCIPexprCreatePolynomial(BMS_BLKMEM * blkmem,SCIP_EXPR ** expr,int nchildren,SCIP_EXPR ** children,int nmonomials,SCIP_EXPRDATA_MONOMIAL ** monomials,SCIP_Real constant,SCIP_Bool copymonomials)6636 SCIP_RETCODE SCIPexprCreatePolynomial(
6637    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
6638    SCIP_EXPR**           expr,               /**< pointer to buffer for expression address */
6639    int                   nchildren,          /**< number of children */
6640    SCIP_EXPR**           children,           /**< children of expression */
6641    int                   nmonomials,         /**< number of monomials */
6642    SCIP_EXPRDATA_MONOMIAL** monomials,       /**< monomials */
6643    SCIP_Real             constant,           /**< constant part */
6644    SCIP_Bool             copymonomials       /**< should monomials by copied or ownership be assumed? */
6645    )
6646 {
6647    SCIP_EXPROPDATA opdata;
6648    SCIP_EXPR**     childrencopy;
6649    SCIP_EXPRDATA_POLYNOMIAL* data;
6650 
6651    assert(nchildren >= 0);
6652    assert(children != NULL || nchildren == 0);
6653    assert(monomials   != NULL || nmonomials   == 0);
6654 
6655    if( nchildren > 0 )
6656    {
6657       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6658    }
6659    else
6660       childrencopy = NULL;
6661 
6662    SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6663    opdata.data = (void*)data;
6664 
6665    SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6666 
6667    return SCIP_OKAY;
6668 }
6669 
6670 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
SCIPexprAddMonomials(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,int nmonomials,SCIP_EXPRDATA_MONOMIAL ** monomials,SCIP_Bool copymonomials)6671 SCIP_RETCODE SCIPexprAddMonomials(
6672    BMS_BLKMEM*           blkmem,             /**< block memory of expression */
6673    SCIP_EXPR*            expr,               /**< expression */
6674    int                   nmonomials,         /**< number of monomials to add */
6675    SCIP_EXPRDATA_MONOMIAL** monomials,       /**< the monomials to add */
6676    SCIP_Bool             copymonomials       /**< should monomials by copied or ownership be assumed? */
6677    )
6678 {
6679    assert(blkmem != NULL);
6680    assert(expr != NULL);
6681    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6682    assert(monomials != NULL || nmonomials == 0);
6683 
6684    if( nmonomials == 0 )
6685       return SCIP_OKAY;
6686 
6687    SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6688 
6689    return SCIP_OKAY;
6690 }
6691 
6692 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
SCIPexprChgPolynomialConstant(SCIP_EXPR * expr,SCIP_Real constant)6693 void SCIPexprChgPolynomialConstant(
6694    SCIP_EXPR*            expr,               /**< expression */
6695    SCIP_Real             constant            /**< new value for constant */
6696    )
6697 {
6698    assert(expr != NULL);
6699    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6700    assert(expr->data.data != NULL);
6701 
6702    ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6703 }
6704 
6705 /** multiplies each summand of a polynomial by a given constant */
SCIPexprMultiplyPolynomialByConstant(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,SCIP_Real factor)6706 void SCIPexprMultiplyPolynomialByConstant(
6707    BMS_BLKMEM*           blkmem,             /**< block memory */
6708    SCIP_EXPR*            expr,               /**< polynomial expression */
6709    SCIP_Real             factor              /**< constant factor */
6710    )
6711 {
6712    assert(expr != NULL);
6713    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6714    assert(expr->data.data != NULL);
6715 
6716    polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6717 }
6718 
6719 /** multiplies each summand of a polynomial by a given monomial */
SCIPexprMultiplyPolynomialByMonomial(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,SCIP_EXPRDATA_MONOMIAL * factor,int * childmap)6720 SCIP_RETCODE SCIPexprMultiplyPolynomialByMonomial(
6721    BMS_BLKMEM*           blkmem,             /**< block memory */
6722    SCIP_EXPR*            expr,               /**< polynomial expression */
6723    SCIP_EXPRDATA_MONOMIAL*  factor,          /**< monomial factor */
6724    int*                  childmap            /**< map children in factor to children in expr, or NULL for 1:1 */
6725    )
6726 {
6727    assert(blkmem != NULL);
6728    assert(factor != NULL);
6729    assert(expr != NULL);
6730    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6731    assert(expr->data.data != NULL);
6732 
6733    SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6734 
6735    return SCIP_OKAY;
6736 }
6737 
6738 /** multiplies this polynomial by a polynomial
6739  *
6740  *  Factor needs to be different from expr.
6741  *  Children of factor need to be children of expr already, w.r.t. an optional mapping of child indices.
6742  */
SCIPexprMultiplyPolynomialByPolynomial(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,SCIP_EXPR * factor,int * childmap)6743 SCIP_RETCODE SCIPexprMultiplyPolynomialByPolynomial(
6744    BMS_BLKMEM*           blkmem,             /**< block memory */
6745    SCIP_EXPR*            expr,               /**< polynomial expression */
6746    SCIP_EXPR*            factor,             /**< polynomial factor */
6747    int*                  childmap            /**< map children in factor to children in expr, or NULL for 1:1 */
6748    )
6749 {
6750    assert(blkmem != NULL);
6751    assert(expr != NULL);
6752    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6753    assert(expr->data.data != NULL);
6754    assert(factor != NULL);
6755    assert(factor->op == SCIP_EXPR_POLYNOMIAL);
6756    assert(factor->data.data != NULL);
6757    assert(expr != factor);
6758 
6759 #ifndef NDEBUG
6760    if( childmap == NULL )
6761    {
6762       int i;
6763       assert(factor->nchildren == expr->nchildren);
6764       for( i = 0; i < factor->nchildren; ++i )
6765          assert(SCIPexprAreEqual(expr->children[i], factor->children[i], 0.0));
6766    }
6767    else
6768    {
6769       int i;
6770       for( i = 0; i < factor->nchildren; ++i )
6771       {
6772          assert(childmap[i] >= 0);
6773          assert(childmap[i] < expr->nchildren);
6774          assert(SCIPexprAreEqual(expr->children[childmap[i]], factor->children[i], 0.0));
6775       }
6776    }
6777 #endif
6778 
6779    SCIP_CALL( polynomialdataMultiplyByPolynomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, (SCIP_EXPRDATA_POLYNOMIAL*)factor->data.data, childmap) );
6780 
6781    return SCIP_OKAY;
6782 }
6783 
6784 /** takes a power of the polynomial
6785  *
6786  *  Exponent need to be an integer.
6787  *  Polynomial needs to be a monomial, if exponent is negative.
6788  */
SCIPexprPolynomialPower(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,int exponent)6789 SCIP_RETCODE SCIPexprPolynomialPower(
6790    BMS_BLKMEM*           blkmem,             /**< block memory */
6791    SCIP_EXPR*            expr,               /**< polynomial expression */
6792    int                   exponent            /**< exponent of power operation */
6793    )
6794 {
6795    assert(blkmem != NULL);
6796    assert(expr != NULL);
6797    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6798    assert(expr->data.data != NULL);
6799 
6800    SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6801 
6802    return SCIP_OKAY;
6803 }
6804 
6805 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6806  *
6807  *  Eliminates monomials with coefficient between -eps and eps.
6808  */
SCIPexprMergeMonomials(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,SCIP_Real eps,SCIP_Bool mergefactors)6809 void SCIPexprMergeMonomials(
6810    BMS_BLKMEM*           blkmem,             /**< block memory */
6811    SCIP_EXPR*            expr,               /**< polynomial expression */
6812    SCIP_Real             eps,                /**< threshold under which numbers are treat as zero */
6813    SCIP_Bool             mergefactors        /**< whether to merge factors in monomials too */
6814    )
6815 {
6816    assert(expr != NULL);
6817    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6818    assert(expr->data.data != NULL);
6819 
6820    polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6821 }
6822 
6823 /** checks if two monomials are equal */
SCIPexprAreMonomialsEqual(SCIP_EXPRDATA_MONOMIAL * monomial1,SCIP_EXPRDATA_MONOMIAL * monomial2,SCIP_Real eps)6824 SCIP_Bool SCIPexprAreMonomialsEqual(
6825    SCIP_EXPRDATA_MONOMIAL* monomial1,        /**< first monomial */
6826    SCIP_EXPRDATA_MONOMIAL* monomial2,        /**< second monomial */
6827    SCIP_Real             eps                 /**< threshold under which numbers are treated as 0.0 */
6828    )
6829 {
6830    int i;
6831 
6832    assert(monomial1 != NULL);
6833    assert(monomial2 != NULL);
6834 
6835    if( monomial1->nfactors != monomial2->nfactors )
6836       return FALSE;
6837 
6838    if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6839       return FALSE;
6840 
6841    SCIPexprSortMonomialFactors(monomial1);
6842    SCIPexprSortMonomialFactors(monomial2);
6843 
6844    for( i = 0; i < monomial1->nfactors; ++i )
6845    {
6846       if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6847          !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6848          return FALSE;
6849    }
6850 
6851    return TRUE;
6852 }
6853 
6854 /** changes coefficient of monomial */
SCIPexprChgMonomialCoef(SCIP_EXPRDATA_MONOMIAL * monomial,SCIP_Real newcoef)6855 void SCIPexprChgMonomialCoef(
6856    SCIP_EXPRDATA_MONOMIAL*  monomial,              /**< monomial */
6857    SCIP_Real             newcoef             /**< new coefficient */
6858    )
6859 {
6860    assert(monomial != NULL);
6861 
6862    monomial->coef = newcoef;
6863 }
6864 
6865 /** adds factors to a monomial */
SCIPexprAddMonomialFactors(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_MONOMIAL * monomial,int nfactors,int * childidxs,SCIP_Real * exponents)6866 SCIP_RETCODE SCIPexprAddMonomialFactors(
6867    BMS_BLKMEM*           blkmem,             /**< block memory */
6868    SCIP_EXPRDATA_MONOMIAL* monomial,         /**< monomial */
6869    int                   nfactors,           /**< number of factors to add */
6870    int*                  childidxs,          /**< indices of children corresponding to factors */
6871    SCIP_Real*            exponents           /**< exponent in each factor */
6872    )
6873 {
6874    assert(monomial != NULL);
6875    assert(nfactors >= 0);
6876    assert(childidxs != NULL || nfactors == 0);
6877    assert(exponents != NULL || nfactors == 0);
6878 
6879    if( nfactors == 0 )
6880       return SCIP_OKAY;
6881 
6882    SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6883    assert(monomial->nfactors + nfactors <= monomial->factorssize);
6884 
6885    BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors);  /*lint !e866*/
6886    BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors);  /*lint !e866*/
6887 
6888    monomial->nfactors += nfactors;
6889    monomial->sorted = (monomial->nfactors <= 1);
6890 
6891    return SCIP_OKAY;
6892 }
6893 
6894 /** multiplies a monomial with a monomial */
SCIPexprMultiplyMonomialByMonomial(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_MONOMIAL * monomial,SCIP_EXPRDATA_MONOMIAL * factor,int * childmap)6895 SCIP_RETCODE SCIPexprMultiplyMonomialByMonomial(
6896    BMS_BLKMEM*           blkmem,             /**< block memory */
6897    SCIP_EXPRDATA_MONOMIAL* monomial,         /**< monomial */
6898    SCIP_EXPRDATA_MONOMIAL* factor,           /**< factor monomial */
6899    int*                  childmap            /**< map to apply to children in factor, or NULL for 1:1 */
6900    )
6901 {
6902    assert(monomial != NULL);
6903    assert(factor != NULL);
6904 
6905    if( factor->coef == 0.0 )
6906    {
6907       monomial->nfactors = 0;
6908       monomial->coef = 0.0;
6909       return SCIP_OKAY;
6910    }
6911 
6912    SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6913 
6914    if( childmap != NULL )
6915    {
6916       int i;
6917       for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6918          monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6919    }
6920 
6921    monomial->coef *= factor->coef;
6922 
6923    return SCIP_OKAY;
6924 }
6925 
6926 /** replaces the monomial by a power of the monomial
6927  *
6928  *  Allows only integers as exponent.
6929  */
SCIPexprMonomialPower(SCIP_EXPRDATA_MONOMIAL * monomial,int exponent)6930 void SCIPexprMonomialPower(
6931    SCIP_EXPRDATA_MONOMIAL* monomial,         /**< monomial */
6932    int                   exponent            /**< integer exponent of power operation */
6933    )
6934 {
6935    int i;
6936 
6937    assert(monomial != NULL);
6938 
6939    if( exponent == 1 )
6940       return;
6941 
6942    if( exponent == 0 )
6943    {
6944       /* x^0 = 1, unless x = 0; 0^0 = 0 */
6945       if( monomial->coef != 0.0 )
6946          monomial->coef = 1.0;
6947       monomial->nfactors = 0;
6948       return;
6949    }
6950 
6951    monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6952    for( i = 0; i < monomial->nfactors; ++i )
6953       monomial->exponents[i] *= exponent;
6954 }
6955 
6956 /** merges factors that correspond to the same child by adding exponents
6957  *
6958  *  Eliminates factors with exponent between -eps and eps.
6959  */
SCIPexprMergeMonomialFactors(SCIP_EXPRDATA_MONOMIAL * monomial,SCIP_Real eps)6960 void SCIPexprMergeMonomialFactors(
6961    SCIP_EXPRDATA_MONOMIAL* monomial,         /**< monomial */
6962    SCIP_Real             eps                 /**< threshold under which numbers are treated as 0.0 */
6963    )
6964 {
6965    int i;
6966    int offset;
6967 
6968    assert(monomial != NULL);
6969    assert(eps >= 0.0);
6970 
6971    SCIPexprSortMonomialFactors(monomial);
6972 
6973    /* merge factors with same child index by adding up their exponents
6974     * delete factors with exponent 0.0 */
6975    offset = 0;
6976    i = 0;
6977    while( i + offset < monomial->nfactors )
6978    {
6979       if( offset > 0 )
6980       {
6981          assert(monomial->childidxs[i] == -1);
6982          assert(monomial->childidxs[i+offset] >= 0);
6983          monomial->childidxs[i] = monomial->childidxs[i+offset];
6984          monomial->exponents[i] = monomial->exponents[i+offset];
6985 #ifndef NDEBUG
6986          monomial->childidxs[i+offset] = -1;
6987 #endif
6988       }
6989 
6990       while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6991       {
6992          monomial->exponents[i] += monomial->exponents[i+offset+1];
6993 #ifndef NDEBUG
6994          monomial->childidxs[i+offset+1] = -1;
6995 #endif
6996          ++offset;
6997       }
6998 
6999       if( EPSZ(monomial->exponents[i], eps) )
7000       {
7001 #ifndef NDEBUG
7002          monomial->childidxs[i] = -1;
7003 #endif
7004          ++offset;
7005          continue;
7006       }
7007       else if( EPSISINT(monomial->exponents[i], eps) )
7008          monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
7009 
7010       ++i;
7011    }
7012 
7013 #ifndef NDEBUG
7014    for( ; i < monomial->nfactors; ++i )
7015       assert(monomial->childidxs[i] == -1);
7016 #endif
7017 
7018    monomial->nfactors -= offset;
7019 
7020    if( EPSEQ(monomial->coef, 1.0, eps) )
7021       monomial->coef = 1.0;
7022    else if( EPSEQ(monomial->coef, -1.0, eps) )
7023       monomial->coef = -1.0;
7024 }
7025 
7026 /** ensures that monomials of a polynomial are sorted */
SCIPexprSortMonomials(SCIP_EXPR * expr)7027 void SCIPexprSortMonomials(
7028    SCIP_EXPR*            expr                /**< polynomial expression */
7029    )
7030 {
7031    assert(expr != NULL);
7032    assert(expr->op == SCIP_EXPR_POLYNOMIAL);
7033    assert(expr->data.data != NULL);
7034 
7035    polynomialdataSortMonomials((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data);
7036 }
7037 
7038 /** creates a monomial */
SCIPexprCreateMonomial(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_MONOMIAL ** monomial,SCIP_Real coef,int nfactors,int * childidxs,SCIP_Real * exponents)7039 SCIP_RETCODE SCIPexprCreateMonomial(
7040    BMS_BLKMEM*           blkmem,             /**< block memory */
7041    SCIP_EXPRDATA_MONOMIAL** monomial,        /**< buffer where to store pointer to new monomial */
7042    SCIP_Real             coef,               /**< coefficient of monomial */
7043    int                   nfactors,           /**< number of factors in monomial */
7044    int*                  childidxs,          /**< indices of children corresponding to factors, or NULL if identity */
7045    SCIP_Real*            exponents           /**< exponent in each factor, or NULL if all 1.0 */
7046    )
7047 {
7048    assert(blkmem != NULL);
7049    assert(monomial != NULL);
7050 
7051    SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
7052 
7053    (*monomial)->coef     = coef;
7054    (*monomial)->nfactors = nfactors;
7055    (*monomial)->factorssize = nfactors;
7056    (*monomial)->sorted = (nfactors <= 1);
7057 
7058    if( nfactors > 0 )
7059    {
7060       if( childidxs != NULL )
7061       {
7062          SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
7063       }
7064       else
7065       {
7066          int i;
7067 
7068          SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
7069          for( i = 0; i < nfactors; ++i )
7070             (*monomial)->childidxs[i] = i;
7071       }
7072 
7073       if( exponents != NULL )
7074       {
7075          SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
7076       }
7077       else
7078       {
7079          int i;
7080 
7081          SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
7082          for( i = 0; i < nfactors; ++i )
7083             (*monomial)->exponents[i] = 1.0;
7084       }
7085    }
7086    else
7087    {
7088       (*monomial)->childidxs = NULL;
7089       (*monomial)->exponents = NULL;
7090    }
7091 
7092    return SCIP_OKAY;
7093 }
7094 
7095 /** frees a monomial */
SCIPexprFreeMonomial(BMS_BLKMEM * blkmem,SCIP_EXPRDATA_MONOMIAL ** monomial)7096 void SCIPexprFreeMonomial(
7097    BMS_BLKMEM*           blkmem,             /**< block memory */
7098    SCIP_EXPRDATA_MONOMIAL** monomial         /**< pointer to monomial that should be freed */
7099    )
7100 {
7101    assert(blkmem != NULL);
7102    assert( monomial != NULL);
7103    assert(*monomial != NULL);
7104 
7105    if( (*monomial)->factorssize > 0 )
7106    {
7107       assert((*monomial)->childidxs != NULL);
7108       assert((*monomial)->exponents != NULL);
7109 
7110       BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
7111       BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
7112    }
7113    assert((*monomial)->childidxs == NULL);
7114    assert((*monomial)->exponents == NULL);
7115 
7116    BMSfreeBlockMemory(blkmem, monomial);
7117 }
7118 
7119 /** ensures that factors in a monomial are sorted */
SCIPexprSortMonomialFactors(SCIP_EXPRDATA_MONOMIAL * monomial)7120 void SCIPexprSortMonomialFactors(
7121    SCIP_EXPRDATA_MONOMIAL* monomial          /**< monomial */
7122    )
7123 {
7124    assert(monomial != NULL);
7125 
7126    if( monomial->sorted )
7127       return;
7128 
7129    if( monomial->nfactors > 0 )
7130       SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
7131 
7132    monomial->sorted = TRUE;
7133 }
7134 
7135 /** finds a factor corresponding to a given child index in a monomial
7136  *
7137  *  Note that if the factors have not been merged, the position of some factor corresponding to a given child is given.
7138  *  Returns TRUE if a factor is found, FALSE if not.
7139  */
SCIPexprFindMonomialFactor(SCIP_EXPRDATA_MONOMIAL * monomial,int childidx,int * pos)7140 SCIP_Bool SCIPexprFindMonomialFactor(
7141    SCIP_EXPRDATA_MONOMIAL* monomial,         /**< monomial */
7142    int                   childidx,           /**< index of the child which factor to search for */
7143    int*                  pos                 /**< buffer to store position of factor */
7144    )
7145 {
7146    assert(monomial != NULL);
7147 
7148    if( monomial->nfactors == 0 )
7149       return FALSE;
7150 
7151    SCIPexprSortMonomialFactors(monomial);
7152 
7153    return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
7154 }
7155 
7156 /** creates a user expression */
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)))7157 SCIP_RETCODE SCIPexprCreateUser(
7158    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
7159    SCIP_EXPR**           expr,               /**< pointer to buffer for expression address */
7160    int                   nchildren,          /**< number of children */
7161    SCIP_EXPR**           children,           /**< children of expression */
7162    SCIP_USEREXPRDATA*    data,               /**< user data for expression, expression assumes ownership */
7163    SCIP_EXPRINTCAPABILITY evalcapability,    /**< capability of evaluation functions (partially redundant, currently) */
7164    SCIP_DECL_USEREXPREVAL    ((*eval)),      /**< evaluation function */
7165    SCIP_DECL_USEREXPRINTEVAL ((*inteval)),   /**< interval evaluation function, or NULL if not implemented */
7166    SCIP_DECL_USEREXPRCURV    ((*curv)),      /**< curvature check function */
7167    SCIP_DECL_USEREXPRPROP    ((*prop)),      /**< interval propagation function, or NULL if not implemented */
7168    SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
7169    SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
7170    SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
7171    SCIP_DECL_USEREXPRPRINT ((*print))        /**< expression print function, or NULL for default string "user" */
7172    )
7173 {
7174    SCIP_EXPROPDATA opdata;
7175    SCIP_EXPRDATA_USER* userexprdata;
7176    SCIP_EXPR** childrencopy;
7177 
7178    assert(blkmem != NULL);
7179    assert(expr != NULL);
7180    assert(eval != NULL);
7181    assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0);  /* the function evaluation is not optional */
7182    assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL);  /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
7183    assert(curv != NULL);
7184    assert(copydata != NULL || data == NULL);
7185    assert(freedata != NULL || data == NULL);
7186 
7187    SCIP_ALLOC( BMSallocBlockMemory(blkmem, &userexprdata) );
7188 
7189    userexprdata->userdata = data;
7190    userexprdata->evalcapability = evalcapability;
7191    userexprdata->eval = eval;
7192    userexprdata->inteval = inteval;
7193    userexprdata->curv = curv;
7194    userexprdata->prop = prop;
7195    userexprdata->estimate = estimate;
7196    userexprdata->copydata = copydata;
7197    userexprdata->freedata = freedata;
7198    userexprdata->print = print;
7199 
7200    opdata.data = (void*) userexprdata;
7201 
7202    if( nchildren == 0 )
7203    {
7204       SCIP_CALL( exprCreate(blkmem, expr, SCIP_EXPR_USER, 0, NULL, opdata) );
7205       return SCIP_OKAY;
7206    }
7207    assert(children != NULL);
7208 
7209    SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
7210 
7211    SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_USER, nchildren, childrencopy, opdata) );
7212 
7213    return SCIP_OKAY;
7214 }
7215 
7216 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
SCIPexprHasParam(SCIP_EXPR * expr)7217 SCIP_Bool SCIPexprHasParam(
7218    SCIP_EXPR*            expr                /**< expression */
7219    )
7220 {
7221    int i;
7222 
7223    assert(expr != NULL);
7224 
7225    if( expr->op == SCIP_EXPR_PARAM )
7226       return TRUE;
7227 
7228    for( i = 0; i < expr->nchildren; ++i )
7229       if( SCIPexprHasParam(expr->children[i]) )
7230          return TRUE;
7231 
7232    return FALSE;
7233 }
7234 
7235 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
SCIPexprGetMaxDegree(SCIP_EXPR * expr,int * maxdegree)7236 SCIP_RETCODE SCIPexprGetMaxDegree(
7237    SCIP_EXPR*            expr,               /**< expression */
7238    int*                  maxdegree           /**< buffer to store maximal degree */
7239    )
7240 {
7241    int child1;
7242    int child2;
7243 
7244    assert(expr      != NULL);
7245    assert(maxdegree != NULL);
7246 
7247    switch( expr->op )
7248    {
7249    case SCIP_EXPR_VARIDX:
7250       *maxdegree = 1;
7251       break;
7252 
7253    case SCIP_EXPR_CONST:
7254    case SCIP_EXPR_PARAM:
7255       *maxdegree = 0;
7256       break;
7257 
7258    case SCIP_EXPR_PLUS:
7259    case SCIP_EXPR_MINUS:
7260    {
7261       assert(expr->children[0] != NULL);
7262       assert(expr->children[1] != NULL);
7263 
7264       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7265       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7266 
7267       *maxdegree = MAX(child1, child2);
7268       break;
7269    }
7270 
7271    case SCIP_EXPR_MUL:
7272    {
7273       assert(expr->children[0] != NULL);
7274       assert(expr->children[1] != NULL);
7275 
7276       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7277       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7278 
7279       *maxdegree = child1 + child2;
7280       break;
7281    }
7282 
7283    case SCIP_EXPR_DIV:
7284    {
7285       assert(expr->children[0] != NULL);
7286       assert(expr->children[1] != NULL);
7287 
7288       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7289       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7290 
7291       /* if not division by constant, then it is not a polynomial */
7292       *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
7293       break;
7294    }
7295 
7296    case SCIP_EXPR_SQUARE:
7297    {
7298       assert(expr->children[0] != NULL);
7299 
7300       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7301 
7302       *maxdegree = 2 * child1;
7303       break;
7304    }
7305 
7306    case SCIP_EXPR_SQRT:
7307    {
7308       assert(expr->children[0] != NULL);
7309 
7310       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7311 
7312       /* if not squareroot of constant, then no polynomial */
7313       *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7314       break;
7315    }
7316 
7317    case SCIP_EXPR_REALPOWER:
7318    {
7319       assert(expr->children[0] != NULL);
7320 
7321       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7322 
7323       /* constant ^ constant has degree 0 */
7324       if( child1 == 0 )
7325       {
7326          *maxdegree = 0;
7327          break;
7328       }
7329 
7330       /* non-polynomial ^ constant is not a polynomial */
7331       if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7332       {
7333          *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7334          break;
7335       }
7336 
7337       /* so it is polynomial ^ constant
7338        * let's see whether the constant is integral */
7339 
7340       if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
7341          *maxdegree = 0;
7342       else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */  /*lint !e777*/
7343          *maxdegree = child1 * (int)expr->data.dbl;
7344       else /* negative or nonintegral exponent does not give polynomial */
7345          *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7346 
7347       break;
7348    }
7349 
7350    case SCIP_EXPR_INTPOWER:
7351    {
7352       assert(expr->children[0] != NULL);
7353 
7354       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7355 
7356       /* constant ^ integer or something ^ 0 has degree 0 */
7357       if( child1 == 0 || expr->data.intval == 0 )
7358       {
7359          *maxdegree = 0;
7360          break;
7361       }
7362 
7363       /* non-polynomial ^ integer  or  something ^ negative  is not a polynomial */
7364       if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
7365       {
7366          *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7367          break;
7368       }
7369 
7370       /* so it is polynomial ^ natural, which gives a polynomial again */
7371       *maxdegree = child1 * expr->data.intval;
7372 
7373       break;
7374    }
7375 
7376    case SCIP_EXPR_SIGNPOWER:
7377    {
7378       assert(expr->children[0] != NULL);
7379 
7380       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7381 
7382       /* if child is not constant, then it is no polynomial */
7383       *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
7384       break;
7385    }
7386 
7387    case SCIP_EXPR_EXP:
7388    case SCIP_EXPR_LOG:
7389    case SCIP_EXPR_SIN:
7390    case SCIP_EXPR_COS:
7391    case SCIP_EXPR_TAN:
7392       /* case SCIP_EXPR_ERF: */
7393       /* case SCIP_EXPR_ERFI: */
7394    case SCIP_EXPR_ABS:
7395    case SCIP_EXPR_SIGN:
7396    case SCIP_EXPR_USER:
7397    {
7398       assert(expr->children[0] != NULL);
7399 
7400       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7401 
7402       /* if argument is not a constant, then no polynomial, otherwise it is a constant */
7403       *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7404       break;
7405    }
7406 
7407    case SCIP_EXPR_MIN:
7408    case SCIP_EXPR_MAX:
7409    {
7410       assert(expr->children[0] != NULL);
7411       assert(expr->children[1] != NULL);
7412 
7413       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7414       SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7415 
7416       /* if any of the operands is not constant, then it is no polynomial */
7417       *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7418       break;
7419    }
7420 
7421    case SCIP_EXPR_SUM:
7422    case SCIP_EXPR_LINEAR:
7423    {
7424       int i;
7425 
7426       *maxdegree = 0;
7427       for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7428       {
7429          SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7430          if( child1 > *maxdegree )
7431             *maxdegree = child1;
7432       }
7433 
7434       break;
7435    }
7436 
7437    case SCIP_EXPR_PRODUCT:
7438    {
7439       int i;
7440 
7441       *maxdegree = 0;
7442       for( i = 0; i < expr->nchildren; ++i )
7443       {
7444          SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7445          if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7446          {
7447             *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7448             break;
7449          }
7450          *maxdegree += child1;
7451       }
7452 
7453       break;
7454    }
7455 
7456    case SCIP_EXPR_QUADRATIC:
7457    {
7458       SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7459       int childidx;
7460       int quadidx;
7461 
7462       quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7463 
7464       /* make sure quadratic elements are sorted */
7465       quadraticdataSort(quadraticdata);
7466 
7467       *maxdegree = 0;
7468       quadidx = 0;
7469       for( childidx = 0; childidx < expr->nchildren; ++childidx )
7470       {
7471          /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7472          if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7473             (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7474             continue;
7475 
7476          SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7477          if( child1 == SCIP_EXPR_DEGREEINFINITY )
7478          {
7479             *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7480             break;
7481          }
7482 
7483          while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7484          {
7485             if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7486             {
7487                /* square term */
7488                if( 2*child1 > *maxdegree )
7489                   *maxdegree = 2*child1;
7490             }
7491             else
7492             {
7493                /* bilinear term */
7494                SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7495                if( child2 == SCIP_EXPR_DEGREEINFINITY )
7496                {
7497                   *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7498                   break;
7499                }
7500                if( child1 + child2 > *maxdegree )
7501                   *maxdegree = child1 + child2;
7502             }
7503             ++quadidx;
7504          }
7505          if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7506             break;
7507       }
7508 
7509       break;
7510    }
7511 
7512    case SCIP_EXPR_POLYNOMIAL:
7513    {
7514       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7515       SCIP_EXPRDATA_MONOMIAL* monomialdata;
7516       int monomialdegree;
7517       int i;
7518       int j;
7519 
7520       polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7521 
7522       *maxdegree = 0;
7523       for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7524       {
7525          monomialdata = polynomialdata->monomials[i];
7526          assert(monomialdata != NULL);
7527 
7528          /* compute degree of monomial = sum of degree of factors */
7529          monomialdegree = 0;
7530          for( j = 0; j < monomialdata->nfactors; ++j )
7531          {
7532             SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7533 
7534             /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7535              * then we report that we are not really a polynomial */
7536             if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7537             {
7538                *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7539                break;
7540             }
7541 
7542             monomialdegree += child1 * (int)monomialdata->exponents[j];
7543          }
7544 
7545          if( monomialdegree > *maxdegree )
7546             *maxdegree = monomialdegree;
7547       }
7548 
7549       break;
7550    }
7551 
7552    case SCIP_EXPR_LAST:
7553       SCIPABORT();
7554       break;
7555    }
7556 
7557    return SCIP_OKAY;
7558 }
7559 
7560 /** counts usage of variables in expression */
SCIPexprGetVarsUsage(SCIP_EXPR * expr,int * varsusage)7561 void SCIPexprGetVarsUsage(
7562    SCIP_EXPR*            expr,               /**< expression to update */
7563    int*                  varsusage           /**< array with counters of variable usage */
7564    )
7565 {
7566    int i;
7567 
7568    assert(expr != NULL);
7569    assert(varsusage != NULL);
7570 
7571    if( expr->op == SCIP_EXPR_VARIDX )
7572    {
7573       ++varsusage[expr->data.intval];
7574    }
7575 
7576    for( i = 0; i < expr->nchildren; ++i )
7577       SCIPexprGetVarsUsage(expr->children[i], varsusage);
7578 }
7579 
7580 /** compares whether two expressions are the same
7581  *
7582  *  Inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x).
7583  */
SCIPexprAreEqual(SCIP_EXPR * expr1,SCIP_EXPR * expr2,SCIP_Real eps)7584 SCIP_Bool SCIPexprAreEqual(
7585    SCIP_EXPR*            expr1,              /**< first expression */
7586    SCIP_EXPR*            expr2,              /**< second expression */
7587    SCIP_Real             eps                 /**< threshold under which numbers are assumed to be zero */
7588    )
7589 {
7590    assert(expr1 != NULL);
7591    assert(expr2 != NULL);
7592 
7593    if( expr1 == expr2 )
7594       return TRUE;
7595 
7596    if( expr1->op != expr2->op )
7597       return FALSE;
7598 
7599    switch( expr1->op )
7600    {
7601    case SCIP_EXPR_VARIDX:
7602    case SCIP_EXPR_PARAM:
7603       return expr1->data.intval == expr2->data.intval;
7604 
7605    case SCIP_EXPR_CONST:
7606       return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7607 
7608       /* operands with two children */
7609    case SCIP_EXPR_PLUS     :
7610    case SCIP_EXPR_MINUS    :
7611    case SCIP_EXPR_MUL      :
7612    case SCIP_EXPR_DIV      :
7613    case SCIP_EXPR_MIN      :
7614    case SCIP_EXPR_MAX      :
7615       return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7616 
7617       /* operands with one child */
7618    case SCIP_EXPR_SQUARE:
7619    case SCIP_EXPR_SQRT  :
7620    case SCIP_EXPR_EXP   :
7621    case SCIP_EXPR_LOG   :
7622    case SCIP_EXPR_SIN   :
7623    case SCIP_EXPR_COS   :
7624    case SCIP_EXPR_TAN   :
7625       /* case SCIP_EXPR_ERF   : */
7626       /* case SCIP_EXPR_ERFI  : */
7627    case SCIP_EXPR_ABS   :
7628    case SCIP_EXPR_SIGN  :
7629       return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7630 
7631    case SCIP_EXPR_REALPOWER:
7632    case SCIP_EXPR_SIGNPOWER:
7633       return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7634 
7635    case SCIP_EXPR_INTPOWER:
7636       return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7637 
7638       /* complex operands */
7639    case SCIP_EXPR_SUM    :
7640    case SCIP_EXPR_PRODUCT:
7641    {
7642       int i;
7643 
7644       /* @todo sort children and have sorted flag in data? */
7645 
7646       if( expr1->nchildren != expr2->nchildren )
7647          return FALSE;
7648 
7649       for( i = 0; i < expr1->nchildren; ++i )
7650       {
7651          if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7652             return FALSE;
7653       }
7654 
7655       return TRUE;
7656    }
7657 
7658    case SCIP_EXPR_LINEAR :
7659    {
7660       SCIP_Real* data1;
7661       SCIP_Real* data2;
7662       int i;
7663 
7664       /* @todo sort children and have sorted flag in data? */
7665 
7666       if( expr1->nchildren != expr2->nchildren )
7667          return FALSE;
7668 
7669       data1 = (SCIP_Real*)expr1->data.data;
7670       data2 = (SCIP_Real*)expr2->data.data;
7671 
7672       /* check if constant and coefficients are equal */
7673       for( i = 0; i < expr1->nchildren + 1; ++i )
7674          if( !EPSEQ(data1[i], data2[i], eps) )
7675             return FALSE;
7676 
7677       /* check if children are equal */
7678       for( i = 0; i < expr1->nchildren; ++i )
7679       {
7680          if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7681             return FALSE;
7682       }
7683 
7684       return TRUE;
7685    }
7686 
7687    case SCIP_EXPR_QUADRATIC:
7688    {
7689       SCIP_EXPRDATA_QUADRATIC* data1;
7690       SCIP_EXPRDATA_QUADRATIC* data2;
7691       int i;
7692 
7693       if( expr1->nchildren != expr2->nchildren )
7694          return FALSE;
7695 
7696       data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7697       data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7698 
7699       if( data1->nquadelems != data2->nquadelems )
7700          return FALSE;
7701 
7702       if( !EPSEQ(data1->constant, data2->constant, eps) )
7703          return FALSE;
7704 
7705       /* check if linear part is equal */
7706       if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7707          for( i = 0; i < expr1->nchildren; ++i )
7708          {
7709             if( data1->lincoefs == NULL )
7710             {
7711                if( !EPSZ(data2->lincoefs[i], eps) )
7712                   return FALSE;
7713             }
7714             else if( data2->lincoefs == NULL )
7715             {
7716                if( !EPSZ(data1->lincoefs[i], eps) )
7717                   return FALSE;
7718             }
7719             else if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7720                return FALSE;
7721          }
7722 
7723       SCIPexprSortQuadElems(expr1);
7724       SCIPexprSortQuadElems(expr2);
7725 
7726       /* check if quadratic elements are equal */
7727       for( i = 0; i < data1->nquadelems; ++i )
7728          if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7729             data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7730             !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7731             return FALSE;
7732 
7733       /* check if children are equal */
7734       for( i = 0; i < expr1->nchildren; ++i )
7735          if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7736             return FALSE;
7737 
7738       return TRUE;
7739    }
7740 
7741    case SCIP_EXPR_POLYNOMIAL:
7742    {
7743       SCIP_EXPRDATA_POLYNOMIAL* data1;
7744       SCIP_EXPRDATA_POLYNOMIAL* data2;
7745       int i;
7746 
7747       if( expr1->nchildren != expr2->nchildren )
7748          return FALSE;
7749 
7750       data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7751       data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7752 
7753       if( data1->nmonomials != data2->nmonomials )
7754          return FALSE;
7755 
7756       if( !EPSEQ(data1->constant, data2->constant, eps) )
7757          return FALSE;
7758 
7759       /* make sure polynomials are sorted */
7760       SCIPexprSortMonomials(expr1);
7761       SCIPexprSortMonomials(expr2);
7762 
7763       /* check if monomials are equal */
7764       for( i = 0; i < data1->nmonomials; ++i )
7765       {
7766          if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7767             return FALSE;
7768       }
7769 
7770       /* check if children are equal */
7771       for( i = 0; i < expr1->nchildren; ++i )
7772       {
7773          if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7774             return FALSE;
7775       }
7776 
7777       return TRUE;
7778    }
7779 
7780    case SCIP_EXPR_USER:
7781    {
7782       /* @todo could implement this via another user callback */
7783       return FALSE;
7784    }
7785 
7786    case SCIP_EXPR_LAST:
7787       break;
7788    }
7789 
7790    SCIPerrorMessage("this should never happen\n");
7791    SCIPABORT();
7792    return FALSE;  /*lint !e527*/
7793 }
7794 
7795 /** aims at simplifying an expression and splitting of a linear expression
7796  *
7797  *  If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
7798  */
SCIPexprSimplify(BMS_BLKMEM * blkmem,SCIP_MESSAGEHDLR * messagehdlr,SCIP_EXPR * expr,SCIP_Real eps,int maxexpansionexponent,int nvars,int * nlinvars,int * linidxs,SCIP_Real * lincoefs)7799 SCIP_RETCODE SCIPexprSimplify(
7800    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
7801    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
7802    SCIP_EXPR*            expr,               /**< expression */
7803    SCIP_Real             eps,                /**< threshold, under which positive values are treat as 0 */
7804    int                   maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7805    int                   nvars,              /**< number of variables in expression */
7806    int*                  nlinvars,           /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7807    int*                  linidxs,            /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7808    SCIP_Real*            lincoefs            /**< array to store coefficients of linear part, or NULL */
7809    )
7810 {
7811    assert(blkmem != NULL);
7812    assert(expr != NULL);
7813    assert(eps >= 0.0);
7814 
7815    SCIPdebugMessage("simplify expression: ");
7816    SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7817    SCIPdebugPrintf("\n");
7818 
7819    SCIP_CALL( exprsimplifyConvertToPolynomials(blkmem, expr) );
7820 
7821    SCIPdebugMessage("converted to polynomials: ");
7822    SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7823    SCIPdebugPrintf("\n");
7824 
7825    SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7826 
7827    SCIPdebugMessage("polynomials flattened: ");
7828    SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7829    SCIPdebugPrintf("\n");
7830 
7831    if( nlinvars != NULL )
7832    {
7833       /* separate linear part from root polynomial */
7834       SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7835 
7836       SCIPdebugMessage("separated linear part: ");
7837       SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7838       SCIPdebugPrintf("\n");
7839    }
7840 
7841    SCIP_CALL( exprsimplifyUnconvertPolynomials(blkmem, expr) );
7842 
7843    SCIPdebugMessage("converted back from polynomials: ");
7844    SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7845    SCIPdebugPrintf("\n");
7846 
7847    return SCIP_OKAY;
7848 }
7849 
7850 /** evaluates an expression w.r.t. given values for children expressions */
SCIPexprEvalShallow(SCIP_EXPR * expr,SCIP_Real * argvals,SCIP_Real * varvals,SCIP_Real * param,SCIP_Real * val)7851 SCIP_RETCODE SCIPexprEvalShallow(
7852    SCIP_EXPR*            expr,               /**< expression */
7853    SCIP_Real*            argvals,            /**< values for children, can be NULL if the expression has no children */
7854    SCIP_Real*            varvals,            /**< values for variables, can be NULL if the expression operand is not a variable */
7855    SCIP_Real*            param,              /**< values for parameters, can be NULL if the expression operand is not a parameter */
7856    SCIP_Real*            val                 /**< buffer to store value */
7857    )
7858 {
7859    assert(expr != NULL);
7860    assert(argvals != NULL || expr->nchildren == 0);
7861 
7862    /* evaluate this expression */
7863    assert( exprOpTable[expr->op].eval != NULL );
7864    SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, argvals, varvals, param, val) );
7865 
7866    return SCIP_OKAY;
7867 }
7868 
7869 /** evaluates an expression w.r.t. a point */
SCIPexprEval(SCIP_EXPR * expr,SCIP_Real * varvals,SCIP_Real * param,SCIP_Real * val)7870 SCIP_RETCODE SCIPexprEval(
7871    SCIP_EXPR*            expr,               /**< expression */
7872    SCIP_Real*            varvals,            /**< values for variables, can be NULL if the expression is constant */
7873    SCIP_Real*            param,              /**< values for parameters, can be NULL if the expression is not parameterized */
7874    SCIP_Real*            val                 /**< buffer to store value */
7875    )
7876 {
7877    int i;
7878    SCIP_Real  staticbuf[SCIP_EXPRESSION_MAXCHILDEST];
7879    SCIP_Real* buf;
7880 
7881    /* if many children, get large enough memory to store argument values */
7882    if( expr->nchildren > SCIP_EXPRESSION_MAXCHILDEST )
7883    {
7884       SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7885    }
7886    else
7887    {
7888       buf = staticbuf;
7889    }
7890 
7891    /* evaluate children */
7892    for( i = 0; i < expr->nchildren; ++i )
7893    {
7894       SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) );  /*lint !e644*/
7895    }
7896 
7897    /* evaluate this expression */
7898    assert( exprOpTable[expr->op].eval != NULL );
7899    SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7900 
7901    /* free memory, if allocated before */
7902    if( staticbuf != buf )
7903    {
7904       BMSfreeMemoryArray(&buf);
7905    }
7906 
7907    return SCIP_OKAY;
7908 }
7909 
7910 /** evaluates an expression w.r.t. given interval values for children expressions */
SCIPexprEvalIntShallow(SCIP_EXPR * expr,SCIP_Real infinity,SCIP_INTERVAL * argvals,SCIP_INTERVAL * varvals,SCIP_Real * param,SCIP_INTERVAL * val)7911 SCIP_RETCODE SCIPexprEvalIntShallow(
7912    SCIP_EXPR*            expr,               /**< expression */
7913    SCIP_Real             infinity,           /**< value to use for infinity */
7914    SCIP_INTERVAL*        argvals,            /**< interval values for children, can be NULL if the expression has no children */
7915    SCIP_INTERVAL*        varvals,            /**< interval values for variables, can be NULL if the expression is constant */
7916    SCIP_Real*            param,              /**< values for parameters, can be NULL if the expression is not parameterized */
7917    SCIP_INTERVAL*        val                 /**< buffer to store value */
7918    )
7919 {
7920    assert(expr != NULL);
7921    assert(argvals != NULL || expr->nchildren == 0);
7922 
7923    /* evaluate this expression */
7924    assert( exprOpTable[expr->op].inteval != NULL );
7925    SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, argvals, varvals, param, val) );
7926 
7927    return SCIP_OKAY;
7928 }
7929 
7930 /** evaluates an expression w.r.t. an interval */
SCIPexprEvalInt(SCIP_EXPR * expr,SCIP_Real infinity,SCIP_INTERVAL * varvals,SCIP_Real * param,SCIP_INTERVAL * val)7931 SCIP_RETCODE SCIPexprEvalInt(
7932    SCIP_EXPR*            expr,               /**< expression */
7933    SCIP_Real             infinity,           /**< value to use for infinity */
7934    SCIP_INTERVAL*        varvals,            /**< interval values for variables, can be NULL if the expression is constant */
7935    SCIP_Real*            param,              /**< values for parameters, can be NULL if the expression is not parameterized */
7936    SCIP_INTERVAL*        val                 /**< buffer to store value */
7937    )
7938 {
7939    int i;
7940    SCIP_INTERVAL  staticbuf[SCIP_EXPRESSION_MAXCHILDEST];
7941    SCIP_INTERVAL* buf;
7942 
7943    /* if many children, get large enough memory to store argument values */
7944    if( expr->nchildren > SCIP_EXPRESSION_MAXCHILDEST )
7945    {
7946       SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7947    }
7948    else
7949    {
7950       buf = staticbuf;
7951    }
7952 
7953    /* evaluate children */
7954    for( i = 0; i < expr->nchildren; ++i )
7955    {
7956       SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) );  /*lint !e644*/
7957    }
7958 
7959    /* evaluate this expression */
7960    assert( exprOpTable[expr->op].inteval != NULL );
7961    SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7962 
7963    /* free memory, if allocated before */
7964    if( staticbuf != buf )
7965    {
7966       BMSfreeMemoryArray(&buf);
7967    }
7968 
7969    return SCIP_OKAY;
7970 }
7971 
7972 /** evaluates a user expression w.r.t. given values for children expressions */
SCIPexprEvalUser(SCIP_EXPR * expr,SCIP_Real * argvals,SCIP_Real * val,SCIP_Real * gradient,SCIP_Real * hessian)7973 SCIP_RETCODE SCIPexprEvalUser(
7974    SCIP_EXPR*            expr,               /**< expression */
7975    SCIP_Real*            argvals,            /**< values for children */
7976    SCIP_Real*            val,                /**< buffer to store function value */
7977    SCIP_Real*            gradient,           /**< buffer to store gradient values, or NULL if not requested */
7978    SCIP_Real*            hessian             /**< buffer to store values of full Hessian, or NULL if not requested */
7979    )
7980 {
7981    SCIP_EXPRDATA_USER* exprdata;
7982 
7983    assert(expr != NULL);
7984    assert(expr->op == SCIP_EXPR_USER);
7985    assert(argvals != NULL || expr->nchildren == 0);
7986 
7987    exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7988    assert(exprdata->eval != NULL);
7989 
7990    SCIP_CALL( exprdata->eval(exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7991 
7992    return SCIP_OKAY;
7993 }
7994 
7995 /** evaluates a user expression w.r.t. an interval */
SCIPexprEvalIntUser(SCIP_EXPR * expr,SCIP_Real infinity,SCIP_INTERVAL * argvals,SCIP_INTERVAL * val,SCIP_INTERVAL * gradient,SCIP_INTERVAL * hessian)7996 SCIP_RETCODE SCIPexprEvalIntUser(
7997    SCIP_EXPR*            expr,               /**< expression */
7998    SCIP_Real             infinity,           /**< value to use for infinity */
7999    SCIP_INTERVAL*        argvals,            /**< values for children */
8000    SCIP_INTERVAL*        val,                /**< buffer to store value */
8001    SCIP_INTERVAL*        gradient,           /**< buffer to store gradient values, or NULL if not requested */
8002    SCIP_INTERVAL*        hessian             /**< buffer to store values of full Hessian, or NULL if not requested */
8003    )
8004 {
8005    SCIP_EXPRDATA_USER* exprdata;
8006 
8007    assert(expr != NULL);
8008    assert(expr->op == SCIP_EXPR_USER);
8009    assert(argvals != NULL || expr->nchildren == 0);
8010 
8011    exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8012 
8013    if( exprdata->inteval == NULL )
8014    {
8015       int i;
8016 
8017       for( i = 0; i < expr->nchildren; ++i )
8018          SCIPintervalSetEntire(infinity, &argvals[i]); /*lint !e613*/
8019    }
8020    else
8021    {
8022       SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
8023    }
8024 
8025    return SCIP_OKAY;
8026 }
8027 
8028 /** internal curvature check method */
8029 static
doCheckCurvature(SCIP_EXPR * expr,SCIP_Real infinity,SCIP_INTERVAL * varbounds,SCIP_INTERVAL * childbounds,SCIP_Real * param,SCIP_EXPRCURV * curv,SCIP_EXPRCURV * childcurv,SCIP_INTERVAL * bounds)8030 SCIP_RETCODE doCheckCurvature(
8031    SCIP_EXPR*            expr,               /**< expression to check */
8032    SCIP_Real             infinity,           /**< value to use for infinity */
8033    SCIP_INTERVAL*        varbounds,          /**< domains of variables */
8034    SCIP_INTERVAL*        childbounds,        /**< child bounds buffer array */
8035    SCIP_Real*            param,              /**< values for parameters, can be NULL if the expression is not parameterized */
8036    SCIP_EXPRCURV*        curv,               /**< buffer to store curvature of expression */
8037    SCIP_EXPRCURV*        childcurv,          /**< buffer array for curvature of children */
8038    SCIP_INTERVAL*        bounds              /**< buffer to store bounds on expression */
8039    )
8040 {
8041    int i;
8042 
8043    assert(childbounds != NULL);
8044    assert(childcurv != NULL);
8045 
8046    /* check curvature and compute bounds of children
8047     * constant children can be considered as always linear */
8048    for( i = 0; i < expr->nchildren; ++i )
8049    {
8050       SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) );  /*lint !e644*/
8051       if( childbounds[i].inf == childbounds[i].sup )  /*lint !e777*/
8052          childcurv[i] = SCIP_EXPRCURV_LINEAR;
8053    }
8054 
8055    /* get curvature and bounds of expr */
8056    assert(exprOpTable[expr->op].curv != NULL);
8057    assert(exprOpTable[expr->op].inteval != NULL);
8058 
8059    SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
8060    SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
8061 
8062    return SCIP_OKAY;
8063 }
8064 
8065 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
SCIPexprCheckCurvature(SCIP_EXPR * expr,SCIP_Real infinity,SCIP_INTERVAL * varbounds,SCIP_Real * param,SCIP_EXPRCURV * curv,SCIP_INTERVAL * bounds)8066 SCIP_RETCODE SCIPexprCheckCurvature(
8067    SCIP_EXPR*            expr,               /**< expression to check */
8068    SCIP_Real             infinity,           /**< value to use for infinity */
8069    SCIP_INTERVAL*        varbounds,          /**< domains of variables */
8070    SCIP_Real*            param,              /**< values for parameters, can be NULL if the expression is not parameterized */
8071    SCIP_EXPRCURV*        curv,               /**< buffer to store curvature of expression */
8072    SCIP_INTERVAL*        bounds              /**< buffer to store bounds on expression */
8073    )
8074 {
8075    SCIP_INTERVAL  childboundsbuf[SCIP_EXPRESSION_MAXCHILDEST];
8076    SCIP_INTERVAL* childbounds = NULL;
8077    SCIP_EXPRCURV  childcurvbuf[SCIP_EXPRESSION_MAXCHILDEST];
8078    SCIP_EXPRCURV* childcurv = NULL;
8079    SCIP_RETCODE retcode = SCIP_OKAY;
8080 
8081    assert(expr != NULL);
8082    assert(curv != NULL);
8083    assert(bounds != NULL);
8084 
8085    /* if many children, get large enough memory to store argument values */
8086    if( expr->nchildren > SCIP_EXPRESSION_MAXCHILDEST )
8087    {
8088       SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
8089       SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, expr->nchildren), TERMINATE );
8090    }
8091    else
8092    {
8093       childbounds = childboundsbuf;
8094       childcurv   = childcurvbuf;
8095    }
8096 
8097    retcode = doCheckCurvature(expr, infinity, varbounds, childbounds, param, curv, childcurv, bounds);
8098 
8099 TERMINATE:
8100    /* free memory, if allocated before */
8101    if( childboundsbuf != childbounds )
8102    {
8103       BMSfreeMemoryArrayNull(&childcurv);
8104       BMSfreeMemoryArrayNull(&childbounds);
8105    }
8106 
8107    return retcode;
8108 }
8109 
8110 /** under-/overestimates a user expression w.r.t. to given values and bounds for children expressions */
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)8111 SCIP_RETCODE SCIPexprEstimateUser(
8112    SCIP_EXPR*           expr,           /**< expression */
8113    SCIP_Real            infinity,       /**< value to use for infinity */
8114    SCIP_Real*           argvals,        /**< values for children */
8115    SCIP_INTERVAL*       argbounds,      /**< bounds for children */
8116    SCIP_Bool            overestimate,   /**< whether to overestimate the expression */
8117    SCIP_Real*           coeffs,         /**< buffer to store the linear coefficients for each child expression that gives a valid under-/overestimator */
8118    SCIP_Real*           constant,       /**< buffer to store the constant value of the linear under-/overestimator */
8119    SCIP_Bool*           success         /**< buffer to store whether an estimator was successfully computed */
8120    )
8121 {
8122    SCIP_EXPRDATA_USER* exprdata;
8123 
8124    assert(expr != NULL);
8125    assert(expr->op == SCIP_EXPR_USER);
8126    assert(argvals != NULL || expr->nchildren == 0);
8127    assert(argbounds != NULL || expr->nchildren == 0);
8128 
8129    exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8130 
8131    if( exprdata->estimate != NULL )
8132    {
8133       SCIP_CALL( exprdata->estimate(infinity, exprdata->userdata, expr->nchildren, argvals, argbounds, overestimate, coeffs, constant, success ) );
8134    }
8135    else
8136    {
8137       *success = FALSE;
8138    }
8139 
8140    return SCIP_OKAY;
8141 }
8142 
8143 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
8144  *
8145  *  Note that only the children of the given expr are checked!
8146  *  A variable with index i is replaced by a copy of substexprs[i], if the latter is not NULL.
8147  *  If substexprs[i] == NULL, then the variable expression i is not touched.
8148  */
SCIPexprSubstituteVars(BMS_BLKMEM * blkmem,SCIP_EXPR * expr,SCIP_EXPR ** substexprs)8149 SCIP_RETCODE SCIPexprSubstituteVars(
8150    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
8151    SCIP_EXPR*            expr,               /**< expression, which of the children may be replaced */
8152    SCIP_EXPR**           substexprs          /**< array of substitute expressions; single entries can be NULL */
8153    )
8154 {
8155    int i;
8156 
8157    assert(blkmem != NULL);
8158    assert(expr   != NULL);
8159    assert(substexprs != NULL);
8160 
8161    for( i = 0; i < expr->nchildren; ++i )
8162    {
8163       if( expr->children[i]->op == SCIP_EXPR_VARIDX )
8164       {
8165          int varidx;
8166          varidx = expr->children[i]->data.intval;
8167 
8168          assert(varidx >= 0);
8169          if( substexprs[varidx] != NULL )
8170          {
8171             /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
8172             SCIPexprFreeDeep(blkmem, &expr->children[i]);
8173             SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
8174          }
8175       }
8176       else
8177       {
8178          /* call recursively */
8179          SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
8180       }
8181    }
8182 
8183    return SCIP_OKAY;
8184 }
8185 
8186 /** updates variable indices in expression tree */
SCIPexprReindexVars(SCIP_EXPR * expr,int * newindices)8187 void SCIPexprReindexVars(
8188    SCIP_EXPR*            expr,               /**< expression to update */
8189    int*                  newindices          /**< new indices of variables */
8190    )
8191 {
8192    int i;
8193 
8194    assert(expr != NULL);
8195    assert(newindices != NULL);
8196 
8197    if( expr->op == SCIP_EXPR_VARIDX )
8198    {
8199       expr->data.intval = newindices[expr->data.intval];
8200       assert(expr->data.intval >= 0);
8201    }
8202 
8203    for( i = 0; i < expr->nchildren; ++i )
8204       SCIPexprReindexVars(expr->children[i], newindices);
8205 }
8206 
8207 /** updates parameter indices in expression tree */
SCIPexprReindexParams(SCIP_EXPR * expr,int * newindices)8208 void SCIPexprReindexParams(
8209    SCIP_EXPR*            expr,               /**< expression to update */
8210    int*                  newindices          /**< new indices of variables */
8211    )
8212 {
8213    int i;
8214 
8215    assert(expr != NULL);
8216    assert(newindices != NULL);
8217 
8218    if( expr->op == SCIP_EXPR_PARAM )
8219    {
8220       expr->data.intval = newindices[expr->data.intval];
8221       assert(expr->data.intval >= 0);
8222    }
8223 
8224    for( i = 0; i < expr->nchildren; ++i )
8225       SCIPexprReindexParams(expr->children[i], newindices);
8226 }
8227 
8228 /** prints an expression */
SCIPexprPrint(SCIP_EXPR * expr,SCIP_MESSAGEHDLR * messagehdlr,FILE * file,const char ** varnames,const char ** paramnames,SCIP_Real * paramvals)8229 void SCIPexprPrint(
8230    SCIP_EXPR*            expr,               /**< expression */
8231    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
8232    FILE*                 file,               /**< file for printing, or NULL for stdout */
8233    const char**          varnames,           /**< names of variables, or NULL for default names */
8234    const char**          paramnames,         /**< names of parameters, or NULL for default names */
8235    SCIP_Real*            paramvals           /**< values of parameters, or NULL for not printing */
8236    )
8237 {
8238    assert( expr != NULL );
8239 
8240    switch( expr->op )
8241    {
8242       /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
8243        *        between 0 and number of params in the expression tree, if it uses the paramnames array
8244        *        because, here, we cannot get the values above we cannot assert them
8245        */
8246    case SCIP_EXPR_VARIDX:
8247       if( varnames != NULL )
8248       {
8249          assert(varnames[expr->data.intval] != NULL);
8250          SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
8251       }
8252       else
8253       {
8254          SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
8255       }
8256       break;
8257 
8258    case SCIP_EXPR_PARAM:
8259       if( paramnames != NULL )
8260       {
8261          assert(paramnames[expr->data.intval] != NULL);
8262          SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
8263       }
8264       else
8265       {
8266          SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
8267       }
8268       if( paramvals != NULL )
8269       {
8270          SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
8271       }
8272       break;
8273 
8274    case SCIP_EXPR_CONST:
8275       if (expr->data.dbl < 0.0 )
8276          SCIPmessageFPrintInfo(messagehdlr, file, "(%g)", expr->data.dbl );
8277       else
8278          SCIPmessageFPrintInfo(messagehdlr, file, "%g", expr->data.dbl );
8279       break;
8280 
8281    case SCIP_EXPR_PLUS:
8282       SCIPmessageFPrintInfo(messagehdlr, file, "(");
8283       SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8284       SCIPmessageFPrintInfo(messagehdlr, file, " + ");
8285       SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8286       SCIPmessageFPrintInfo(messagehdlr, file, ")");
8287       break;
8288 
8289    case SCIP_EXPR_MINUS:
8290       SCIPmessageFPrintInfo(messagehdlr, file, "(");
8291       SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8292       SCIPmessageFPrintInfo(messagehdlr, file, " - ");
8293       SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8294       SCIPmessageFPrintInfo(messagehdlr, file, ")");
8295       break;
8296 
8297    case SCIP_EXPR_MUL:
8298       SCIPmessageFPrintInfo(messagehdlr, file, "(");
8299       SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8300       SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8301       SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8302       SCIPmessageFPrintInfo(messagehdlr, file, ")");
8303       break;
8304 
8305    case SCIP_EXPR_DIV:
8306       SCIPmessageFPrintInfo(messagehdlr, file, "(");
8307       SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8308       SCIPmessageFPrintInfo(messagehdlr, file, " / ");
8309       SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8310       SCIPmessageFPrintInfo(messagehdlr, file, ")");
8311       break;
8312 
8313    case SCIP_EXPR_REALPOWER:
8314    case SCIP_EXPR_SIGNPOWER:
8315       SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8316       SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8317       SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
8318       break;
8319 
8320    case SCIP_EXPR_INTPOWER:
8321       SCIPmessageFPrintInfo(messagehdlr, file, "power(");
8322       SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8323       SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
8324       break;
8325 
8326    case SCIP_EXPR_SQUARE:
8327    case SCIP_EXPR_SQRT:
8328    case SCIP_EXPR_EXP:
8329    case SCIP_EXPR_LOG:
8330    case SCIP_EXPR_SIN:
8331    case SCIP_EXPR_COS:
8332    case SCIP_EXPR_TAN:
8333       /* case SCIP_EXPR_ERF: */
8334       /* case SCIP_EXPR_ERFI: */
8335    case SCIP_EXPR_MIN:
8336    case SCIP_EXPR_MAX:
8337    case SCIP_EXPR_ABS:
8338    case SCIP_EXPR_SIGN:
8339    {
8340       int i;
8341 
8342       SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8343 
8344       for( i = 0; i < expr->nchildren; ++i )
8345       {
8346          SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8347          if( i + 1 < expr->nchildren )
8348          {
8349             SCIPmessageFPrintInfo(messagehdlr, file, ", ");
8350          }
8351       }
8352 
8353       SCIPmessageFPrintInfo(messagehdlr, file, ")");
8354       break;
8355    }
8356 
8357    case SCIP_EXPR_SUM:
8358    case SCIP_EXPR_PRODUCT:
8359    {
8360       switch( expr->nchildren )
8361       {
8362       case 0:
8363          SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
8364          break;
8365       case 1:
8366          SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8367          break;
8368       default:
8369       {
8370          int i;
8371 
8372          SCIPmessageFPrintInfo(messagehdlr, file, "(");
8373          for( i = 0; i < expr->nchildren; ++i )
8374          {
8375             if( i > 0 )
8376             {
8377                SCIPmessageFPrintInfo(messagehdlr, file, "%s", expr->op == SCIP_EXPR_SUM ? " + " : " * ");
8378             }
8379             SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8380          }
8381          SCIPmessageFPrintInfo(messagehdlr, file, ")");
8382       }
8383       }
8384       break;
8385    }
8386 
8387    case SCIP_EXPR_LINEAR:
8388    {
8389       SCIP_Real constant;
8390       int i;
8391 
8392       constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
8393 
8394       if( expr->nchildren == 0 )
8395       {
8396          SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", constant);
8397          break;
8398       }
8399 
8400       SCIPmessageFPrintInfo(messagehdlr, file, "(");
8401 
8402       if( constant != 0.0 )
8403       {
8404          SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", constant);
8405       }
8406 
8407       for( i = 0; i < expr->nchildren; ++i )
8408       {
8409          SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", ((SCIP_Real*)expr->data.data)[i]);
8410          SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8411       }
8412 
8413       SCIPmessageFPrintInfo(messagehdlr, file, ")");
8414       break;
8415    }
8416 
8417    case SCIP_EXPR_QUADRATIC:
8418    {
8419       SCIP_EXPRDATA_QUADRATIC* quadraticdata;
8420       int i;
8421 
8422       quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
8423       assert(quadraticdata != NULL);
8424 
8425       SCIPmessageFPrintInfo(messagehdlr, file, "(");
8426 
8427       if( quadraticdata->constant != 0.0 )
8428          SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->constant);
8429 
8430       if( quadraticdata->lincoefs != NULL )
8431          for( i = 0; i < expr->nchildren; ++i )
8432          {
8433             if( quadraticdata->lincoefs[i] == 0.0 )
8434                continue;
8435             SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->lincoefs[i]);
8436             SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8437          }
8438 
8439       for( i = 0; i < quadraticdata->nquadelems; ++i )
8440       {
8441          SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->quadelems[i].coef);
8442          SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
8443          if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
8444          {
8445             SCIPmessageFPrintInfo(messagehdlr, file, "^2");
8446          }
8447          else
8448          {
8449             SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8450             SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
8451          }
8452       }
8453 
8454       SCIPmessageFPrintInfo(messagehdlr, file, ")");
8455       break;
8456    }
8457 
8458    case SCIP_EXPR_POLYNOMIAL:
8459    {
8460       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
8461       SCIP_EXPRDATA_MONOMIAL*   monomialdata;
8462       int i;
8463       int j;
8464 
8465       SCIPmessageFPrintInfo(messagehdlr, file, "(");
8466 
8467       polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
8468       assert(polynomialdata != NULL);
8469 
8470       if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
8471       {
8472          SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", polynomialdata->constant);
8473       }
8474 
8475       for( i = 0; i < polynomialdata->nmonomials; ++i )
8476       {
8477          monomialdata = polynomialdata->monomials[i];
8478          SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g", monomialdata->coef);
8479 
8480          for( j = 0; j < monomialdata->nfactors; ++j )
8481          {
8482             SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8483 
8484             SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
8485             if( monomialdata->exponents[j] < 0.0 )
8486             {
8487                SCIPmessageFPrintInfo(messagehdlr, file, "^(%.15g)", monomialdata->exponents[j]);
8488             }
8489             else if( monomialdata->exponents[j] != 1.0 )
8490             {
8491                SCIPmessageFPrintInfo(messagehdlr, file, "^%.15g", monomialdata->exponents[j]);
8492             }
8493          }
8494       }
8495 
8496       SCIPmessageFPrintInfo(messagehdlr, file, ")");
8497       break;
8498    }
8499 
8500    case SCIP_EXPR_USER:
8501    {
8502       SCIP_EXPRDATA_USER* exprdata;
8503       int i;
8504 
8505       exprdata = (SCIP_EXPRDATA_USER*)expr->data.data;
8506       assert(exprdata != NULL);
8507 
8508       if( exprdata->print != NULL )
8509       {
8510          exprdata->print(exprdata->userdata, messagehdlr, file);
8511       }
8512       else
8513       {
8514          SCIPmessageFPrintInfo(messagehdlr, file, "user");
8515       }
8516 
8517       SCIPmessageFPrintInfo(messagehdlr, file, "(");
8518       for( i = 0; i < expr->nchildren; ++i )
8519       {
8520          if( i > 0 )
8521          {
8522             SCIPmessageFPrintInfo(messagehdlr, file, ",");
8523          }
8524          SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8525       }
8526       SCIPmessageFPrintInfo(messagehdlr, file, ")");
8527 
8528       break;
8529    }
8530 
8531    case SCIP_EXPR_LAST:
8532    {
8533       SCIPerrorMessage("invalid expression\n");
8534       SCIPABORT();
8535    }
8536    }
8537 }
8538 
8539 /** parses an expression from a string */
SCIPexprParse(BMS_BLKMEM * blkmem,SCIP_MESSAGEHDLR * messagehdlr,SCIP_EXPR ** expr,const char * str,const char * lastchar,int * nvars,int * varnames,int varnameslength)8540 SCIP_RETCODE SCIPexprParse(
8541    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
8542    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
8543    SCIP_EXPR**           expr,               /**< buffer to store pointer to created expression */
8544    const char*           str,                /**< pointer to the string to be parsed */
8545    const char*           lastchar,           /**< pointer to the last char of str that should be parsed */
8546    int*                  nvars,              /**< buffer to store number of variables */
8547    int*                  varnames,           /**< buffer to store variable names, prefixed by index (as int) */
8548    int                   varnameslength      /**< length of the varnames buffer array */
8549    )
8550 {
8551    SCIP_HASHTABLE* vartable;
8552    SCIP_RETCODE retcode;
8553 
8554    assert(blkmem != NULL);
8555    assert(expr != NULL);
8556    assert(str != NULL);
8557    assert(lastchar != NULL);
8558    assert(nvars != NULL);
8559    assert(varnames != NULL);
8560 
8561    *nvars = 0;
8562 
8563    /* create a hash table for variable names and corresponding expression index
8564     * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
8565     */
8566    SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString,
8567          SCIPhashKeyValString, NULL) );
8568 
8569    retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames,
8570       &varnameslength, vartable, 0);
8571 
8572    SCIPhashtableFree(&vartable);
8573 
8574    return retcode;
8575 }
8576 
8577 
8578 /**@} */
8579 
8580 /**@name Expression tree methods */
8581 /**@{ */
8582 
8583 /* In debug mode, the following methods are implemented as function calls to ensure
8584  * type validity.
8585  * In optimized mode, the methods are implemented as defines to improve performance.
8586  * However, we want to have them in the library anyways, so we have to undef the defines.
8587  */
8588 
8589 #undef SCIPexprtreeGetRoot
8590 #undef SCIPexprtreeGetNVars
8591 #undef SCIPexprtreeGetNParams
8592 #undef SCIPexprtreeGetParamVals
8593 #undef SCIPexprtreeSetParamVal
8594 #undef SCIPexprtreeGetInterpreterData
8595 #undef SCIPexprtreeSetInterpreterData
8596 #undef SCIPexprtreeFreeInterpreterData
8597 #undef SCIPexprtreeHasParam
8598 #undef SCIPexprtreeGetMaxDegree
8599 #undef SCIPexprtreeEval
8600 #undef SCIPexprtreeEvalInt
8601 #undef SCIPexprtreePrint
8602 
8603 /** returns root expression of an expression tree */
SCIPexprtreeGetRoot(SCIP_EXPRTREE * tree)8604 SCIP_EXPR* SCIPexprtreeGetRoot(
8605    SCIP_EXPRTREE*        tree                /**< expression tree */
8606    )
8607 {
8608    assert(tree != NULL);
8609 
8610    return tree->root;
8611 }
8612 
8613 /** returns number of variables in expression tree */
SCIPexprtreeGetNVars(SCIP_EXPRTREE * tree)8614 int SCIPexprtreeGetNVars(
8615    SCIP_EXPRTREE*        tree                /**< expression tree */
8616    )
8617 {
8618    assert(tree != NULL);
8619 
8620    return tree->nvars;
8621 }
8622 
8623 /** returns number of parameters in expression tree */
SCIPexprtreeGetNParams(SCIP_EXPRTREE * tree)8624 int SCIPexprtreeGetNParams(
8625    SCIP_EXPRTREE*        tree                /**< expression tree */
8626    )
8627 {
8628    assert(tree != NULL);
8629 
8630    return tree->nparams;
8631 }
8632 
8633 /** returns values of parameters or NULL if none */
SCIPexprtreeGetParamVals(SCIP_EXPRTREE * tree)8634 SCIP_Real* SCIPexprtreeGetParamVals(
8635    SCIP_EXPRTREE*        tree                /**< expression tree */
8636    )
8637 {
8638    assert(tree != NULL);
8639 
8640    return tree->params;
8641 }
8642 
8643 /** sets value of a single parameter in expression tree */
SCIPexprtreeSetParamVal(SCIP_EXPRTREE * tree,int paramidx,SCIP_Real paramval)8644 void SCIPexprtreeSetParamVal(
8645    SCIP_EXPRTREE*        tree,               /**< expression tree */
8646    int                   paramidx,           /**< index of parameter */
8647    SCIP_Real             paramval            /**< new value of parameter */
8648    )
8649 {
8650    assert(tree != NULL);
8651    assert(paramidx >= 0);
8652    assert(paramidx < tree->nparams);
8653    assert(tree->params != NULL);
8654 
8655    tree->params[paramidx] = paramval;
8656 }
8657 
8658 /** gets data of expression tree interpreter, or NULL if not set */
SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE * tree)8659 SCIP_EXPRINTDATA* SCIPexprtreeGetInterpreterData(
8660    SCIP_EXPRTREE*        tree                /**< expression tree */
8661    )
8662 {
8663    assert(tree != NULL);
8664 
8665    return tree->interpreterdata;
8666 }
8667 
8668 /** sets data of expression tree interpreter */
SCIPexprtreeSetInterpreterData(SCIP_EXPRTREE * tree,SCIP_EXPRINTDATA * interpreterdata)8669 void SCIPexprtreeSetInterpreterData(
8670    SCIP_EXPRTREE*        tree,               /**< expression tree */
8671    SCIP_EXPRINTDATA*     interpreterdata     /**< expression interpreter data */
8672    )
8673 {
8674    assert(tree != NULL);
8675    assert(interpreterdata != NULL);
8676    assert(tree->interpreterdata == NULL);
8677 
8678    tree->interpreterdata = interpreterdata;
8679 }
8680 
8681 /** frees data of expression tree interpreter, if any */
SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE * tree)8682 SCIP_RETCODE SCIPexprtreeFreeInterpreterData(
8683    SCIP_EXPRTREE*        tree                /**< expression tree */
8684    )
8685 {
8686    if( tree->interpreterdata != NULL )
8687    {
8688       SCIP_CALL( SCIPexprintFreeData(&tree->interpreterdata) );
8689       assert(tree->interpreterdata == NULL);
8690    }
8691 
8692    return SCIP_OKAY;
8693 }
8694 
8695 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
SCIPexprtreeHasParam(SCIP_EXPRTREE * tree)8696 SCIP_Bool SCIPexprtreeHasParam(
8697    SCIP_EXPRTREE*        tree                /**< expression tree */
8698    )
8699 {
8700    assert(tree != NULL);
8701 
8702    return SCIPexprHasParam(tree->root);
8703 }
8704 
8705 /** Gives maximal degree of expression in expression tree.
8706  *
8707  *  If constant expression, gives 0,
8708  *  if linear expression, gives 1,
8709  *  if polynomial expression, gives its maximal degree,
8710  *  otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8711  */
SCIPexprtreeGetMaxDegree(SCIP_EXPRTREE * tree,int * maxdegree)8712 SCIP_RETCODE SCIPexprtreeGetMaxDegree(
8713    SCIP_EXPRTREE*        tree,               /**< expression tree */
8714    int*                  maxdegree           /**< buffer to store maximal degree */
8715    )
8716 {
8717    assert(tree != NULL);
8718 
8719    SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8720 
8721    return SCIP_OKAY;
8722 }
8723 
8724 /** evaluates an expression tree w.r.t. a point */
SCIPexprtreeEval(SCIP_EXPRTREE * tree,SCIP_Real * varvals,SCIP_Real * val)8725 SCIP_RETCODE SCIPexprtreeEval(
8726    SCIP_EXPRTREE*        tree,               /**< expression tree */
8727    SCIP_Real*            varvals,            /**< values for variables */
8728    SCIP_Real*            val                 /**< buffer to store expression tree value */
8729    )
8730 {
8731    assert(tree    != NULL);
8732    assert(varvals != NULL || tree->nvars == 0);
8733    assert(val     != NULL);
8734 
8735    SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8736 
8737    return SCIP_OKAY;
8738 }
8739 
8740 /** evaluates an expression tree w.r.t. an interval */
SCIPexprtreeEvalInt(SCIP_EXPRTREE * tree,SCIP_Real infinity,SCIP_INTERVAL * varvals,SCIP_INTERVAL * val)8741 SCIP_RETCODE SCIPexprtreeEvalInt(
8742    SCIP_EXPRTREE*        tree,               /**< expression tree */
8743    SCIP_Real             infinity,           /**< value for infinity */
8744    SCIP_INTERVAL*        varvals,            /**< intervals for variables */
8745    SCIP_INTERVAL*        val                 /**< buffer to store expression tree value */
8746    )
8747 {
8748    assert(tree    != NULL);
8749    assert(varvals != NULL || tree->nvars == 0);
8750    assert(val     != NULL);
8751 
8752    SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8753 
8754    return SCIP_OKAY;
8755 }
8756 
8757 /** prints an expression tree */
SCIPexprtreePrint(SCIP_EXPRTREE * tree,SCIP_MESSAGEHDLR * messagehdlr,FILE * file,const char ** varnames,const char ** paramnames)8758 void SCIPexprtreePrint(
8759    SCIP_EXPRTREE*        tree,               /**< expression tree */
8760    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
8761    FILE*                 file,               /**< file for printing, or NULL for stdout */
8762    const char**          varnames,           /**< names of variables, or NULL for default names */
8763    const char**          paramnames          /**< names of parameters, or NULL for default names */
8764    )
8765 {
8766    assert(tree != NULL);
8767 
8768    SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8769 }
8770 
8771 
8772 /** creates an expression tree */
SCIPexprtreeCreate(BMS_BLKMEM * blkmem,SCIP_EXPRTREE ** tree,SCIP_EXPR * root,int nvars,int nparams,SCIP_Real * params)8773 SCIP_RETCODE SCIPexprtreeCreate(
8774    BMS_BLKMEM*           blkmem,             /**< block memory data structure */
8775    SCIP_EXPRTREE**       tree,               /**< buffer to store address of created expression tree */
8776    SCIP_EXPR*            root,               /**< pointer to root expression, not copied deep !, can be NULL */
8777    int                   nvars,              /**< number of variables in variable mapping */
8778    int                   nparams,            /**< number of parameters in expression */
8779    SCIP_Real*            params              /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8780    )
8781 {
8782    assert(blkmem != NULL);
8783    assert(tree   != NULL);
8784 
8785    SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8786 
8787    (*tree)->blkmem    = blkmem;
8788    (*tree)->root      = root;
8789    (*tree)->nvars     = nvars;
8790    (*tree)->vars      = NULL;
8791    (*tree)->nparams   = nparams;
8792    (*tree)->interpreterdata = NULL;
8793 
8794    if( params != NULL )
8795    {
8796       assert(nparams > 0);
8797       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8798    }
8799    else if( nparams > 0 )
8800    {
8801       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8802       BMSclearMemoryArray((*tree)->params, nparams);
8803    }
8804    else
8805    {
8806       assert(nparams == 0);
8807       (*tree)->params = NULL;
8808    }
8809 
8810    return SCIP_OKAY;
8811 }
8812 
8813 /** copies an expression tree */
SCIPexprtreeCopy(BMS_BLKMEM * blkmem,SCIP_EXPRTREE ** targettree,SCIP_EXPRTREE * sourcetree)8814 SCIP_RETCODE SCIPexprtreeCopy(
8815    BMS_BLKMEM*           blkmem,             /**< block memory that should be used in new expression tree */
8816    SCIP_EXPRTREE**       targettree,         /**< buffer to store address of copied expression tree */
8817    SCIP_EXPRTREE*        sourcetree          /**< expression tree to copy */
8818    )
8819 {
8820    assert(blkmem     != NULL);
8821    assert(targettree != NULL);
8822    assert(sourcetree != NULL);
8823 
8824    /* copy expression tree "header" */
8825    SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8826 
8827    /* we may have a new block memory; and we do not want to keep the others interpreter data */
8828    (*targettree)->blkmem          = blkmem;
8829    (*targettree)->interpreterdata = NULL;
8830 
8831    /* copy variables, if any */
8832    if( sourcetree->vars != NULL )
8833    {
8834       assert(sourcetree->nvars > 0);
8835 
8836       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8837    }
8838 
8839    /* copy parameters, if any */
8840    if( sourcetree->params != NULL )
8841    {
8842       assert(sourcetree->nparams > 0);
8843 
8844       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8845    }
8846 
8847    /* copy expression */
8848    SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8849 
8850    return SCIP_OKAY;
8851 }
8852 
8853 /** frees an expression tree */
SCIPexprtreeFree(SCIP_EXPRTREE ** tree)8854 SCIP_RETCODE SCIPexprtreeFree(
8855    SCIP_EXPRTREE**       tree                /**< pointer to expression tree that is freed */
8856    )
8857 {
8858    assert( tree != NULL);
8859    assert(*tree != NULL);
8860 
8861    SCIP_CALL( SCIPexprtreeFreeInterpreterData(*tree) );
8862 
8863    if( (*tree)->root != NULL )
8864    {
8865       SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8866       assert((*tree)->root == NULL);
8867    }
8868 
8869    BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars,   (*tree)->nvars  );
8870    BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8871 
8872    BMSfreeBlockMemory((*tree)->blkmem, tree);
8873 
8874    return SCIP_OKAY;
8875 }
8876 
8877 /** sets number and values of all parameters in expression tree */
SCIPexprtreeSetParams(SCIP_EXPRTREE * tree,int nparams,SCIP_Real * paramvals)8878 SCIP_RETCODE SCIPexprtreeSetParams(
8879    SCIP_EXPRTREE*        tree,               /**< expression tree */
8880    int                   nparams,            /**< number of parameters */
8881    SCIP_Real*            paramvals           /**< values of parameters, can be NULL if nparams == 0 */
8882    )
8883 {
8884    assert(tree != NULL);
8885    assert(paramvals != NULL || nparams == 0);
8886 
8887    if( nparams == 0 )
8888    {
8889       BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8890    }
8891    else if( tree->params != NULL )
8892    {
8893       SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8894       BMScopyMemoryArray(tree->params, paramvals, nparams);
8895    }
8896    else
8897    {
8898       SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8899    }
8900 
8901    tree->nparams = nparams;
8902    assert(tree->params != NULL || tree->nparams == 0);
8903 
8904    return SCIP_OKAY;
8905 }
8906 
8907 
8908 /** gives the number of usages for each variable in the expression tree */
SCIPexprtreeGetVarsUsage(SCIP_EXPRTREE * tree,int * varsusage)8909 void SCIPexprtreeGetVarsUsage(
8910    SCIP_EXPRTREE*        tree,               /**< expression tree */
8911    int*                  varsusage           /**< array where to store for each variable how often it is used in the tree */
8912    )
8913 {
8914    assert(tree != NULL);
8915    assert(varsusage != NULL);
8916 
8917    if( tree->nvars == 0 )
8918       return;
8919 
8920    BMSclearMemoryArray(varsusage, tree->nvars);
8921    SCIPexprGetVarsUsage(tree->root, varsusage);
8922 }
8923 
8924 /** aims at simplifying an expression and splitting of a linear expression
8925  *
8926  *  If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8927  */
SCIPexprtreeSimplify(SCIP_EXPRTREE * tree,SCIP_MESSAGEHDLR * messagehdlr,SCIP_Real eps,int maxexpansionexponent,int * nlinvars,int * linidxs,SCIP_Real * lincoefs)8928 SCIP_RETCODE SCIPexprtreeSimplify(
8929    SCIP_EXPRTREE*        tree,               /**< expression tree */
8930    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
8931    SCIP_Real             eps,                /**< threshold, under which positive values are treat as 0 */
8932    int                   maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8933    int*                  nlinvars,           /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8934    int*                  linidxs,            /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8935    SCIP_Real*            lincoefs            /**< array to store coefficients of linear part, or NULL */
8936    )
8937 {
8938 #ifndef NDEBUG
8939    SCIP_RANDNUMGEN* randnumgen;
8940    SCIP_Real* testx;
8941    SCIP_Real testval_before;
8942    SCIP_Real testval_after;
8943    int i;
8944 #endif
8945 
8946    assert(tree != NULL);
8947 
8948 #ifndef NDEBUG
8949    SCIP_CALL( SCIPrandomCreate(&randnumgen, tree->blkmem, 42) );
8950 
8951    SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) );  /*lint !e666*/
8952    for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8953       testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0);  /*lint !e644*/
8954    SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8955 
8956    SCIPrandomFree(&randnumgen, tree->blkmem);
8957 #endif
8958 
8959    /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8960    SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8961 
8962 #ifndef NDEBUG
8963    SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8964    if( nlinvars != NULL && testval_before == testval_before )  /*lint !e777*/
8965       for( i = 0; i < *nlinvars; ++i )
8966          testval_after += lincoefs[i] * testx[linidxs[i]];
8967    assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps));  /*lint !e777*/
8968    BMSfreeMemoryArray(&testx);
8969 #endif
8970 
8971    /* removing something from the the tree may invalidate the interpreter data */
8972    if( nlinvars != NULL && *nlinvars > 0 )
8973       SCIP_CALL( SCIPexprtreeFreeInterpreterData(tree) );
8974 
8975    return SCIP_OKAY;
8976 }
8977 
8978 /** adds an expression to the root expression of the tree
8979  *
8980  *  The root is replaced with an SCIP_EXPR_PLUS expression which has the previous root and the given expression (or a copy of it) as children.
8981  *  If no root existed yet, then the root is set to the given expression (or a copy of it).
8982  */
SCIPexprtreeAddExpr(SCIP_EXPRTREE * tree,SCIP_EXPR * expr,SCIP_Bool copyexpr)8983 SCIP_RETCODE SCIPexprtreeAddExpr(
8984    SCIP_EXPRTREE*        tree,               /**< expression tree */
8985    SCIP_EXPR*            expr,               /**< expression to add to tree */
8986    SCIP_Bool             copyexpr            /**< whether expression should be copied */
8987    )
8988 {
8989    assert(tree != NULL);
8990 
8991    /* adding something to the tree may invalidate the interpreter data */
8992    SCIP_CALL( SCIPexprtreeFreeInterpreterData(tree) );
8993 
8994    if( copyexpr )
8995    {
8996       SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8997    }
8998 
8999    if( tree->root == NULL )
9000    {
9001       tree->root = expr;
9002    }
9003    else
9004    {
9005       SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
9006    }
9007 
9008    return SCIP_OKAY;
9009 }
9010 
9011 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
SCIPexprtreeCheckCurvature(SCIP_EXPRTREE * tree,SCIP_Real infinity,SCIP_INTERVAL * varbounds,SCIP_EXPRCURV * curv,SCIP_INTERVAL * bounds)9012 SCIP_RETCODE SCIPexprtreeCheckCurvature(
9013    SCIP_EXPRTREE*        tree,               /**< expression tree */
9014    SCIP_Real             infinity,           /**< value for infinity */
9015    SCIP_INTERVAL*        varbounds,          /**< domains of variables */
9016    SCIP_EXPRCURV*        curv,               /**< buffer to store curvature of expression */
9017    SCIP_INTERVAL*        bounds              /**< buffer to store bounds on expression, or NULL if not needed */
9018    )
9019 {
9020    SCIP_INTERVAL exprbounds;
9021 
9022    assert(tree != NULL);
9023 
9024    if( tree->root == NULL )
9025    {
9026       *curv = SCIP_EXPRCURV_LINEAR;
9027 
9028       if( bounds != NULL )
9029          SCIPintervalSet(bounds, 0.0);
9030 
9031       return SCIP_OKAY;
9032    }
9033 
9034    SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
9035 
9036    if( bounds != NULL )
9037       *bounds = exprbounds;
9038 
9039    return SCIP_OKAY;
9040 }
9041 
9042 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
9043  *
9044  *  A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
9045  *  If substexprs[i] == NULL, then the variable expression i is not touched.
9046  */
SCIPexprtreeSubstituteVars(SCIP_EXPRTREE * tree,SCIP_EXPR ** substexprs)9047 SCIP_RETCODE SCIPexprtreeSubstituteVars(
9048    SCIP_EXPRTREE*        tree,               /**< expression tree */
9049    SCIP_EXPR**           substexprs          /**< array of substitute expressions; single entries can be NULL */
9050    )
9051 {
9052    assert(tree != NULL);
9053 
9054    if( tree->root == NULL )
9055       return SCIP_OKAY;
9056 
9057    if( tree->root->op == SCIP_EXPR_VARIDX )
9058    {
9059       int varidx;
9060 
9061       varidx = tree->root->data.intval;
9062       assert(varidx >= 0);
9063       if( substexprs[varidx] != NULL )
9064       {
9065          /* substitute root expression */
9066          SCIPexprFreeDeep(tree->blkmem, &tree->root);
9067          SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
9068       }
9069    }
9070    else
9071    {
9072       /* check children (and grandchildren and so on...) of root expression */
9073       SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
9074    }
9075 
9076    /* substitution of variables should invalidate interpreter data */
9077    SCIP_CALL( SCIPexprtreeFreeInterpreterData(tree) );
9078 
9079    return SCIP_OKAY;
9080 }
9081 
9082 /**@} */
9083 
9084 /**@name Quadratic element methods */
9085 /**@{ */
9086 
9087 /** comparing two quadratic elements
9088  *
9089  *  a is better than b if index1 of a is smaller than index1 of b or index1 of both is equal but index2 of a is smaller than index2 of b
9090  */
9091 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
9092 
9093 /** swaps two quadratic elements */
9094 #define QUADELEMS_SWAP(x,y)                     \
9095    {                                            \
9096       SCIP_QUADELEM temp = x;                   \
9097       x = y;                                    \
9098       y = temp;                                 \
9099    }
9100 
9101 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
9102 static
quadelemsQuickSort(SCIP_QUADELEM * elems,int start,int end)9103 void quadelemsQuickSort(
9104    SCIP_QUADELEM*        elems,              /**< array to be sorted */
9105    int                   start,              /**< starting index */
9106    int                   end                 /**< ending index */
9107    )
9108 {
9109    assert(start <= end);
9110 
9111    /* use quick sort for long lists */
9112    while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
9113    {
9114       SCIP_QUADELEM pivotkey;
9115       int lo;
9116       int hi;
9117       int mid;
9118 
9119       /* select pivot element */
9120       mid = (start+end)/2;
9121       pivotkey = elems[mid];
9122 
9123       /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
9124       lo = start;
9125       hi = end;
9126       for( ;; )
9127       {
9128          while( lo < end   &&  QUADELEMS_ISBETTER(elems[lo], pivotkey) )
9129             lo++;
9130          while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
9131             hi--;
9132 
9133          if( lo >= hi )
9134             break;
9135 
9136          QUADELEMS_SWAP(elems[lo], elems[hi]);
9137 
9138          lo++;
9139          hi--;
9140       }
9141       assert(hi == lo-1 || hi == start);
9142 
9143       /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
9144       while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
9145          lo++;
9146 
9147       /* make sure that we have at least one element in the smaller partition */
9148       if( lo == start )
9149       {
9150          /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
9151          assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
9152          assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
9153          QUADELEMS_SWAP(elems[lo], elems[mid]);
9154          lo++;
9155       }
9156 
9157       /* sort the smaller partition by a recursive call, sort the larger part without recursion */
9158       if( hi - start <= end - lo )
9159       {
9160          /* sort [start,hi] with a recursive call */
9161          if( start < hi )
9162             quadelemsQuickSort(elems, start, hi);
9163 
9164          /* now focus on the larger part [lo,end] */
9165          start = lo;
9166       }
9167       else
9168       {
9169          /* sort [lo,end] with a recursive call */
9170          if( lo < end )
9171             quadelemsQuickSort(elems, lo, end);
9172 
9173          /* now focus on the larger part [start,hi] */
9174          end = hi;
9175       }
9176    }
9177 
9178    /* use shell sort on the remaining small list */
9179    if( end - start >= 1 )
9180    {
9181       static const int incs[3] = {1, 5, 19}; /* sequence of increments */
9182       int k;
9183 
9184       for( k = 2; k >= 0; --k )
9185       {
9186          int h;
9187          int i;
9188 
9189          for( h = incs[k], i = h + start; i <= end; ++i )
9190          {
9191             int j;
9192             SCIP_QUADELEM tempkey = elems[i];
9193 
9194             j = i;
9195             while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
9196             {
9197                elems[j] = elems[j-h];
9198                j -= h;
9199             }
9200 
9201             elems[j] = tempkey;
9202          }
9203       }
9204    }
9205 }
9206 
9207 /** sorts an array of quadratic elements
9208  *
9209  *  The elements are sorted such that the first index is increasing and
9210  *  such that among elements with the same first index, the second index is increasing.
9211  *  For elements with same first and second index, the order is not defined.
9212  */
SCIPquadelemSort(SCIP_QUADELEM * quadelems,int nquadelems)9213 void SCIPquadelemSort(
9214    SCIP_QUADELEM*        quadelems,          /**< array of quadratic elements */
9215    int                   nquadelems          /**< number of quadratic elements */
9216    )
9217 {
9218    if( nquadelems == 0 )
9219       return;
9220 
9221 #ifndef NDEBUG
9222    {
9223       int i;
9224       for( i = 0; i < nquadelems; ++i )
9225          assert(quadelems[i].idx1 <= quadelems[i].idx2);
9226    }
9227 #endif
9228 
9229    quadelemsQuickSort(quadelems, 0, nquadelems-1);
9230 }
9231 
9232 /** Finds an index pair in a sorted array of quadratic elements.
9233  *
9234  *  If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
9235  *  If (idx1,idx2) is not found in quadelems, then returns FALSE and stores position where a quadratic element with these indices would be inserted in *pos.
9236  *  Assumes that idx1 <= idx2.
9237  */
SCIPquadelemSortedFind(SCIP_QUADELEM * quadelems,int idx1,int idx2,int nquadelems,int * pos)9238 SCIP_Bool SCIPquadelemSortedFind(
9239    SCIP_QUADELEM*        quadelems,          /**< array of quadratic elements */
9240    int                   idx1,               /**< index of first  variable in element to search for */
9241    int                   idx2,               /**< index of second variable in element to search for */
9242    int                   nquadelems,         /**< number of quadratic elements in array */
9243    int*                  pos                 /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
9244    )
9245 {
9246    int left;
9247    int right;
9248 
9249    assert(quadelems != NULL || nquadelems == 0);
9250    assert(idx1 <= idx2);
9251 
9252    if( nquadelems == 0 )
9253    {
9254       if( pos != NULL )
9255          *pos = 0;
9256       return FALSE;
9257    }
9258 
9259    left = 0;
9260    right = nquadelems - 1;
9261    while( left <= right )
9262    {
9263       int middle;
9264 
9265       middle = (left+right)/2;
9266       assert(0 <= middle && middle < nquadelems);
9267 
9268       if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) )  /*lint !e613*/
9269          right = middle - 1;
9270       else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) )  /*lint !e613*/
9271          left  = middle + 1;
9272       else
9273       {
9274          if( pos != NULL )
9275             *pos = middle;
9276          return TRUE;
9277       }
9278    }
9279    assert(left == right+1);
9280 
9281    if( pos != NULL )
9282       *pos = left;
9283    return FALSE;
9284 }
9285 
9286 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
9287  *
9288  *  Assumes that elements have been sorted before.
9289  */
SCIPquadelemSqueeze(SCIP_QUADELEM * quadelems,int nquadelems,int * nquadelemsnew)9290 void SCIPquadelemSqueeze(
9291    SCIP_QUADELEM*        quadelems,          /**< array of quadratic elements */
9292    int                   nquadelems,         /**< number of quadratic elements */
9293    int*                  nquadelemsnew       /**< pointer to store new (reduced) number of quadratic elements */
9294    )
9295 {
9296    int i;
9297    int next;
9298 
9299    assert(quadelems     != NULL);
9300    assert(nquadelemsnew != NULL);
9301    assert(nquadelems    >= 0);
9302 
9303    i = 0;
9304    next = 0;
9305    while( next < nquadelems )
9306    {
9307       /* assert that array is sorted */
9308       assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
9309          (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
9310 
9311       /* skip elements with coefficient 0.0 */
9312       if( quadelems[next].coef == 0.0 )
9313       {
9314          ++next;
9315          continue;
9316       }
9317 
9318       /* if next element has same index as previous one, add it to the previous one */
9319       if( i >= 1 &&
9320          quadelems[i-1].idx1 == quadelems[next].idx1 &&
9321          quadelems[i-1].idx2 == quadelems[next].idx2 )
9322       {
9323          quadelems[i-1].coef += quadelems[next].coef;
9324          ++next;
9325          continue;
9326       }
9327 
9328       /* otherwise, move next element to current position */
9329       quadelems[i] = quadelems[next];
9330       ++i;
9331       ++next;
9332    }
9333    assert(next == nquadelems);
9334 
9335    /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
9336    *nquadelemsnew = i;
9337 }
9338 
9339 /**@} */
9340 
9341 /**@name Expression graph node private methods */
9342 /**@{ */
9343 
9344 /** adds a parent to an expression graph node */
9345 static
exprgraphNodeAddParent(BMS_BLKMEM * blkmem,SCIP_EXPRGRAPHNODE * node,SCIP_EXPRGRAPHNODE * parent)9346 SCIP_RETCODE exprgraphNodeAddParent(
9347    BMS_BLKMEM*           blkmem,             /**< block memory */
9348    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node where to add a parent */
9349    SCIP_EXPRGRAPHNODE*   parent              /**< parent node */
9350    )
9351 {
9352    assert(blkmem != NULL);
9353    assert(node != NULL);
9354    assert(node->depth >= 0);
9355    assert(node->pos >= 0);
9356    assert(parent != NULL);
9357    assert(parent->depth >= 0);
9358    assert(parent->pos >= 0);
9359    assert(parent->depth > node->depth); /* a parent node need to have larger depth */
9360 
9361    ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
9362    assert(node->nparents < node->parentssize);
9363 
9364    node->parents[node->nparents] = parent;
9365    ++node->nparents;
9366 
9367    /* update sorted flag */
9368    node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (exprgraphnodecomp((void*)node->parents[node->nparents-2], (void*)parent) <= 0));
9369 
9370    return SCIP_OKAY;
9371 }
9372 
9373 /** ensures that array of parents in a node is sorted */
9374 static
exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE * node)9375 void exprgraphNodeSortParents(
9376    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
9377    )
9378 {
9379    assert(node != NULL);
9380 
9381    if( node->parentssorted )
9382    {
9383 #ifndef NDEBUG
9384       int i;
9385       for( i = 1; i < node->nparents; ++i )
9386          assert(exprgraphnodecomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
9387 #endif
9388       return;
9389    }
9390 
9391    SCIPsortPtr((void**)node->parents, exprgraphnodecomp, node->nparents);
9392 
9393    node->parentssorted = TRUE;
9394 }
9395 
9396 /** removes a parent from an expression graph node
9397  *
9398  *  If the node is not used and has no other parents, then it is freed.
9399  */
9400 static
exprgraphNodeRemoveParent(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE ** node,SCIP_EXPRGRAPHNODE * parent)9401 SCIP_RETCODE exprgraphNodeRemoveParent(
9402    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
9403    SCIP_EXPRGRAPHNODE**  node,               /**< expression graph node where to remove a parent, *node will be set to NULL */
9404    SCIP_EXPRGRAPHNODE*   parent              /**< parent node to remove */
9405    )
9406 {
9407    SCIP_EXPRGRAPHNODE* node_;
9408    int pos;
9409    int i;
9410 
9411    assert(exprgraph != NULL);
9412    assert(node != NULL);
9413    assert(*node != NULL);
9414    assert((*node)->depth >= 0);
9415    assert((*node)->pos >= 0);
9416    assert((*node)->nparents > 0);
9417    assert(parent != NULL);
9418    assert(parent->depth >= 0);
9419    assert(parent->pos >= 0);
9420    assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
9421 
9422    /* find parent */
9423    exprgraphNodeSortParents(*node);
9424    (void) SCIPsortedvecFindPtr((void**)(*node)->parents, exprgraphnodecomp, (void*)parent, (*node)->nparents, &pos);
9425    assert(pos >= 0);
9426    assert(pos < (*node)->nparents);
9427    assert((*node)->parents[pos] == parent);
9428 
9429 #ifdef SCIP_DISABLED_CODE
9430    /* move last parent to pos, if pos is before last
9431     * update sorted flag */
9432    if( pos < (*node)->nparents-1 )
9433    {
9434       (*node)->parents[pos]  = (*node)->parents[(*node)->nparents-1];
9435       (*node)->parentssorted = ((*node)->nparents <= 2);
9436    }
9437 #else
9438    /* move all parents behind pos one position up
9439     * this is faster than moving the last parent to position pos if there are many repeated calls to this function as the parents array remains sorted
9440     */
9441    for( i = pos+1; i < (*node)->nparents; ++i )
9442       (*node)->parents[i-1] = (*node)->parents[i];
9443 #endif
9444    --(*node)->nparents;
9445 
9446    /* keep pointer to *node in case it is still used */
9447    node_ = (*node)->nuses > 0 ? *node : NULL;
9448 
9449    /* capture and release node so it is freed if possible */
9450    SCIPexprgraphCaptureNode(*node);
9451    SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
9452 
9453    /* restore pointer, if node still exists */
9454    *node = node_;
9455 
9456    return SCIP_OKAY;
9457 }
9458 
9459 /** checks if a node is parent of a node */
9460 static
exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE * node,SCIP_EXPRGRAPHNODE * parent)9461 SCIP_Bool exprgraphNodeIsParent(
9462    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node */
9463    SCIP_EXPRGRAPHNODE*   parent              /**< parent to look for */
9464    )
9465 {
9466    int pos;
9467 
9468    assert(node   != NULL);
9469    assert(parent != NULL);
9470 
9471    /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
9472    if( node->depth >= parent->depth || node->nparents == 0 )
9473       return FALSE;
9474    assert(node->parents != NULL);
9475 
9476    /* ensure parents array is sorted */
9477    exprgraphNodeSortParents(node);
9478 
9479    return SCIPsortedvecFindPtr((void**)node->parents, exprgraphnodecomp, (void*)parent, node->nparents, &pos);
9480 }
9481 
9482 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
9483  *
9484  *  For a sum or product expression, this corresponds to add additional summands and factors, resp.
9485  *  For a linear expression, this corresponds to add each expression with coefficient 1.0.
9486  *  For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
9487  *
9488  *  It is assumed that node and all exprs are in the expression graph already.
9489  *  It is assumed that all expressions that are added have lower depth than node.
9490  */
9491 static
exprgraphNodeAddChildren(BMS_BLKMEM * blkmem,SCIP_EXPRGRAPHNODE * node,int nexprs,SCIP_EXPRGRAPHNODE ** exprs,int * childmap)9492 SCIP_RETCODE exprgraphNodeAddChildren(
9493    BMS_BLKMEM*           blkmem,             /**< block memory */
9494    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node */
9495    int                   nexprs,             /**< number of children to add */
9496    SCIP_EXPRGRAPHNODE**  exprs,              /**< children nodes to add */
9497    int*                  childmap            /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
9498    )
9499 {
9500    int i;
9501    int j;
9502    int orignchildren;
9503    SCIP_Bool existsalready;
9504 
9505    assert(blkmem != NULL);
9506    assert(node != NULL);
9507    assert(node->depth > 0);
9508    assert(node->pos >= 0);
9509    assert(node->op == SCIP_EXPR_SUM || node->op == SCIP_EXPR_PRODUCT || node->op == SCIP_EXPR_LINEAR || node->op == SCIP_EXPR_QUADRATIC || node->op == SCIP_EXPR_POLYNOMIAL);
9510    assert(exprs != NULL || nexprs == 0);
9511 
9512    if( nexprs == 0 )
9513       return SCIP_OKAY;
9514 
9515    orignchildren = node->nchildren;
9516    SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
9517 
9518    for( i = 0; i < nexprs; ++i )
9519    {
9520       assert(exprs[i]->depth >= 0);           /*lint !e613*/
9521       assert(exprs[i]->pos >= 0);             /*lint !e613*/
9522       assert(exprs[i]->depth < node->depth);  /*lint !e613*/
9523 
9524       /* check if exprs[i] is a child already, if not SUM or PRODUCT */
9525       existsalready = FALSE;
9526       if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
9527          for( j = 0; j < orignchildren; ++j )
9528             /* during simplification of polynomials, their may be NULL's in children array */
9529             if( node->children[j] != NULL && node->children[j] == exprs[i] )  /*lint !e613*/
9530             {
9531                existsalready = TRUE;
9532                break;
9533             }
9534 
9535       if( !existsalready )
9536       {
9537          /* add exprs[i] to children array */
9538          node->children[node->nchildren] = exprs[i];  /*lint !e613*/
9539          SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) );  /*lint !e613*/
9540          if( childmap != NULL )
9541             childmap[i] = node->nchildren;
9542          ++node->nchildren;
9543       }
9544       else
9545       {
9546          if( childmap != NULL )
9547             childmap[i] = j;  /*lint !e644*/
9548          if( node->op == SCIP_EXPR_LINEAR )
9549          {
9550             /* if linear expression, increase coefficient by 1.0 */
9551             ((SCIP_Real*)node->data.data)[j] += 1.0;
9552          }
9553       }
9554    }
9555 
9556    /* shrink children array to actually used size */
9557    SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
9558 
9559    if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
9560    {
9561       /* if linear expression, then add 1.0 coefficients for new expressions */
9562       SCIP_Real* data;
9563 
9564       data = (SCIP_Real*)node->data.data;
9565       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
9566       data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
9567       for( i = orignchildren; i < node->nchildren; ++i )
9568          data[i] = 1.0;
9569       node->data.data = (void*)data;
9570    }
9571    else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
9572    {
9573       /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
9574       SCIP_EXPRDATA_QUADRATIC* data;
9575 
9576       data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9577       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
9578       BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren);  /*lint !e866*/
9579    }
9580 
9581    node->simplified = FALSE;
9582 
9583    return SCIP_OKAY;
9584 }
9585 
9586 /** replaces a child node by another node
9587  *
9588  *  Assumes that both nodes represent the same expression.
9589  *  If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
9590  *  newchild must have deeper depth than node.
9591  */
9592 static
exprgraphNodeReplaceChild(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,SCIP_EXPRGRAPHNODE ** oldchild,SCIP_EXPRGRAPHNODE * newchild)9593 SCIP_RETCODE exprgraphNodeReplaceChild(
9594    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
9595    SCIP_EXPRGRAPHNODE*   node,               /**< pointer to expression graph node */
9596    SCIP_EXPRGRAPHNODE**  oldchild,           /**< child node that should be replaced, it may be freed */
9597    SCIP_EXPRGRAPHNODE*   newchild            /**< node that should take position of oldchild */
9598    )
9599 {
9600    int childpos = -1;
9601 
9602    assert(exprgraph != NULL);
9603    assert(node != NULL);
9604    assert(oldchild != NULL);
9605    assert(*oldchild != NULL);
9606    assert(newchild != NULL);
9607 
9608    if( *oldchild == newchild )
9609       return SCIP_OKAY;
9610 
9611    SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
9612 
9613    /* let's see if child is just next to the place where we looked in a previous call to this function */
9614    if( exprgraph->lastreplacechildpos >= 0 && exprgraph->lastreplacechildpos+1 < node->nchildren && node->children[exprgraph->lastreplacechildpos+1] == *oldchild )
9615    {
9616       childpos = exprgraph->lastreplacechildpos+1;
9617    }
9618    else for( childpos = 0; childpos < node->nchildren; ++childpos )
9619    {
9620       /* search for oldchild in children array */
9621       if( node->children[childpos] == *oldchild )
9622          break;
9623    }
9624    assert(childpos >= 0);
9625    assert(childpos < node->nchildren);
9626    assert(node->children[childpos] == *oldchild);
9627 
9628    /* add as parent to newchild */
9629    SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
9630 
9631    /* remove as parent from oldchild */
9632    SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
9633 
9634    /* set newchild as child i */
9635    node->children[childpos] = newchild;
9636 
9637    node->simplified = FALSE;
9638 
9639    /* remember to look next to childpos first next time */
9640    exprgraph->lastreplacechildpos = childpos;
9641 
9642    return SCIP_OKAY;
9643 }
9644 
9645 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
9646  *
9647  *  A node is larger than another node, if their corresponding constants are related that way.
9648  */
9649 static
SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)9650 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
9651 {
9652    assert(elem1 != NULL);
9653    assert(elem2 != NULL);
9654    assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
9655    assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
9656    assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */  /*lint !e777*/
9657    assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */  /*lint !e777*/
9658 
9659    if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9660       return 1;
9661    else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9662       return -1;
9663    else
9664       return 0;
9665 }
9666 
9667 /** sort array of nodes that holds constants */
9668 static
exprgraphSortConstNodes(SCIP_EXPRGRAPH * exprgraph)9669 void exprgraphSortConstNodes(
9670    SCIP_EXPRGRAPH*       exprgraph           /**< expression graph */
9671    )
9672 {
9673    assert(exprgraph != NULL);
9674 
9675    if( exprgraph->constssorted )
9676       return;
9677 
9678    SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9679 
9680    exprgraph->constssorted = TRUE;
9681 }
9682 
9683 /** finds position of expression graph node corresponding to a constant in constnodes array */
9684 static
exprgraphFindConstNodePos(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,int * pos)9685 SCIP_Bool exprgraphFindConstNodePos(
9686    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
9687    SCIP_EXPRGRAPHNODE*   node,               /**< node to search for */
9688    int*                  pos                 /**< buffer to store position of node, if found */
9689    )
9690 {
9691    int left;
9692    int right;
9693    int middle;
9694 
9695    assert(exprgraph != NULL);
9696    assert(node != NULL);
9697    assert(node->op == SCIP_EXPR_CONST);
9698    assert(node->depth == 0);
9699    assert(node->pos >= 0);
9700    assert(pos != NULL);
9701 
9702    exprgraphSortConstNodes(exprgraph);
9703    assert(exprgraph->constssorted);
9704 
9705    /* find a node with constant node->data.dbl using binary search */
9706    left = 0;
9707    right = exprgraph->nconsts-1;
9708    *pos = -1;
9709    while( left <= right )
9710    {
9711       middle = (left+right)/2;
9712       assert(0 <= middle && middle < exprgraph->nconsts);
9713 
9714       if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9715          right = middle - 1;
9716       else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9717          left  = middle + 1;
9718       else
9719       {
9720          *pos = middle;
9721          break;
9722       }
9723    }
9724    assert(left == right+1 || *pos >= 0);
9725    if( left == right+1 )
9726       return FALSE;
9727 
9728    /* search left of *pos to find node */
9729    while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl )  /*lint !e777*/
9730       --*pos;
9731    /* search right of *pos to find node */
9732    while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl )  /*lint !e777*/
9733       ++*pos;
9734 
9735    return exprgraph->constnodes[*pos] == node;
9736 }
9737 
9738 /** creates an expression graph node */
9739 static
exprgraphCreateNode(BMS_BLKMEM * blkmem,SCIP_EXPRGRAPHNODE ** node,SCIP_EXPROP op,SCIP_EXPROPDATA opdata)9740 SCIP_RETCODE exprgraphCreateNode(
9741    BMS_BLKMEM*           blkmem,             /**< block memory */
9742    SCIP_EXPRGRAPHNODE**  node,               /**< buffer to store expression graph node */
9743    SCIP_EXPROP           op,                 /**< operator type of expression */
9744    SCIP_EXPROPDATA       opdata              /**< operator data of expression */
9745    )
9746 {
9747    assert(blkmem != NULL);
9748    assert(node   != NULL);
9749 
9750    SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9751    BMSclearMemory(*node);
9752 
9753    (*node)->op   = op;
9754    (*node)->data = opdata;
9755 
9756    /* mark graph position as not in graph yet */
9757    (*node)->depth = -1;
9758    (*node)->pos   = -1;
9759 
9760    /* arrays of length 0 are trivially sorted */
9761    (*node)->parentssorted  = TRUE;
9762 
9763    /* set bounds interval to entire */
9764    (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9765    SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9766 
9767    /* set initial value to invalid */
9768    (*node)->value = SCIP_INVALID;
9769 
9770    /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9771    if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9772       (*node)->curv = SCIP_EXPRCURV_LINEAR;
9773    else
9774       (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9775 
9776    /* per default, a node is enabled */
9777    (*node)->enabled = TRUE;
9778 
9779    return SCIP_OKAY;
9780 }
9781 
9782 /** prints the expression corresponding to a node (not recursively) */
9783 static
exprgraphPrintNodeExpression(SCIP_EXPRGRAPHNODE * node,SCIP_MESSAGEHDLR * messagehdlr,FILE * file,const char ** varnames,SCIP_Bool printchildrenbounds)9784 void exprgraphPrintNodeExpression(
9785    SCIP_EXPRGRAPHNODE*   node,               /**< node of expression graph */
9786    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
9787    FILE*                 file,               /**< file to print to, or NULL for stdout */
9788    const char**          varnames,           /**< variable names, or NULL for generic names */
9789    SCIP_Bool             printchildrenbounds /**< whether to print bounds of children */
9790    )
9791 {
9792    int i;
9793 
9794    assert(node != NULL);
9795 
9796    switch( node->op )
9797    {
9798    case SCIP_EXPR_VARIDX:
9799       if( varnames != NULL )
9800       {
9801          SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9802       }
9803       else
9804          SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9805       break;
9806 
9807    case SCIP_EXPR_CONST:
9808       SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9809       break;
9810 
9811    case SCIP_EXPR_PARAM:
9812       SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9813       break;
9814 
9815    case SCIP_EXPR_PLUS:
9816       if( printchildrenbounds )
9817          SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9818       SCIPmessageFPrintInfo(messagehdlr, file, "+");
9819       if( printchildrenbounds )
9820          SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9821       break;
9822 
9823    case SCIP_EXPR_MINUS:
9824       if( printchildrenbounds )
9825          SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9826       SCIPmessageFPrintInfo(messagehdlr, file, "-");
9827       if( printchildrenbounds )
9828          SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9829       break;
9830 
9831    case SCIP_EXPR_MUL:
9832       if( printchildrenbounds )
9833          SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9834       SCIPmessageFPrintInfo(messagehdlr, file, "*");
9835       if( printchildrenbounds )
9836          SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9837       break;
9838 
9839    case SCIP_EXPR_DIV:
9840       if( printchildrenbounds )
9841          SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9842       SCIPmessageFPrintInfo(messagehdlr, file, "/");
9843       if( printchildrenbounds )
9844          SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9845       break;
9846 
9847    case SCIP_EXPR_SQUARE:
9848       if( printchildrenbounds )
9849          SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9850       SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9851       break;
9852 
9853    case SCIP_EXPR_REALPOWER:
9854       if( printchildrenbounds )
9855          SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9856       SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9857       break;
9858 
9859    case SCIP_EXPR_SIGNPOWER:
9860       if( printchildrenbounds )
9861          SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9862             node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9863       else
9864          SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9865       break;
9866 
9867    case SCIP_EXPR_INTPOWER:
9868       SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9869       if( printchildrenbounds )
9870          SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9871       SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9872       break;
9873 
9874    case SCIP_EXPR_SQRT:
9875    case SCIP_EXPR_EXP:
9876    case SCIP_EXPR_LOG:
9877    case SCIP_EXPR_SIN:
9878    case SCIP_EXPR_COS:
9879    case SCIP_EXPR_TAN:
9880       /* SCIP_EXPR_ERF       = 20, */  /**< gaussian error function (1 operand) */
9881       /* SCIP_EXPR_ERFI      = 21, */  /**< imaginary part of gaussian error function (1 operand) */
9882    case SCIP_EXPR_MIN:
9883    case SCIP_EXPR_MAX:
9884    case SCIP_EXPR_ABS:
9885    case SCIP_EXPR_SIGN:
9886       SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9887       if( printchildrenbounds )
9888       {
9889          SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9890          if( node->nchildren == 2 )
9891             SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9892          SCIPmessageFPrintInfo(messagehdlr, file, ")");
9893       }
9894       break;
9895 
9896    case SCIP_EXPR_SUM:
9897       if( printchildrenbounds )
9898          for( i = 0; i < node->nchildren; ++i )
9899          {
9900             if( i > 0 )
9901                SCIPmessageFPrintInfo(messagehdlr, file, "+");
9902             SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9903          }
9904       else
9905          SCIPmessageFPrintInfo(messagehdlr, file, "+");
9906       break;
9907 
9908    case SCIP_EXPR_PRODUCT:
9909       if( printchildrenbounds )
9910          for( i = 0; i < node->nchildren; ++i )
9911          {
9912             if( i > 0 )
9913                SCIPmessageFPrintInfo(messagehdlr, file, "*");
9914             SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9915          }
9916       else
9917          SCIPmessageFPrintInfo(messagehdlr, file, "*");
9918       break;
9919 
9920    case SCIP_EXPR_LINEAR:
9921    {
9922       SCIP_Real constant;
9923 
9924       constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9925 
9926       if( constant != 0.0 || node->nchildren == 0 )
9927          SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9928 
9929       for( i = 0; i < node->nchildren; ++i )
9930       {
9931          if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9932             SCIPmessageFPrintInfo(messagehdlr, file, "+");
9933          else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9934             SCIPmessageFPrintInfo(messagehdlr, file, "-");
9935          else
9936             SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9937          SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9938          if( printchildrenbounds )
9939             SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9940       }
9941 
9942       break;
9943    }
9944 
9945    case SCIP_EXPR_QUADRATIC:
9946    {
9947       SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9948 
9949       quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9950       assert(quadraticdata != NULL);
9951 
9952       if( quadraticdata->constant != 0.0 )
9953          SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9954 
9955       if( quadraticdata->lincoefs != NULL )
9956          for( i = 0; i < node->nchildren; ++i )
9957          {
9958             if( quadraticdata->lincoefs[i] == 0.0 )
9959                continue;
9960             SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9961             if( printchildrenbounds )
9962                SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9963          }
9964 
9965       for( i = 0; i < quadraticdata->nquadelems; ++i )
9966       {
9967          if( quadraticdata->quadelems[i].coef == 1.0 )
9968             SCIPmessageFPrintInfo(messagehdlr, file, "+");
9969          else if( quadraticdata->quadelems[i].coef == -1.0 )
9970             SCIPmessageFPrintInfo(messagehdlr, file, "-");
9971          else
9972             SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9973          SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9974          if( printchildrenbounds )
9975             SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9976          if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9977             SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9978          else
9979          {
9980             SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9981             if( printchildrenbounds )
9982                SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9983          }
9984       }
9985 
9986       break;
9987    }
9988 
9989    case SCIP_EXPR_POLYNOMIAL:
9990    {
9991       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9992       SCIP_EXPRDATA_MONOMIAL*   monomialdata;
9993       int j;
9994 
9995       polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9996       assert(polynomialdata != NULL);
9997 
9998       if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9999       {
10000          SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
10001       }
10002 
10003       for( i = 0; i < polynomialdata->nmonomials; ++i )
10004       {
10005          monomialdata = polynomialdata->monomials[i];
10006          if( monomialdata->coef == 1.0 )
10007             SCIPmessageFPrintInfo(messagehdlr, file, "+");
10008          else if( monomialdata->coef == -1.0 )
10009             SCIPmessageFPrintInfo(messagehdlr, file, "-");
10010          else
10011             SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
10012 
10013          for( j = 0; j < monomialdata->nfactors; ++j )
10014          {
10015             SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
10016             if( printchildrenbounds )
10017                SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
10018             if( monomialdata->exponents[j] < 0.0 )
10019                SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
10020             else if( monomialdata->exponents[j] != 1.0 )
10021                SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
10022          }
10023       }
10024 
10025       break;
10026    }
10027 
10028    case SCIP_EXPR_LAST:
10029       SCIPABORT();
10030       break;
10031 
10032    default:
10033       SCIPmessageFPrintInfo(messagehdlr, file, "%s", SCIPexpropGetName(node->op));
10034       break;
10035    } /*lint !e788*/
10036 }
10037 
10038 /** prints a node of an expression graph */
10039 static
exprgraphPrintNodeDot(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,SCIP_MESSAGEHDLR * messagehdlr,FILE * file,const char ** varnames)10040 void exprgraphPrintNodeDot(
10041    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
10042    SCIP_EXPRGRAPHNODE*   node,               /**< node of expression graph */
10043    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
10044    FILE*                 file,               /**< file to print to, or NULL for stdout */
10045    const char**          varnames            /**< variable names, or NULL for generic names */
10046    )
10047 {
10048    SCIP_Real color;
10049    int i;
10050 
10051    assert(exprgraph != NULL);
10052    assert(node != NULL);
10053    assert(file != NULL);
10054 
10055    color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
10056    SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
10057 
10058    exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
10059 
10060    SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
10061    if( node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED )
10062       SCIPmessageFPrintInfo(messagehdlr, file, "!");
10063    if( node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED )
10064       SCIPmessageFPrintInfo(messagehdlr, file, "*");
10065    if( node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT )
10066       SCIPmessageFPrintInfo(messagehdlr, file, "+");
10067 
10068    SCIPmessageFPrintInfo(messagehdlr, file, "\"");
10069 
10070    if( !node->enabled )
10071       SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
10072 
10073    SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
10074 
10075    /* add edges from node to children */
10076    for( i = 0; i < node->nchildren; ++i )
10077       SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d -> n%d_%d [label=\"c%d\"]\n", node->depth, node->pos, node->children[i]->depth, node->children[i]->pos, i);
10078 }
10079 
10080 /** evaluate node of expression graph w.r.t. values stored in children */
10081 static
exprgraphNodeEval(SCIP_EXPRGRAPHNODE * node,SCIP_Real * varvals)10082 SCIP_RETCODE exprgraphNodeEval(
10083    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node */
10084    SCIP_Real*            varvals             /**< values for variables */
10085    )
10086 {
10087    int i;
10088    SCIP_Real  staticbuf[SCIP_EXPRESSION_MAXCHILDEST];
10089    SCIP_Real* buf;
10090 
10091    assert(node != NULL);
10092 
10093    /* if many children, get large enough memory to store argument values */
10094    if( node->nchildren > SCIP_EXPRESSION_MAXCHILDEST )
10095    {
10096       SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
10097    }
10098    else
10099    {
10100       buf = staticbuf;
10101    }
10102 
10103    /* get values of children */
10104    for( i = 0; i < node->nchildren; ++i )
10105    {
10106       assert(node->children[i]->value != SCIP_INVALID);  /*lint !e777*/
10107       buf[i] = node->children[i]->value;  /*lint !e644*/
10108    }
10109 
10110    /* evaluate this expression */
10111    assert(exprOpTable[node->op].eval != NULL);
10112    SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
10113    assert(node->value != SCIP_INVALID);  /*lint !e777*/
10114 
10115    /* free memory, if allocated before */
10116    if( staticbuf != buf )
10117    {
10118       BMSfreeMemoryArray(&buf);
10119    }
10120 
10121    return SCIP_OKAY;
10122 }
10123 
10124 /** evaluates node including subtree */
10125 static
exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE * node,SCIP_Real * varvals)10126 SCIP_RETCODE exprgraphNodeEvalWithChildren(
10127    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node */
10128    SCIP_Real*            varvals             /**< values for variables */
10129    )
10130 {
10131    int i;
10132 
10133    assert(node != NULL);
10134 
10135    for( i = 0; i < node->nchildren; ++i )
10136    {
10137       SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
10138    }
10139 
10140    SCIP_CALL( exprgraphNodeEval(node, varvals) );
10141 
10142    return SCIP_OKAY;
10143 }
10144 
10145 /** updates bounds of a node if a children has changed its bounds */
10146 static
exprgraphNodeUpdateBounds(SCIP_EXPRGRAPHNODE * node,SCIP_Real infinity,SCIP_Real minstrength,SCIP_Bool parenttightenisinvalid)10147 SCIP_RETCODE exprgraphNodeUpdateBounds(
10148    SCIP_EXPRGRAPHNODE*   node,               /**< node of expression graph */
10149    SCIP_Real             infinity,           /**< value for infinity in interval arithmetics */
10150    SCIP_Real             minstrength,        /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
10151    SCIP_Bool             parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
10152    )
10153 {
10154    SCIP_INTERVAL  childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
10155    SCIP_INTERVAL* childbounds;
10156    SCIP_INTERVAL newbounds;
10157    int i;
10158 
10159    assert(node != NULL);
10160    assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
10161    assert(node->pos >= 0);   /* node should be in graph */
10162    assert(node->op != SCIP_EXPR_VARIDX);
10163    assert(node->op != SCIP_EXPR_PARAM);
10164 
10165    /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
10166     * if node is disabled, then also do nothing */
10167    if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
10168       return SCIP_OKAY;
10169 
10170    /* if many children, get large enough memory to store children bounds */
10171    if( node->nchildren > SCIP_EXPRESSION_MAXCHILDEST )
10172    {
10173       SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
10174    }
10175    else
10176    {
10177       childbounds = childboundsstatic;
10178    }
10179 
10180    /* assemble bounds of children */
10181    for( i = 0; i < node->nchildren; ++i )
10182    {
10183       /* child should have valid and non-empty bounds */
10184       assert(!(node->children[i]->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
10185       assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10186 
10187       childbounds[i] = node->children[i]->bounds;  /*lint !e644*/
10188    }
10189 
10190    /* call interval evaluation function for this operand */
10191    assert( exprOpTable[node->op].inteval != NULL );
10192    SCIPintervalSet(&newbounds, 0.0);
10193    SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
10194 
10195    /* free memory, if allocated before */
10196    if( childbounds != childboundsstatic )
10197    {
10198       BMSfreeMemoryArray(&childbounds);
10199    }
10200 
10201    /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
10202 
10203    /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
10204     * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
10205     *
10206     * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
10207     *
10208     * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
10209     */
10210    if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
10211       ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
10212    {
10213       for( i = 0; i < node->nparents; ++i )
10214          node->parents[i]->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
10215 
10216       node->bounds = newbounds;
10217    }
10218    else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
10219       (     isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
10220    {
10221       for( i = 0; i < node->nparents; ++i )
10222          node->parents[i]->boundstatus |= SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
10223 
10224       node->bounds = newbounds;
10225    }
10226    else
10227    {
10228       SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
10229    }
10230 
10231    SCIPdebugMessage("updated bounds of node %p (%d,%d) op %s to [%g,%g]\n", (void*)node, node->depth, node->pos, SCIPexpropGetName(node->op), node->bounds.inf, node->bounds.sup);
10232 
10233    /* node now has valid bounds */
10234    node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
10235 
10236    return SCIP_OKAY;
10237 }
10238 
10239 /** propagate bounds of a node into children by reverting the nodes expression */
10240 static
exprgraphNodePropagateBounds(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,SCIP_Real infinity,SCIP_Real minstrength,SCIP_Bool * cutoff)10241 void exprgraphNodePropagateBounds(
10242    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
10243    SCIP_EXPRGRAPHNODE*   node,               /**< node in expression graph with no parents */
10244    SCIP_Real             infinity,           /**< value for infinity in interval arithmetics */
10245    SCIP_Real             minstrength,        /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
10246    SCIP_Bool*            cutoff              /**< buffer to store whether a node's bounds were propagated to an empty interval */
10247    )
10248 {
10249    SCIP_INTERVAL childbounds;
10250    int i;
10251 
10252    assert(exprgraph != NULL);
10253    assert(node != NULL);
10254    assert(node->depth >= 0); /* node should be in graph */
10255    assert(node->pos >= 0);   /* node should be in graph */
10256    assert(minstrength >= 0.0);
10257    assert(cutoff != NULL);
10258    assert(!SCIPintervalIsEmpty(infinity, node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
10259    assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
10260 
10261    /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
10262    if( (node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT) == 0 )
10263       return;
10264 
10265    /* if node is not enabled, then do nothing */
10266    if( !node->enabled )
10267       return;
10268 
10269    /* tell children that they should propagate their bounds even if not tightened */
10270    if( (node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE) == SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE )
10271       minstrength = -1.0;
10272 
10273    /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
10274    node->boundstatus = SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
10275 
10276    /* SCIPdebugMessage("propagating node %p (%d,%d) op %s: [%10g,%10g] = ", (void*)node, node->depth, node->pos, SCIPexpropGetName(node->op), node->bounds.inf, node->bounds.sup);
10277     * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10278     * SCIPdebugPrintf("\n");
10279     */
10280 
10281    /* @todo add callback to exprOpTable for this */
10282 
10283    switch( node->op )
10284    {
10285    case SCIP_EXPR_VARIDX:
10286    case SCIP_EXPR_CONST:
10287    case SCIP_EXPR_PARAM:
10288       /* cannot propagate bound changes further */
10289       break;
10290 
10291    case SCIP_EXPR_PLUS:
10292    {
10293       assert(node->nchildren == 2);
10294       /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
10295 
10296       SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10297       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10298 
10299       if( *cutoff )
10300          break;
10301 
10302       SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10303       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10304 
10305       break;
10306    }
10307 
10308    case SCIP_EXPR_MINUS:
10309    {
10310       assert(node->nchildren == 2);
10311       /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
10312 
10313       SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10314       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10315 
10316       if( *cutoff )
10317          break;
10318 
10319       SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10320       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10321 
10322       break;
10323    }
10324 
10325    case SCIP_EXPR_MUL:
10326    {
10327       assert(node->nchildren == 2);
10328       /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
10329 
10330       SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10331       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10332 
10333       if( *cutoff )
10334          break;
10335 
10336       SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10337       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10338 
10339       break;
10340    }
10341 
10342    case SCIP_EXPR_DIV:
10343    {
10344       assert(node->nchildren == 2);
10345       /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
10346 
10347       SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10348       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10349 
10350       if( *cutoff )
10351          break;
10352 
10353       SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10354       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10355 
10356       break;
10357    }
10358 
10359    case SCIP_EXPR_SQUARE:
10360    {
10361       assert(node->nchildren == 1);
10362       /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
10363 
10364       if( node->bounds.sup < 0.0 )
10365       {
10366          *cutoff = TRUE;
10367          break;
10368       }
10369 
10370       SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
10371       if( node->children[0]->bounds.inf <= -childbounds.inf )
10372          SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
10373       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10374 
10375       break;
10376    }
10377 
10378    case SCIP_EXPR_SQRT:
10379    {
10380       assert(node->nchildren == 1);
10381       /* f = sqrt(c0) -> c0 = f^2 */
10382 
10383       SCIPintervalSquare(infinity, &childbounds, node->bounds);
10384       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10385 
10386       break;
10387    }
10388 
10389    case SCIP_EXPR_REALPOWER:
10390    {
10391       assert(node->nchildren == 1);
10392 
10393       SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
10394 
10395       if( SCIPintervalIsEmpty(infinity, childbounds) )
10396       {
10397          *cutoff = TRUE;
10398          break;
10399       }
10400       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10401 
10402       break;
10403    }
10404 
10405    case SCIP_EXPR_SIGNPOWER:
10406    {
10407       assert(node->nchildren == 1);
10408 
10409       if( node->data.dbl != 0.0 )
10410       {
10411          SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
10412       }
10413       else
10414       {
10415          /* behaves like SCIP_EXPR_SIGN */
10416          SCIPintervalSetBounds(&childbounds,
10417             (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10418             (node->bounds.inf <=  1.0 && node->bounds.sup >=  1.0) ?  infinity : 0.0);
10419       }
10420 
10421       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10422 
10423       break;
10424    }
10425 
10426    case SCIP_EXPR_INTPOWER:
10427    {
10428       assert(node->nchildren == 1);
10429 
10430       SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
10431 
10432       if( SCIPintervalIsEmpty(infinity, childbounds) )
10433       {
10434          *cutoff = TRUE;
10435          break;
10436       }
10437       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10438 
10439       break;
10440    }
10441 
10442    case SCIP_EXPR_EXP:
10443    {
10444       assert(node->nchildren == 1);
10445       /* f = exp(c0) -> c0 = log(f) */
10446 
10447       if( node->bounds.sup < 0.0 )
10448       {
10449          *cutoff = TRUE;
10450          break;
10451       }
10452 
10453       SCIPintervalLog(infinity, &childbounds, node->bounds);
10454       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10455 
10456       break;
10457    }
10458 
10459    case SCIP_EXPR_LOG:
10460    {
10461       assert(node->nchildren == 1);
10462       /* f = log(c0) -> c0 = exp(f) */
10463 
10464       SCIPintervalExp(infinity, &childbounds, node->bounds);
10465       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10466 
10467       break;
10468    }
10469 
10470    case SCIP_EXPR_SIN:
10471    case SCIP_EXPR_COS:
10472    case SCIP_EXPR_TAN:
10473       /* case SCIP_EXPR_ERF: */
10474       /* case SCIP_EXPR_ERFI: */
10475    {
10476       assert(node->nchildren == 1);
10477 
10478       /* @todo implement */
10479 
10480       break;
10481    }
10482 
10483    case SCIP_EXPR_ABS:
10484    {
10485       assert(node->nchildren == 1);
10486 
10487       /* use identity if child bounds are non-negative */
10488       if( node->children[0]->bounds.inf >= 0 )
10489       {
10490          SCIPintervalSetBounds(&childbounds, node->bounds.inf, node->bounds.sup);
10491       }
10492       /* use -identity if child bounds are non-positive */
10493       else if( node->children[0]->bounds.sup <= 0 )
10494       {
10495          assert(node->bounds.inf <= node->bounds.sup);
10496          SCIPintervalSetBounds(&childbounds, -node->bounds.sup, -node->bounds.inf);
10497       }
10498       /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
10499       else
10500       {
10501          SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
10502       }
10503 
10504       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10505 
10506       break;
10507    }
10508 
10509    case SCIP_EXPR_SIGN:
10510    {
10511       assert(node->nchildren == 1);
10512       /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
10513 
10514       SCIPintervalSetBounds(&childbounds,
10515          (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10516          (node->bounds.inf <=  1.0 && node->bounds.sup >=  1.0) ?  infinity : 0.0);
10517       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10518 
10519       break;
10520    }
10521 
10522    case SCIP_EXPR_MIN:
10523    {
10524       assert(node->nchildren == 2);
10525       /* f = min(c0,c1) -> f <= c0, f <= c1
10526        * if c1 > f -> c0 = f
10527        * if c0 > f -> c1 = f
10528        */
10529 
10530       SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10531          node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10532       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10533 
10534       if( *cutoff )
10535          break;
10536 
10537       SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10538          node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10539       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10540 
10541       break;
10542    }
10543 
10544    case SCIP_EXPR_MAX:
10545    {
10546       assert(node->nchildren == 2);
10547       /* f = max(c0, c1) -> f >= c0, f >= c1
10548        * if c1 < f -> c0 = f
10549        * if c0 < f -> c1 = f
10550        */
10551 
10552       SCIPintervalSetBounds(&childbounds,
10553          node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10554          node->bounds.sup);
10555       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10556 
10557       SCIPintervalSetBounds(&childbounds,
10558          node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10559          node->bounds.sup);
10560       SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10561 
10562       break;
10563    }
10564 
10565    case SCIP_EXPR_SUM:
10566    {
10567       SCIP_ROUNDMODE prevroundmode;
10568 
10569       /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
10570 
10571       SCIP_Real minlinactivity;
10572       SCIP_Real maxlinactivity;
10573       int minlinactivityinf;
10574       int maxlinactivityinf;
10575 
10576       if( node->nchildren == 0 )
10577          break;
10578 
10579       if( SCIPintervalIsEntire(infinity, node->bounds) )
10580          break;
10581 
10582       minlinactivity = 0.0;
10583       maxlinactivity = 0.0;
10584       minlinactivityinf = 0;
10585       maxlinactivityinf = 0;
10586 
10587       prevroundmode = SCIPintervalGetRoundingMode();
10588       SCIPintervalSetRoundingModeDownwards();
10589 
10590       for( i = 0; i < node->nchildren; ++i )
10591       {
10592          assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10593 
10594          /* minimal activity is only useful if node has a finite upper bound */
10595          if( node->bounds.sup < infinity )
10596          {
10597             if( node->children[i]->bounds.inf <= -infinity )
10598             {
10599                ++minlinactivityinf;
10600             }
10601             else
10602             {
10603                assert(node->children[i]->bounds.inf < infinity);
10604                minlinactivity += node->children[i]->bounds.inf;
10605             }
10606          }
10607 
10608          /* maximal activity is only useful if node has a finite lower bound
10609           * we compute negated maximal activity here so we can keep downward rounding
10610           */
10611          if( node->bounds.inf > -infinity )
10612          {
10613             if( node->children[i]->bounds.sup >= infinity )
10614             {
10615                ++maxlinactivityinf;
10616             }
10617             else
10618             {
10619                assert(node->children[i]->bounds.sup > -infinity);
10620                maxlinactivity -= node->children[i]->bounds.sup;
10621             }
10622          }
10623       }
10624       maxlinactivity = -maxlinactivity; /* correct sign */
10625 
10626       /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10627       if( (minlinactivityinf >= 2 || node->bounds.sup >=  infinity) &&
10628          ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10629          )
10630       {
10631          SCIPintervalSetRoundingMode(prevroundmode);
10632          break;
10633       }
10634 
10635       for( i = 0; i < node->nchildren && !*cutoff; ++i )
10636       {
10637          /* upper bounds of c_i is
10638           *   node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
10639           *   node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
10640           */
10641          SCIPintervalSetEntire(infinity, &childbounds);
10642          if( node->bounds.sup <  infinity )
10643          {
10644             /* we are still in downward rounding mode, so negate and negate to get upward rounding */
10645             if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10646             {
10647                assert(minlinactivityinf == 1);
10648                childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
10649             }
10650             else if( minlinactivityinf == 0 )
10651             {
10652                childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
10653             }
10654          }
10655 
10656          /* lower bounds of c_i is
10657           *   node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
10658           *   node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
10659           */
10660          if( node->bounds.inf > -infinity )
10661          {
10662             if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10663             {
10664                assert(maxlinactivityinf == 1);
10665                childbounds.inf = node->bounds.inf - maxlinactivity;
10666             }
10667             else if( maxlinactivityinf == 0 )
10668             {
10669                childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
10670             }
10671          }
10672 
10673          SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10674       }
10675 
10676       SCIPintervalSetRoundingMode(prevroundmode);
10677 
10678       break;
10679    }
10680 
10681    case SCIP_EXPR_PRODUCT:
10682    {
10683       int j;
10684       /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
10685 
10686       /* too expensive (runtime here is quadratic in number of children) */
10687       if( node->nchildren > 10 )
10688          break;
10689 
10690       /* useless */
10691       if( SCIPintervalIsEntire(infinity, node->bounds) )
10692          break;
10693 
10694       for( i = 0; i < node->nchildren && !*cutoff; ++i )
10695       {
10696          /* compute prod_{j:j!=i} c_j */
10697          SCIPintervalSet(&childbounds, 1.0);
10698          for( j = 0; j < node->nchildren; ++j )
10699          {
10700             if( i == j )
10701                continue;
10702             SCIPintervalMul(infinity, &childbounds, childbounds, node->children[j]->bounds);
10703 
10704             /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10705             if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10706                break;
10707          }
10708 
10709          if( j == node->nchildren )
10710          {
10711             SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10712             SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10713          }
10714       }
10715 
10716       break;
10717    }
10718 
10719    case SCIP_EXPR_LINEAR:
10720    {
10721       SCIP_ROUNDMODE prevroundmode;
10722       SCIP_Real* coefs;
10723 
10724       /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10725 
10726       SCIP_Real minlinactivity;
10727       SCIP_Real maxlinactivity;
10728       int minlinactivityinf;
10729       int maxlinactivityinf;
10730 
10731       if( node->nchildren == 0 )
10732          break;
10733 
10734       if( SCIPintervalIsEntire(infinity, node->bounds) )
10735          break;
10736 
10737       coefs = (SCIP_Real*)node->data.data;
10738 
10739       minlinactivity =  coefs[node->nchildren];
10740       maxlinactivity = -coefs[node->nchildren];
10741       minlinactivityinf = 0;
10742       maxlinactivityinf = 0;
10743 
10744       prevroundmode = SCIPintervalGetRoundingMode();
10745       SCIPintervalSetRoundingModeDownwards();
10746 
10747       for( i = 0; i < node->nchildren; ++i )
10748       {
10749          assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10750 
10751          /* minimal activity is only useful if node has a finite upper bound */
10752          if( node->bounds.sup < infinity )
10753          {
10754             if( coefs[i] >= 0.0 )
10755             {
10756                if( node->children[i]->bounds.inf <= -infinity )
10757                {
10758                   ++minlinactivityinf;
10759                }
10760                else
10761                {
10762                   assert(node->children[i]->bounds.inf < infinity);
10763                   minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10764                }
10765             }
10766             else
10767             {
10768                if( node->children[i]->bounds.sup >= infinity )
10769                {
10770                   ++minlinactivityinf;
10771                }
10772                else
10773                {
10774                   assert(node->children[i]->bounds.sup > -infinity);
10775                   minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10776                }
10777             }
10778          }
10779 
10780          /* maximal activity is only useful if node has a finite lower bound
10781           * we compute negated maximal activity here so we can keep downward rounding
10782           */
10783          if( node->bounds.inf > -infinity )
10784          {
10785             if( coefs[i] >= 0.0 )
10786             {
10787                if( node->children[i]->bounds.sup >= infinity )
10788                {
10789                   ++maxlinactivityinf;
10790                }
10791                else
10792                {
10793                   assert(node->children[i]->bounds.sup > -infinity);
10794                   maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup;
10795                }
10796             }
10797             else
10798             {
10799                if( node->children[i]->bounds.inf <= -infinity )
10800                {
10801                   ++maxlinactivityinf;
10802                }
10803                else
10804                {
10805                   assert(node->children[i]->bounds.inf < infinity);
10806                   maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.inf;
10807                }
10808             }
10809          }
10810       }
10811       maxlinactivity = SCIPintervalNegateReal(maxlinactivity); /* correct sign */
10812 
10813       /* SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]; bounds = [%10g,%10g]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf, node->bounds.inf, node->bounds.sup); */
10814 
10815       /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10816       if( (minlinactivityinf >= 2 || node->bounds.sup >=  infinity) &&
10817          (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10818          )
10819       {
10820          SCIPintervalSetRoundingMode(prevroundmode);
10821          break;
10822       }
10823 
10824       for( i = 0; i < node->nchildren && !*cutoff; ++i )
10825       {
10826          SCIP_INTERVAL ac;
10827 
10828          if( coefs[i] == 0.0 )
10829             continue;
10830 
10831          /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10832          SCIPintervalSet(&ac, 0.0);
10833          if( coefs[i] >= 0.0 )
10834          {
10835             if( node->children[i]->bounds.inf > -infinity )
10836                ac.inf = coefs[i] * node->children[i]->bounds.inf;
10837             if( node->children[i]->bounds.sup < infinity )
10838                ac.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup);
10839          }
10840          else
10841          {
10842             if( node->children[i]->bounds.sup < infinity )
10843                ac.inf = coefs[i] * node->children[i]->bounds.sup;
10844             if( node->children[i]->bounds.inf > -infinity )
10845                ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10846          }
10847 
10848          SCIPintervalSetEntire(infinity, &childbounds);
10849          if( coefs[i] > 0.0 )
10850          {
10851             /* upper bounds of c_i is
10852              *   (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10853              *   (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10854              */
10855             if( node->bounds.sup <  infinity )
10856             {
10857                /* we are still in downward rounding mode, so negate to get upward rounding */
10858                if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10859                {
10860                   assert(minlinactivityinf == 1);
10861                   childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10862                }
10863                else if( minlinactivityinf == 0 )
10864                {
10865                   childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10866                }
10867             }
10868 
10869             /* lower bounds of c_i is
10870              *   (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10871              *   (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10872              */
10873             if( node->bounds.inf > -infinity )
10874             {
10875                if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10876                {
10877                   assert(maxlinactivityinf == 1);
10878                   childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10879                }
10880                else if( maxlinactivityinf == 0 )
10881                {
10882                   childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10883                }
10884             }
10885          }
10886          else
10887          {
10888             /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10889              * thus, we do (b-a)/(-c) in downward rounding
10890              */
10891             /* lower bounds of c_i is
10892              *   (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10893              *   (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10894              */
10895             if( node->bounds.sup <  infinity )
10896             {
10897                if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10898                {
10899                   assert(minlinactivityinf == 1);
10900                   childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10901                }
10902                else if( minlinactivityinf == 0 )
10903                {
10904                   childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10905                }
10906             }
10907 
10908             /* upper bounds of c_i is
10909              *   (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10910              *   (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10911              */
10912             if( node->bounds.inf > -infinity )
10913             {
10914                /* we are still in downward rounding mode, so negate to get upward rounding */
10915                if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10916                {
10917                   assert(maxlinactivityinf == 1);
10918                   childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10919                }
10920                else if( maxlinactivityinf == 0 )
10921                {
10922                   childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10923                }
10924             }
10925          }
10926 
10927          SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10928       }
10929 
10930       SCIPintervalSetRoundingMode(prevroundmode);
10931 
10932       break;
10933    }
10934 
10935    case SCIP_EXPR_QUADRATIC:
10936    {
10937       SCIP_EXPRDATA_QUADRATIC* quaddata;
10938       SCIP_INTERVAL tmp;
10939       SCIP_INTERVAL a;
10940       SCIP_INTERVAL b;
10941       SCIP_INTERVAL c;
10942       SCIP_QUADELEM* quadelems;
10943       int nquadelems;
10944       SCIP_Real* lincoefs;
10945       int k;
10946 
10947       /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10948        * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10949        */
10950 
10951       quaddata   = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10952       quadelems  = quaddata->quadelems;
10953       nquadelems = quaddata->nquadelems;
10954       lincoefs   = quaddata->lincoefs;
10955 
10956       /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10957       if( nquadelems > 10 )
10958          break;
10959 
10960       if( SCIPintervalIsEntire(infinity, node->bounds) )
10961          break;
10962 
10963       if( node->nchildren == 2 && nquadelems > 0 )
10964       {
10965          /* if it's a bivariate quadratic expression with bilinear term, do something special */
10966          SCIP_Real ax;  /* square coefficient of first  child */
10967          SCIP_Real ay;  /* square coefficient of second child */
10968          SCIP_Real axy; /* bilinear coefficient */
10969 
10970          ax = 0.0;
10971          ay = 0.0;
10972          axy = 0.0;
10973          for( i = 0; i < nquadelems; ++i )
10974             if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10975                ax += quadelems[i].coef;
10976             else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10977                ay += quadelems[i].coef;
10978             else
10979                axy += quadelems[i].coef;
10980 
10981          c = node->bounds;
10982          SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10983 
10984          /* compute bounds for x */
10985          SCIPintervalSolveBivariateQuadExpressionAllScalar(
10986             infinity, &childbounds, ax, ay, axy,
10987             lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10988             c, node->children[0]->bounds, node->children[1]->bounds
10989             );
10990          if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10991          {
10992             SCIPdebugMessage("%g x^2 + %g y^2 + %g xy + %g x + %g y in [%g,%g], x = [%g,%g], y = [%g,%g] -> x in [%g,%g], cutoff = %d\n",
10993                ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10994                c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10995                node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10996                );
10997          }
10998 
10999          if( SCIPintervalIsEmpty(infinity, childbounds) )
11000             *cutoff = TRUE;
11001          else
11002             SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11003          if( *cutoff )
11004             break;
11005 
11006          /* compute bounds for y */
11007          SCIPintervalSolveBivariateQuadExpressionAllScalar(
11008             infinity, &childbounds, ay, ax, axy,
11009             lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
11010             c, node->children[1]->bounds, node->children[0]->bounds
11011             );
11012 
11013          if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
11014          {
11015             SCIPdebugMessage("%g x^2 + %g y^2 + %g xy + %g x + %g y in [%g,%g], x = [%g,%g], y = [%g,%g] -> y in [%g,%g], cutoff = %d\n",
11016                ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
11017                c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
11018                node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
11019                );
11020          }
11021 
11022          if( SCIPintervalIsEmpty(infinity, childbounds) )
11023             *cutoff = TRUE;
11024          else
11025             SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
11026          if( *cutoff )
11027             break;
11028 
11029          break;
11030       }
11031 
11032       for( i = 0; i < node->nchildren && !*cutoff; ++i )
11033       {
11034          SCIPintervalSet(&a, 0.0);
11035          SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
11036          c = node->bounds;
11037          SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
11038 
11039          /* move linear terms not corresponding to i into c
11040           * @todo do this faster, see EXPR_LINEAR
11041           */
11042          if( lincoefs != NULL )
11043             for( k = 0; k < node->nchildren; ++k )
11044                if( i != k && lincoefs[k] != 0.0 )
11045                {
11046                   SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
11047                   SCIPintervalSub(infinity, &c, c, tmp);
11048                }
11049 
11050          for( k = 0; k < nquadelems; ++k )
11051          {
11052             if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
11053             {
11054                SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
11055             }
11056             else if( quadelems[k].idx1 == i )
11057             {
11058                SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
11059                SCIPintervalAdd(infinity, &b, b, tmp);
11060             }
11061             else if( quadelems[k].idx2 == i )
11062             {
11063                SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
11064                SCIPintervalAdd(infinity, &b, b, tmp);
11065             }
11066             else if( quadelems[k].idx1 == quadelems[k].idx2 )
11067             {
11068                SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
11069                SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11070                SCIPintervalSub(infinity, &c, c, tmp);
11071             }
11072             else
11073             {
11074                SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
11075                SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11076                SCIPintervalSub(infinity, &c, c, tmp);
11077             }
11078          }
11079 
11080          SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
11081             a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
11082          SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c, node->children[i]->bounds);
11083          if( SCIPintervalIsEmpty(infinity, childbounds) )
11084             *cutoff = TRUE;
11085          else
11086             SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11087       }
11088 
11089       break;
11090    }
11091 
11092    case SCIP_EXPR_POLYNOMIAL:
11093    {
11094       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11095       SCIP_EXPRDATA_MONOMIAL**  monomials;
11096       SCIP_EXPRDATA_MONOMIAL*   monomial;
11097       int nmonomials;
11098       int j;
11099       int k;
11100       SCIP_Real n;
11101       int nexpisdoublen;
11102       int nexpishalfn;
11103       char abc_flag;
11104 
11105       SCIP_INTERVAL monomialcoef;
11106       SCIP_INTERVAL tmp;
11107       SCIP_INTERVAL a;
11108       SCIP_INTERVAL b;
11109       SCIP_INTERVAL c;
11110       SCIP_INTERVAL childpowbounds;
11111 
11112       /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
11113        * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
11114        *
11115        * we determine n by setting n to the first exponent of x that we see
11116        * then we count how often we see x^(2n) and x^(n/2)
11117        * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
11118        */
11119 
11120       polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11121       monomials  = polynomialdata->monomials;
11122       nmonomials = polynomialdata->nmonomials;
11123 
11124       if( SCIPintervalIsEntire(infinity, node->bounds) )
11125          break;
11126 
11127       for( i = 0; i < node->nchildren && !*cutoff; ++i )
11128       {
11129          n = 0.0;
11130          nexpisdoublen = 0;
11131          nexpishalfn = 0;
11132          for( j = 0; j < nmonomials; ++j )
11133          {
11134             monomial = monomials[j];
11135             for( k = 0; k < monomial->nfactors; ++k )
11136             {
11137                if( monomial->childidxs[k] == i )
11138                {
11139                   if( n == 0.0 )
11140                      n = monomial->exponents[k];
11141                   else if( n == 2*monomial->exponents[k] )  /*lint !e777*/
11142                      ++nexpishalfn;
11143                   else if( 2*n == monomial->exponents[k] )  /*lint !e777*/
11144                      ++nexpisdoublen;
11145                }
11146             }
11147          }
11148 
11149          if( n == 0.0 )
11150          {
11151             /* child does not appear in polynomial -> cannot deduce bound */
11152             continue;
11153          }
11154 
11155          /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
11156          if( nexpishalfn > nexpisdoublen )
11157             n /= 2.0;
11158 
11159          SCIPintervalSet(&a, 0.0);
11160          SCIPintervalSet(&b, 0.0);
11161          SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
11162 
11163          for( j = 0; j < nmonomials; ++j )
11164          {
11165             monomial = monomials[j];
11166             SCIPintervalSet(&monomialcoef, monomial->coef);
11167             abc_flag = 'c';
11168             for( k = 0; k < monomial->nfactors; ++k )
11169             {
11170                if( monomial->childidxs[k] == i )
11171                {
11172                   assert(abc_flag == 'c'); /* child should appear only once per monom */
11173                   if( n > 0.0 )
11174                   {
11175                      if( monomial->exponents[k] > 2.0*n )
11176                      {
11177                         abc_flag = 'a';
11178                         SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11179                         SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11180                      }
11181                      else if( monomial->exponents[k] == 2*n )  /*lint !e777*/
11182                      {
11183                         abc_flag = 'a';
11184                      }
11185                      else if( monomial->exponents[k] > n )
11186                      {
11187                         abc_flag = 'b';
11188                         SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11189                         SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11190                      }
11191                      else if( monomial->exponents[k] == n )  /*lint !e777*/
11192                      {
11193                         abc_flag = 'b';
11194                      }
11195                      else
11196                      {
11197                         SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11198                         SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11199                      }
11200                   }
11201                   else
11202                   {
11203                      assert(n < 0.0);
11204                      if( monomial->exponents[k] < 2.0*n )
11205                      {
11206                         abc_flag = 'a';
11207                         SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11208                         SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11209                      }
11210                      else if( monomial->exponents[k] == 2*n )  /*lint !e777*/
11211                      {
11212                         abc_flag = 'a';
11213                      }
11214                      else if( monomial->exponents[k] < n )
11215                      {
11216                         abc_flag = 'b';
11217                         SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11218                         SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11219                      }
11220                      else if( monomial->exponents[k] == n )  /*lint !e777*/
11221                      {
11222                         abc_flag = 'b';
11223                      }
11224                      else
11225                      {
11226                         SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11227                         SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11228                      }
11229                   }
11230                }
11231                else
11232                {
11233                   SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
11234                   SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11235                }
11236             }
11237 
11238             if( abc_flag == 'a' )
11239             {
11240                SCIPintervalAdd(infinity, &a, a, monomialcoef);
11241                /* if monomialcoef is such that a exceeds value for infinity, then stop */
11242                if( a.inf >= infinity || a.sup <= -infinity )
11243                   break;
11244             }
11245             else if( abc_flag == 'b' )
11246             {
11247                SCIPintervalAdd(infinity, &b, b, monomialcoef);
11248                /* if monomialcoef is such that b exceeds value for infinity, then stop */
11249                if( b.inf >= infinity || b.sup <= -infinity )
11250                   break;
11251             }
11252             else
11253             {
11254                SCIPintervalSub(infinity, &c, c, monomialcoef);
11255                /* if monomialcoef is such that c exceeds value for infinity, then stop */
11256                if( c.inf >= infinity || c.sup <= -infinity )
11257                   break;
11258             }
11259          }
11260 
11261          /* if we run out of numbers (within -infinity,infinity) above, then stop */
11262          if( j < nmonomials )
11263             continue;
11264 
11265          /* now have equation a*child^(2n) + b*child^n = c
11266           * solve a*y^2 + b*y = c (for y in childbounds^n), then child^n = y
11267           */
11268          SCIPintervalPowerScalar(infinity, &childpowbounds, node->children[i]->bounds, n);
11269          SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g] for c%d^%g in [%10g,%10g]",
11270             a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup, i, n, childpowbounds.inf, childpowbounds.sup);
11271          SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c, childpowbounds);
11272          SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
11273 
11274          if( SCIPintervalIsEmpty(infinity, tmp) )
11275          {
11276             *cutoff = TRUE;
11277             break;
11278          }
11279 
11280          SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
11281          SCIPdebugPrintf(" with c%d = [%10g, %10g] -> c%d = [%10g, %10g]\n", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup, i, childbounds.inf, childbounds.sup);
11282          if( SCIPintervalIsEmpty(infinity, childbounds) )
11283          {
11284             SCIPdebugMessage(" -> cutoff\n");
11285             *cutoff = TRUE;
11286             break;
11287          }
11288 
11289          SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11290 
11291          /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
11292             SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11293             SCIPdebugPrintf("\n"); */
11294       }
11295 
11296       break;
11297    }
11298 
11299    case SCIP_EXPR_USER:
11300    {
11301       SCIP_INTERVAL* childrenbounds;
11302       SCIP_EXPRDATA_USER* exprdata;
11303       int c;
11304 
11305       exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11306 
11307       /* do nothing if callback not implemented */
11308       if( exprdata->prop == NULL )
11309          break;
11310 
11311       /* if only one child, do faster */
11312       if( node->nchildren == 1 )
11313       {
11314          childbounds = node->children[0]->bounds;
11315          SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, 1, &childbounds, node->bounds, cutoff) );
11316 
11317          if( !*cutoff )
11318             SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11319 
11320          break;
11321       }
11322 
11323       SCIP_ALLOC_ABORT( BMSallocBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren) );
11324       for( c = 0; c < node->nchildren; ++c )
11325          childrenbounds[c] = node->children[c]->bounds;
11326 
11327       SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, node->nchildren, childrenbounds, node->bounds, cutoff) );
11328 
11329       for( c = 0; !*cutoff && c < node->nchildren; ++c )
11330       {
11331          SCIPexprgraphTightenNodeBounds(exprgraph, node->children[c], childrenbounds[c], minstrength, infinity, cutoff);
11332       }
11333 
11334       BMSfreeBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren);
11335 
11336       break;
11337    }
11338 
11339    case SCIP_EXPR_LAST:
11340       SCIPABORT();
11341       break;
11342    }
11343 }
11344 
11345 /** removes duplicate children in a polynomial expression node
11346  *
11347  *  Leaves NULL's in children array.
11348  */
11349 static
exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node)11350 SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(
11351    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
11352    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
11353    )
11354 {
11355    SCIP_Bool foundduplicates;
11356    int* childmap;
11357    int i;
11358    int j;
11359 
11360    assert(exprgraph != NULL);
11361    assert(node != NULL);
11362    assert(node->op == SCIP_EXPR_POLYNOMIAL);
11363 
11364    if( node->nchildren == 0 )
11365       return SCIP_OKAY;
11366 
11367    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
11368 
11369    foundduplicates = FALSE;
11370    for( i = 0; i < node->nchildren; ++i )
11371    {
11372       if( node->children[i] == NULL )
11373          continue;
11374       childmap[i] = i;  /*lint !e644*/
11375 
11376       for( j = i+1; j < node->nchildren; ++j )
11377       {
11378          if( node->children[j] == NULL )
11379             continue;
11380 
11381          if( node->children[i] == node->children[j] )
11382          {
11383             /* node should be parent of children[j] at least twice,
11384              * so we remove it once
11385              */
11386             SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
11387             node->children[j] = NULL;
11388             assert(exprgraphNodeIsParent(node->children[i], node));
11389 
11390             childmap[j] = i;
11391             foundduplicates = TRUE;
11392          }
11393       }
11394    }
11395 
11396    /* apply childmap to monomials */
11397    if( foundduplicates )
11398       polynomialdataApplyChildmap((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, childmap);
11399 
11400    /* free childmap */
11401    BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
11402 
11403    return SCIP_OKAY;
11404 }
11405 
11406 /** eliminates NULL's in children array and shrinks it to actual size */
11407 static
exprgraphNodeRemovePolynomialNullChildren(BMS_BLKMEM * blkmem,SCIP_EXPRGRAPHNODE * node)11408 SCIP_RETCODE exprgraphNodeRemovePolynomialNullChildren(
11409    BMS_BLKMEM*           blkmem,             /**< block memory */
11410    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
11411    )
11412 {
11413    int* childmap;
11414    int lastnonnull;
11415    int i;
11416 
11417    assert(blkmem != NULL);
11418    assert(node != NULL);
11419    assert(node->op == SCIP_EXPR_POLYNOMIAL);
11420 
11421    if( node->nchildren == 0 )
11422       return SCIP_OKAY;
11423 
11424    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
11425 
11426    /* close gaps in children array */
11427    lastnonnull = node->nchildren-1;
11428    while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11429       --lastnonnull;
11430    for( i = 0; i <= lastnonnull; ++i )
11431    {
11432       if( node->children[i] != NULL )
11433       {
11434          childmap[i] = i; /* child at index i is not moved */  /*lint !e644*/
11435          continue;
11436       }
11437       assert(node->children[lastnonnull] != NULL);
11438 
11439       /* move child at lastnonnull to position i */
11440       node->children[i] = node->children[lastnonnull];
11441       node->children[lastnonnull] = NULL;
11442       childmap[lastnonnull] = i;
11443 
11444       /* update lastnonnull */
11445       --lastnonnull;
11446       while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11447          --lastnonnull;
11448    }
11449    assert(i > lastnonnull);
11450 
11451    /* apply childmap to monomials */
11452    if( lastnonnull < node->nchildren-1 )
11453       polynomialdataApplyChildmap((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, childmap);
11454 
11455    BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
11456 
11457    /* shrink children array */
11458    if( lastnonnull >= 0 )
11459    {
11460       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
11461       node->nchildren = lastnonnull+1;
11462    }
11463    else
11464    {
11465       BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11466       node->nchildren = 0;
11467    }
11468 
11469    return SCIP_OKAY;
11470 }
11471 
11472 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
11473  *
11474  *  Converts node into polynomial, if possible and not constant.
11475  */
11476 static
exprgraphNodeSimplify(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,SCIP_MESSAGEHDLR * messagehdlr,SCIP_Real eps,int maxexpansionexponent,SCIP_Bool * havechange)11477 SCIP_RETCODE exprgraphNodeSimplify(
11478    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
11479    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node */
11480    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
11481    SCIP_Real             eps,                /**< threshold, under which positive values are treat as 0 */
11482    int                   maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
11483    SCIP_Bool*            havechange          /**< flag to set if the node has been changed */
11484    )
11485 {
11486    SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11487    SCIP_EXPRDATA_MONOMIAL* monomial;
11488    BMS_BLKMEM* blkmem;
11489    SCIP_Bool removechild;
11490    SCIP_Bool* childinuse;
11491    int* childmap;
11492    int childmapsize;
11493    int i;
11494    int j;
11495    int orignchildren;
11496 
11497    assert(exprgraph != NULL);
11498    assert(node != NULL);
11499    assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
11500    assert(havechange != NULL);
11501 
11502    blkmem = exprgraph->blkmem;
11503    assert(blkmem != NULL);
11504 
11505    SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
11506 
11507    /* if all children are constants, then turn this node into constant */
11508    for( i = 0; i < node->nchildren; ++i )
11509       if( node->children[i]->op != SCIP_EXPR_CONST )
11510          break;
11511    if( node->nchildren > 0 && i == node->nchildren )
11512    {
11513       /* get value of node */
11514       SCIP_CALL( exprgraphNodeEvalWithChildren(node, NULL) );
11515       assert(node->value != SCIP_INVALID);  /*lint !e777*/
11516 
11517       SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
11518       SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11519       SCIPdebugPrintf("\n");
11520 
11521       /* free expression data */
11522       if( exprOpTable[node->op].freedata != NULL )
11523          exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
11524 
11525       /* disconnect from children */
11526       for( i = 0; i < node->nchildren; ++i )
11527       {
11528          SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11529       }
11530       BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11531       node->nchildren = 0;
11532 
11533       /* turn into constant expression */
11534       node->op = SCIP_EXPR_CONST;
11535       node->data.dbl = node->value;
11536 
11537       *havechange = TRUE;
11538       node->simplified = TRUE;
11539 
11540       return SCIP_OKAY;
11541    }
11542 
11543    /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
11544     * @todo log(product) -> sum(log)
11545     * @todo product(exp) -> exp(sum)
11546     * @todo exp(x)^p -> exp(p*x)
11547     * @todo exp(const*log(x)) -> x^const
11548     */
11549 
11550    SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
11551 
11552    if( node->op != SCIP_EXPR_POLYNOMIAL )
11553    {
11554       node->simplified = TRUE;
11555       return SCIP_OKAY;
11556    }
11557 
11558    polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11559    assert(polynomialdata != NULL);
11560 
11561    orignchildren = node->nchildren;
11562 
11563    /* check if we have duplicate children and merge */
11564    SCIP_CALL( exprgraphNodeRemovePolynomialDuplicateChildren(exprgraph, node) );
11565    polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11566 
11567    SCIPdebugMessage("expand factors in expression node ");
11568    SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11569    SCIPdebugPrintf("\n");
11570 
11571    childmap = NULL;
11572    childmapsize = 0;
11573 
11574    /* resolve children that are constants
11575     * we do this first, because it reduces the degree and number of factors in the monomials,
11576     *   thereby allowing some expansions of polynomials that may not be possible otherwise, e.g., turning c0*c1 with c0=quadratic and c1=constant into a single monomial
11577     */
11578    for( i = 0; i < node->nchildren; ++i )
11579    {
11580       if( node->children[i] == NULL )
11581          continue;
11582 
11583       /* convert children to polynomial, if not constant or polynomial
11584        * if child was simplified in this round, it may have already been converted, and then nothing happens
11585        * but if child was already simplified, then it was not converted, and thus we try it here
11586        */
11587       if( node->children[i]->op != SCIP_EXPR_CONST )
11588          continue;
11589 
11590       SCIPdebugMessage("expand child %d in expression node ", i);
11591       SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11592       SCIPdebugPrintf("\n\tchild = ");
11593       SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11594       SCIPdebugPrintf("\n");
11595 
11596       removechild = TRUE; /* we intend to release children[i] */
11597 
11598       ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11599 
11600       /* put constant of child i into every monomial where child i is used */
11601       for( j = 0; j < polynomialdata->nmonomials; ++j )
11602       {
11603          int factorpos;
11604 
11605          monomial = polynomialdata->monomials[j];
11606          /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11607          assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11608 
11609          if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11610          {
11611             assert(factorpos >= 0);
11612             assert(factorpos < monomial->nfactors);
11613             /* assert that factors have been merged */
11614             assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11615             assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11616 
11617             SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11618 
11619             if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 )  /*lint !e835*/
11620             {
11621                /* if constant is negative and our exponent is not integer, then cannot do expansion */
11622                SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
11623                removechild = FALSE;
11624             }
11625             else
11626             {
11627                monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
11628 
11629                /* move last factor to position factorpos */
11630                if( factorpos < monomial->nfactors-1 )
11631                {
11632                   monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
11633                   monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
11634                }
11635                --monomial->nfactors;
11636                monomial->sorted = FALSE;
11637                polynomialdata->sorted = FALSE;
11638 
11639                *havechange = TRUE;
11640             }
11641          }
11642       }
11643 
11644       /* forget about child i, if it is not used anymore */
11645       if( removechild )
11646       {
11647          /* remove node from list of parents of child i */
11648          SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11649          node->children[i] = NULL;
11650       }
11651 
11652       /* simplify current polynomial again */
11653       polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11654    }
11655 
11656    /* resolve children that are polynomials itself */
11657    for( i = 0; i < node->nchildren; ++i )
11658    {
11659       if( node->children[i] == NULL )
11660          continue;
11661 
11662       /* convert children to polynomial, if not constant or polynomial
11663        * if child was simplified in this round, it may have already been converted, and then nothing happens
11664        * but if child was already simplified, then it was not converted, and thus we try it here
11665        */
11666       SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
11667 
11668       if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
11669          continue;
11670 
11671       SCIPdebugMessage("expand child %d in expression node %p = ", i, (void*)node);
11672       SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11673       SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n\tchild = ") );
11674       SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11675       SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
11676 
11677       removechild = TRUE; /* we intend to release children[i] */
11678 
11679       ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11680 
11681       /* add children of child i to node */
11682       SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
11683 
11684       /* put polynomial of child i into every monomial where child i is used */
11685       j = 0;
11686       while( j < polynomialdata->nmonomials )
11687       {
11688          int factorpos;
11689          SCIP_Bool success;
11690 
11691          monomial = polynomialdata->monomials[j];
11692          /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11693          assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11694 
11695          /* make sure factors are merged, should only be potentially necessary if not sorted, see also #1848 */
11696          if( !monomial->sorted )
11697             SCIPexprMergeMonomialFactors(monomial, eps);
11698 
11699          if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11700          {
11701             ++j;
11702             continue;
11703          }
11704 
11705          assert(factorpos >= 0);
11706          assert(factorpos < monomial->nfactors);
11707          /* assert that factors have been merged */
11708          assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11709          assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11710 
11711          SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11712 
11713          SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
11714                (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
11715 
11716          if( !success )
11717          {
11718             removechild = FALSE;
11719             ++j;
11720          }
11721          else
11722             *havechange = TRUE;
11723 
11724          /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
11725           * we thus repeat with index j, if a factor was successfully expanded
11726           */
11727       }
11728 
11729       /* forget about child i, if it is not used anymore */
11730       if( removechild )
11731       {
11732          /* remove node from list of parents of child i */
11733          SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11734          node->children[i] = NULL;
11735       }
11736    }
11737 
11738    /* simplify current polynomial again */
11739    polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11740 
11741    BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
11742 
11743    /* check which children are still in use */
11744    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
11745    BMSclearMemoryArray(childinuse, node->nchildren);  /*lint !e644*/
11746    for( i = 0; i < polynomialdata->nmonomials; ++i )
11747    {
11748       monomial = polynomialdata->monomials[i];
11749       assert(monomial != NULL);
11750 
11751       for( j = 0; j < monomial->nfactors; ++j )
11752       {
11753          assert(monomial->childidxs[j] >= 0);
11754          assert(monomial->childidxs[j] < node->nchildren);
11755          childinuse[monomial->childidxs[j]] = TRUE;
11756       }
11757    }
11758 
11759    /* free children that are not used in any monomial */
11760    for( i = 0; i < node->nchildren; ++i )
11761       if( node->children[i] != NULL && !childinuse[i] )
11762       {
11763          SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11764          node->children[i] = NULL;
11765       }
11766 
11767    BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11768 
11769    /* remove NULLs from children array */
11770    SCIP_CALL( exprgraphNodeRemovePolynomialNullChildren(blkmem, node) );
11771 
11772    /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11773    if( node->nchildren == 0 )
11774    {
11775       SCIP_Real val;
11776 
11777       /* if no children, then it should also have no monomials */
11778       assert(polynomialdata->nmonomials == 0);
11779 
11780       val = polynomialdata->constant;
11781       polynomialdataFree(blkmem, &polynomialdata);
11782 
11783       node->op = SCIP_EXPR_CONST;
11784       node->data.dbl = val;
11785       node->value = val;
11786    }
11787 
11788    /* if no factor in a monomial was replaced, the number of children should not have changed
11789     * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11790     */
11791    *havechange |= (node->nchildren < orignchildren);  /*lint !e514*/
11792 
11793    node->simplified = TRUE;
11794 
11795    SCIPdebugMessage("-> %p = ", (void*)node);
11796    SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11797    SCIPdebugPrintf("\n");
11798 
11799    return SCIP_OKAY;
11800 }
11801 
11802 /** creates an expression from a given node in an expression graph
11803  *
11804  *  Assembles mapping of variables from graph to tree.
11805  */
11806 static
exprgraphNodeCreateExpr(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,SCIP_EXPR ** expr,int * nexprvars,int * varidx)11807 SCIP_RETCODE exprgraphNodeCreateExpr(
11808    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
11809    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node which expression should be created */
11810    SCIP_EXPR**           expr,               /**< buffer to store pointer to created expression */
11811    int*                  nexprvars,          /**< current number of variables in expression */
11812    int*                  varidx              /**< current mapping of variable indices from graph to expression */
11813    )
11814 {
11815    SCIP_EXPR** childexprs;
11816    int i;
11817 
11818    assert(exprgraph != NULL);
11819    assert(node != NULL);
11820    assert(expr != NULL);
11821    assert(nexprvars != NULL);
11822    assert(*nexprvars >= 0);
11823    assert(varidx != NULL);
11824 
11825    childexprs = NULL;
11826    if( node->nchildren > 0 )
11827    {
11828       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11829       for( i = 0; i < node->nchildren; ++i )
11830       {
11831          SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) );  /*lint !e613*/
11832       }
11833    }
11834 
11835    switch( node->op )
11836    {
11837    case SCIP_EXPR_VARIDX:
11838    {
11839       /* check if the variable already has an index assigned in the expression tree
11840        * if not, create one and increase nexprvars
11841        */
11842       assert(node->data.intval >= 0);
11843       assert(node->data.intval < exprgraph->nvars);
11844       assert(varidx[node->data.intval] >= -1);
11845       assert(varidx[node->data.intval] < *nexprvars);
11846       if( varidx[node->data.intval] == -1 )
11847       {
11848          varidx[node->data.intval] = *nexprvars;
11849          ++*nexprvars;
11850       }
11851 
11852       SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11853       break;
11854    }
11855 
11856    case SCIP_EXPR_CONST:
11857    {
11858       SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11859       break;
11860    }
11861 
11862    case SCIP_EXPR_REALPOWER:
11863    case SCIP_EXPR_SIGNPOWER:
11864    {
11865       assert(node->nchildren == 1);
11866       assert(childexprs != NULL);
11867       /* coverity[var_deref_op] */
11868       SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) );  /*lint !e613*/
11869       break;
11870    }
11871 
11872    case SCIP_EXPR_INTPOWER:
11873    {
11874       assert(node->nchildren == 1);
11875       assert(childexprs != NULL);
11876       /* coverity[var_deref_op] */
11877       SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) );  /*lint !e613*/
11878       break;
11879    }
11880 
11881    case SCIP_EXPR_PLUS:
11882    case SCIP_EXPR_MINUS:
11883    case SCIP_EXPR_MUL:
11884    case SCIP_EXPR_DIV:
11885    case SCIP_EXPR_MIN:
11886    case SCIP_EXPR_MAX:
11887    {
11888       assert(node->nchildren == 2);
11889       assert(childexprs != NULL);
11890       /* coverity[var_deref_op] */
11891       SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) );  /*lint !e613*/
11892       break;
11893    }
11894 
11895    case SCIP_EXPR_SQUARE:
11896    case SCIP_EXPR_SQRT:
11897    case SCIP_EXPR_EXP:
11898    case SCIP_EXPR_LOG:
11899    case SCIP_EXPR_SIN:
11900    case SCIP_EXPR_COS:
11901    case SCIP_EXPR_TAN:
11902       /* case SCIP_EXPR_ERF: */
11903       /* case SCIP_EXPR_ERFI: */
11904    case SCIP_EXPR_ABS:
11905    case SCIP_EXPR_SIGN:
11906    {
11907       assert(node->nchildren == 1);
11908       assert(childexprs != NULL);
11909       /* coverity[var_deref_op] */
11910       SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) );  /*lint !e613*/
11911       break;
11912    }
11913 
11914    case SCIP_EXPR_SUM:
11915    case SCIP_EXPR_PRODUCT:
11916    {
11917       SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11918       break;
11919    }
11920 
11921    case SCIP_EXPR_LINEAR:
11922    {
11923       assert(node->data.data != NULL);
11924 
11925       SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11926       break;
11927    }
11928 
11929    case SCIP_EXPR_QUADRATIC:
11930    {
11931       SCIP_EXPRDATA_QUADRATIC* quaddata;
11932 
11933       quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11934       assert(quaddata != NULL);
11935 
11936       SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11937             quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11938       break;
11939    }
11940 
11941    case SCIP_EXPR_POLYNOMIAL:
11942    {
11943       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11944 
11945       polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11946       assert(polynomialdata != NULL);
11947 
11948       SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11949             polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11950 
11951       break;
11952    }
11953 
11954    case SCIP_EXPR_USER:
11955    {
11956       SCIP_EXPRDATA_USER* exprdata;
11957       SCIP_USEREXPRDATA* userdata;
11958 
11959       exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11960       assert(exprdata != NULL);
11961 
11962       if( exprdata->copydata != NULL )
11963       {
11964          SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11965       }
11966       else
11967          userdata = exprdata->userdata;
11968 
11969       /* coverity[var_deref_op] */
11970       /* coverity[var_deref_model] */
11971       SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11972          userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata, exprdata->print) );
11973 
11974       break;
11975    }
11976 
11977    case SCIP_EXPR_LAST:
11978    case SCIP_EXPR_PARAM:
11979    {
11980       SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11981       return SCIP_ERROR;
11982    }
11983    }
11984 
11985    BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11986 
11987    return SCIP_OKAY;
11988 }
11989 
11990 /** counts how often expression graph variables are used in a subtree of the expression graph
11991  *
11992  *  @note The function does not clear the array first, but only increases already existing counts.
11993  */
11994 static
exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE * node,int * varsusage)11995 void exprgraphNodeGetVarsUsage(
11996    SCIP_EXPRGRAPHNODE*   node,               /**< root node of expression graph subtree */
11997    int*                  varsusage           /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11998    )
11999 {
12000    int i;
12001 
12002    assert(node != NULL);
12003    assert(varsusage != NULL);
12004 
12005    if( node->op == SCIP_EXPR_VARIDX )
12006    {
12007       ++varsusage[node->data.intval];
12008       return;
12009    }
12010 
12011    for( i = 0; i < node->nchildren; ++i )
12012       exprgraphNodeGetVarsUsage(node->children[i], varsusage);
12013 }
12014 
12015 /** checks whether a node can be put into a component when checking block separability of an expression
12016  *
12017  *  If a variable used by node is already in another component, components are merged and component number is updated.
12018  */
12019 static
exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE * node,int * compnr,int nchildcomps,int * childcomps,int nvars,int * varcomps)12020 void exprgraphNodeCheckSeparabilityComponent(
12021    SCIP_EXPRGRAPHNODE*   node,               /**< node to which we assign a component */
12022    int*                  compnr,             /**< component number to assign, may be reduced if variables overlap */
12023    int                   nchildcomps,        /**< number of entries for which childcomps have been set already */
12024    int*                  childcomps,         /**< component numbers of children */
12025    int                   nvars,              /**< number of variables */
12026    int*                  varcomps            /**< component numbers of variables */
12027    )
12028 {
12029    int varidx;
12030    int i;
12031 
12032    assert(node != NULL);
12033    assert(compnr != NULL);
12034    assert(*compnr >= 0);
12035    assert(childcomps != NULL);
12036    assert(varcomps != NULL);
12037 
12038    if( node->op != SCIP_EXPR_VARIDX )
12039    {
12040       for( i = 0; i < node->nchildren; ++i )
12041          exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
12042       return;
12043    }
12044 
12045    varidx = node->data.intval;
12046    assert(varidx >= 0);
12047    assert(varidx < nvars);
12048 
12049    if( varcomps[varidx] == -1 )
12050    {
12051       /* first time we get to this variable, so set it's component to compnr and we are done */
12052       varcomps[varidx] = *compnr;
12053       return;
12054    }
12055 
12056    if( varcomps[varidx] == *compnr )
12057    {
12058       /* variable is already in current component, that's also good and we are done */
12059       return;
12060    }
12061 
12062    /* variable is already in another component, so have to merge component compnr into that component
12063     * do this by updating varcomps and childcomps */
12064    for( i = 0; i < nvars; ++i )
12065       if( varcomps[i] == *compnr )
12066          varcomps[i] = varcomps[varidx];
12067    for( i = 0; i < nchildcomps; ++i )
12068       if( childcomps[i] == *compnr )
12069          /* coverity[copy_paste_error] */
12070          childcomps[i] = varcomps[varidx];
12071    *compnr = varcomps[varidx];
12072 }
12073 
12074 /**@} */
12075 
12076 /**@name Expression graph private methods */
12077 /**@{ */
12078 
12079 /** assert that expression graph has at least a given depth */
12080 static
exprgraphEnsureDepth(SCIP_EXPRGRAPH * exprgraph,int mindepth)12081 SCIP_RETCODE exprgraphEnsureDepth(
12082    SCIP_EXPRGRAPH*       exprgraph,          /**< buffer to store pointer to expression graph */
12083    int                   mindepth            /**< minimal depth that should be ensured */
12084    )
12085 {
12086    int olddepth;
12087 
12088    assert(exprgraph != NULL);
12089    assert(exprgraph->blkmem != NULL);
12090 
12091    if( mindepth <= exprgraph->depth )
12092       return SCIP_OKAY;
12093 
12094    olddepth = exprgraph->depth;
12095    ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
12096    assert(exprgraph->depth >= mindepth);
12097 
12098    /* initialize new array entries to 0 and NULL, resp. */
12099    BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth);  /*lint !e866*/
12100    BMSclearMemoryArray(&exprgraph->nnodes[olddepth],    exprgraph->depth - olddepth);  /*lint !e866*/
12101    BMSclearMemoryArray(&exprgraph->nodes[olddepth],     exprgraph->depth - olddepth);  /*lint !e866*/
12102 
12103    return SCIP_OKAY;
12104 }
12105 
12106 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
12107 static
exprgraphRemoveVar(SCIP_EXPRGRAPH * exprgraph,int varidx)12108 SCIP_RETCODE exprgraphRemoveVar(
12109    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
12110    int                   varidx              /**< variable index */
12111    )
12112 {
12113    SCIP_EXPRGRAPHNODE* varnode;
12114    void* var;
12115 
12116    assert(exprgraph != NULL);
12117    assert(varidx >= 0);
12118    assert(varidx < exprgraph->nvars);
12119 
12120    varnode = exprgraph->varnodes[varidx];
12121    assert(varnode->data.intval == varidx);
12122 
12123    var = exprgraph->vars[varidx];
12124 
12125    /* call varremove callback method, if set */
12126    if( exprgraph->exprgraphvarremove != NULL )
12127    {
12128       SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
12129    }
12130 
12131    /* remove variable from hashmap */
12132    SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
12133 
12134    /* move last variable to position varidx and give it the new index */
12135    if( varidx < exprgraph->nvars-1 )
12136    {
12137       /* call callback method, if set */
12138       if( exprgraph->exprgraphvarchgidx != NULL )
12139       {
12140          SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
12141       }
12142 
12143       exprgraph->vars[varidx]      = exprgraph->vars[exprgraph->nvars-1];
12144       exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
12145       exprgraph->varnodes[varidx]  = exprgraph->varnodes[exprgraph->nvars-1];
12146       exprgraph->varnodes[varidx]->data.intval = varidx;
12147       SCIP_CALL( SCIPhashmapSetImageInt(exprgraph->varidxs, exprgraph->vars[varidx], varidx) );
12148    }
12149    --exprgraph->nvars;
12150 
12151    return SCIP_OKAY;
12152 }
12153 
12154 /** moves a node in an expression graph to a different depth
12155  *
12156  *  New depth must be larger than children depth.
12157  *  Moves parent nodes to higher depth, if needed.
12158  *  Variable nodes cannot be moved.
12159  */
12160 static
exprgraphMoveNode(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,int newdepth)12161 SCIP_RETCODE exprgraphMoveNode(
12162    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
12163    SCIP_EXPRGRAPHNODE*   node,               /**< node that shall be moved */
12164    int                   newdepth            /**< new depth to which to move node */
12165    )
12166 {
12167    int olddepth;
12168    int oldpos;
12169    int i;
12170 
12171    assert(exprgraph != NULL);
12172    assert(node != NULL);
12173    assert(node->depth >= 0); /* node should be in graph */
12174    assert(newdepth >= 0);
12175 
12176    /* if already on aimed depth, then don't need to move */
12177    if( node->depth == newdepth )
12178       return SCIP_OKAY;
12179 
12180    SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
12181 
12182 #ifndef NDEBUG
12183    /* assert that children are at lower depth than new depth */
12184    for( i = 0; i < node->nchildren; ++i )
12185       assert(node->children[i]->depth < newdepth);
12186 #endif
12187 
12188    /* move parents to higher depth, if needed */
12189    for( i = 0; i < node->nparents; ++i )
12190    {
12191       if( node->parents[i]->depth <= newdepth )
12192       {
12193          /* move parent to depth+1 */
12194          SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
12195          assert(node->parents[i]->depth > newdepth);
12196       }
12197    }
12198 
12199    /* ensure that graph is deep enough */
12200    SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
12201    assert(exprgraph->depth > newdepth);
12202 
12203    olddepth = node->depth;
12204    oldpos   = node->pos;
12205 
12206    /* add node to new depth */
12207    ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1);  /*lint !e866*/
12208    node->depth = newdepth;
12209    node->pos   = exprgraph->nnodes[newdepth];
12210    exprgraph->nodes[newdepth][node->pos] = node;
12211    ++exprgraph->nnodes[newdepth];
12212 
12213    /* by moving the node to a new depth, the parents array in all its childrens may not be sorted anymore (parents order depends on depth) */
12214    for( i = 0; i < node->nchildren; ++i )
12215       node->children[i]->parentssorted = FALSE;
12216 
12217    /* move last node at previous depth to previous position, if it wasn't last */
12218    if( oldpos < exprgraph->nnodes[olddepth]-1 )
12219    {
12220       exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
12221       exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
12222 
12223       /* by moving the node to a new position, the parents array in all its children may not be sorted anymore (parents order depends on depth) */
12224       for( i = 0; i < exprgraph->nodes[olddepth][oldpos]->nchildren; ++i )
12225          exprgraph->nodes[olddepth][oldpos]->children[i]->parentssorted = FALSE;
12226    }
12227    --exprgraph->nnodes[olddepth];
12228 
12229    if( node->depth == 0 )
12230    {
12231       /* if at depth 0, then it need to be a node for either a constant or a variable */
12232       assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
12233       if( node->op == SCIP_EXPR_CONST )
12234       {
12235          /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
12236          ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
12237          exprgraph->constnodes[exprgraph->nconsts] = node;
12238          ++exprgraph->nconsts;
12239          exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
12240       }
12241       else
12242       {
12243          /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
12244          SCIPerrorMessage("cannot move variable nodes to depth 0\n");
12245          return SCIP_ERROR;
12246       }
12247 
12248       /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
12249       node->curv = SCIP_EXPRCURV_LINEAR;
12250    }
12251 
12252    return SCIP_OKAY;
12253 }
12254 
12255 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
12256 static
exprgraphFindParentByOperator(SCIP_EXPRGRAPH * exprgraph,int nchildren,SCIP_EXPRGRAPHNODE ** children,SCIP_EXPROP op,SCIP_EXPROPDATA opdata,SCIP_EXPR ** exprchildren,SCIP_EXPRGRAPHNODE ** parent)12257 SCIP_RETCODE exprgraphFindParentByOperator(
12258    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
12259    int                   nchildren,          /**< number of children */
12260    SCIP_EXPRGRAPHNODE**  children,           /**< children which parents to inspect */
12261    SCIP_EXPROP           op,                 /**< operator */
12262    SCIP_EXPROPDATA       opdata,             /**< operator data */
12263    SCIP_EXPR**           exprchildren,       /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12264    SCIP_EXPRGRAPHNODE**  parent              /**< buffer to store parent node if any is found, or NULL if none found */
12265    )
12266 {
12267    SCIP_EXPRGRAPHNODE** parentcands;
12268    int nparentcands;
12269    int parentcandssize;
12270    int i;
12271    int p;
12272 
12273    assert(exprgraph != NULL);
12274    assert(nchildren > 0);
12275    assert(children != NULL);
12276    assert(parent != NULL);
12277 
12278    *parent = NULL;
12279 
12280    /* create initial set of parent candidates as
12281     * all parents of first child that have the same operator type and the same number of children
12282     * additionally, some easy conditions for complex expression types:
12283     * if expression type is int/real/signpower, then compare also exponent,
12284     * if expression type is linear, then compare also constant part,
12285     * if expression type is quadratic, then compare also number of quadratic elements,
12286     * if expression type is polynomial, then compare also number of monmials and constant part
12287     */
12288    parentcandssize = children[0]->nparents;
12289    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12290    nparentcands = 0;
12291    for( p = 0; p < children[0]->nparents; ++p )
12292       if( children[0]->parents[p]->op == op &&
12293          children[0]->parents[p]->nchildren == nchildren &&
12294          (op != SCIP_EXPR_INTPOWER   || opdata.intval == children[0]->parents[p]->data.intval) &&
12295          (op != SCIP_EXPR_REALPOWER  || opdata.dbl == children[0]->parents[p]->data.dbl) &&  /*lint !e777*/
12296          (op != SCIP_EXPR_SIGNPOWER  || opdata.dbl == children[0]->parents[p]->data.dbl) &&  /*lint !e777*/
12297          (op != SCIP_EXPR_LINEAR     || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) &&  /*lint !e777*/
12298          (op != SCIP_EXPR_QUADRATIC  || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12299          (op != SCIP_EXPR_QUADRATIC  || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) &&  /*lint !e777*/
12300          (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12301          (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant)  /*lint !e777*/
12302          )
12303       {
12304          parentcands[nparentcands++] = children[0]->parents[p];  /*lint !e644*/
12305       }
12306 
12307    /* for all remaining children, remove parent candidates, that are not in their list of parents */
12308    for( i = 1; i < nchildren && nparentcands > 0; ++i )
12309    {
12310       p = 0;
12311       while( p < nparentcands )
12312       {
12313          /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12314           * otherwise keep candidate and check next one
12315           */
12316          if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12317          {
12318             parentcands[p] = parentcands[nparentcands-1];
12319             --nparentcands;
12320          }
12321          else
12322             ++p;
12323       }
12324    }
12325 
12326    SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12327 
12328    if( nparentcands == 0 )
12329    {
12330       BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12331       return SCIP_OKAY;
12332    }
12333 
12334    /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12335     * check if there is also one which corresponds to same expression and store that one in *parent
12336     */
12337    switch( op )
12338    {
12339       /* commutative operands with no data */
12340    case SCIP_EXPR_PLUS   :
12341    case SCIP_EXPR_MUL    :
12342    case SCIP_EXPR_MIN    :
12343    case SCIP_EXPR_MAX    :
12344    case SCIP_EXPR_SUM    :
12345    case SCIP_EXPR_PRODUCT:
12346    case SCIP_EXPR_SQUARE :
12347    case SCIP_EXPR_SQRT   :
12348    case SCIP_EXPR_EXP    :
12349    case SCIP_EXPR_LOG    :
12350    case SCIP_EXPR_SIN    :
12351    case SCIP_EXPR_COS    :
12352    case SCIP_EXPR_TAN    :
12353       /* case SCIP_EXPR_ERF    : */
12354       /* case SCIP_EXPR_ERFI   : */
12355    case SCIP_EXPR_ABS    :
12356    case SCIP_EXPR_SIGN   :
12357    {
12358       /* sort childnodes, if needed for later */
12359       if( nchildren > 2 )
12360          SCIPsortPtr((void**)children, exprgraphnodecomp, nchildren);
12361       for( p = 0; p < nparentcands; ++p )
12362       {
12363          assert(parentcands[p]->op        == op);        /* that was the first  criterium for adding a node to parentcands */
12364          assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12365 
12366          if( nchildren == 1 )
12367          {
12368             assert(parentcands[p]->children[0] == children[0]);
12369             /* same operand, same child, so same expression */
12370             *parent = parentcands[p];
12371             break;
12372          }
12373          else if( nchildren == 2 )
12374          {
12375             /* We know that every node in children is also a child of parentcands[p].
12376              * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12377              * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12378              */
12379             if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12380                ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12381             {
12382                *parent = parentcands[p];
12383                break;
12384             }
12385          }
12386          else
12387          {
12388             /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12389 
12390             /* sort children of parent candidate */
12391             SCIPsortPtr((void**)parentcands[p]->children, exprgraphnodecomp, nchildren);
12392 
12393             /* check if childnodes and parentcands[p]->children are the same */
12394             for( i = 0; i < nchildren; ++i )
12395                if( children[i] != parentcands[p]->children[i] )
12396                   break;
12397             if( i == nchildren )
12398             {
12399                /* yeah, found an exact match */
12400                *parent = parentcands[p];
12401                break;
12402             }
12403          }
12404       }
12405 
12406       break;
12407    }
12408 
12409    /* non-commutative operands with two children */
12410    case SCIP_EXPR_MINUS    :
12411    case SCIP_EXPR_DIV      :
12412    {
12413       for( p = 0; p < nparentcands; ++p )
12414       {
12415          assert(parentcands[p]->op == op); /* that was the first  criterium for adding a node to parentcands */
12416          assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12417          /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12418          if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12419          {
12420             /* yeah, found one */
12421             *parent = parentcands[p];
12422             break;
12423          }
12424       }
12425 
12426       break;
12427    }
12428 
12429    /* operands with one child and data */
12430    case SCIP_EXPR_INTPOWER:
12431    {
12432       assert(parentcands[0]->op == op); /* that was the first  criterium for adding a node to parentcands */
12433       assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12434       assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12435       assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12436 
12437       /* yeah, have one with same exponent */
12438       *parent = parentcands[0];
12439 
12440       break;
12441    }
12442 
12443    case SCIP_EXPR_REALPOWER:
12444    case SCIP_EXPR_SIGNPOWER:
12445    {
12446       assert(parentcands[0]->op == op); /* that was the first  criterium for adding a node to parentcands */
12447       assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12448       assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12449       assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */  /*lint !e777*/
12450 
12451       /* yeah, have one with same exponent */
12452       *parent = parentcands[0];
12453 
12454       break;
12455    }
12456 
12457    /* commutative operands with n children and data */
12458    case SCIP_EXPR_LINEAR:
12459    {
12460       SCIP_Real* exprcoef;
12461       SCIP_Real* candcoef;
12462 
12463       exprcoef = (SCIP_Real*)opdata.data;
12464       /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12465       if( exprchildren != NULL )
12466          SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, exprgraphnodecomp, nchildren);
12467       else
12468          SCIPsortPtrReal((void**)children, exprcoef, exprgraphnodecomp, nchildren);
12469       for( p = 0; p < nparentcands; ++p )
12470       {
12471          assert(parentcands[p]->op        == op);        /* that was the first  criterium for adding a node to parentcands */
12472          assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12473 
12474          candcoef = (SCIP_Real*)parentcands[p]->data.data;
12475          assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */  /*lint !e777*/
12476 
12477          /* sort children of parent candidate */
12478          SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, exprgraphnodecomp, nchildren);
12479 
12480          /* check if children and coefficients in parent candidate and expression are the same */
12481          for( i = 0; i < nchildren; ++i )
12482          {
12483             if( children[i] != parentcands[p]->children[i] )
12484                break;
12485             if( exprcoef[i] != candcoef[i] )  /*lint !e777*/
12486                break;
12487          }
12488          if( i < nchildren )
12489             continue;
12490 
12491          /* yeah, found an exact match */
12492          *parent = parentcands[p];
12493          break;
12494       }
12495 
12496       break;
12497    }
12498 
12499    case SCIP_EXPR_QUADRATIC:
12500    {
12501       SCIP_EXPRDATA_QUADRATIC* exprdata;
12502       SCIP_Real* exprlincoef;
12503       SCIP_Real* candlincoef;
12504       SCIP_EXPRDATA_QUADRATIC* canddata;
12505       int* perm;
12506       int* invperm;
12507 
12508       exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12509       exprlincoef = exprdata->lincoefs;
12510 
12511       /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12512 
12513       /* sort expr->children and childnodes and store inverse permutation in invperm */
12514       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12515       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm,    nchildren) );
12516       for( i = 0; i < nchildren; ++i )
12517          invperm[i] = i;  /*lint !e644*/
12518 
12519       if( exprlincoef != NULL )
12520          if( exprchildren != NULL )
12521             SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12522          else
12523             SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12524       else
12525          if( exprchildren != NULL )
12526             SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12527          else
12528             SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12529 
12530       /* compute permutation from its inverse */
12531       for( i = 0; i < nchildren; ++i )
12532          perm[invperm[i]] = i;  /*lint !e644*/
12533 
12534       /* apply permuation to exprdata->quadelems and sort again */
12535       for( i = 0; i < exprdata->nquadelems; ++i )
12536       {
12537          exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12538          exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12539          if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12540          {
12541             int tmp;
12542             tmp = exprdata->quadelems[i].idx1;
12543             exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12544             exprdata->quadelems[i].idx2 = tmp;
12545          }
12546       }
12547       SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12548       exprdata->sorted = TRUE;
12549 
12550       for( p = 0; p < nparentcands; ++p )
12551       {
12552          assert(parentcands[p]->op        == op);        /* that was the first  criterium for adding a node to parentcands */
12553          assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12554 
12555          canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12556          candlincoef = canddata->lincoefs;
12557          assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12558          assert(canddata->constant   == exprdata->constant);   /* that was a criterium for adding a node to parentcands */  /*lint !e777*/
12559 
12560          /* sort parentcands[p]->children and store inverse permutation in invperm */
12561          for( i = 0; i < nchildren; ++i )
12562             invperm[i] = i;
12563 
12564          if( candlincoef != NULL )
12565             SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, exprgraphnodecomp, parentcands[p]->nchildren);
12566          else
12567             SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12568 
12569          /* compute permutation from its inverse */
12570          for( i = 0; i < nchildren; ++i )
12571             perm[invperm[i]] = i;
12572 
12573          /* apply permutation to canddata->quadelems */
12574          for( i = 0; i < canddata->nquadelems; ++i )
12575          {
12576             canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12577             canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12578             if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12579             {
12580                int tmp;
12581                tmp = canddata->quadelems[i].idx1;
12582                canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12583                canddata->quadelems[i].idx2 = tmp;
12584             }
12585          }
12586          SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12587          canddata->sorted = TRUE;
12588 
12589          /* check if children and linear coefficients in parent candidate and expression are the same */
12590          for( i = 0; i < nchildren; ++i )
12591          {
12592             if( children[i] != parentcands[p]->children[i] )
12593                break;
12594             if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) )  /*lint !e777*/
12595                break;
12596          }
12597          if( i < nchildren )
12598             continue;
12599 
12600          assert(exprdata->nquadelems == canddata->nquadelems);
12601          for( i = 0; i < exprdata->nquadelems; ++i )
12602          {
12603             if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12604                exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12605                exprdata->quadelems[i].coef != canddata->quadelems[i].coef )  /*lint !e777*/
12606                break;
12607          }
12608          if( i == exprdata->nquadelems )
12609          {
12610             /* yeah, parentcands[p] is same quadratic expression as expr */
12611             *parent = parentcands[p];
12612             break;
12613          }
12614       }
12615 
12616       BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm,    nchildren);
12617       BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12618 
12619       break;
12620    }
12621 
12622    /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12623    case SCIP_EXPR_POLYNOMIAL:
12624    {
12625       SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12626       SCIP_EXPRDATA_POLYNOMIAL* canddata;
12627       int* perm;
12628       int* invperm;
12629 
12630       exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12631 
12632       /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12633 
12634       /* sort exprchildren and childnodes and store inverse permutation in invperm */
12635       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12636       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm,    nchildren) );
12637       for( i = 0; i < nchildren; ++i )
12638          invperm[i] = i;  /*lint !e644*/
12639 
12640       if( exprchildren != NULL )
12641          SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12642       else
12643          SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12644 
12645       /* compute permutation from its inverse */
12646       for( i = 0; i < nchildren; ++i )
12647          perm[invperm[i]] = i;  /*lint !e644*/
12648 
12649       /* apply permutation to exprdata and sort again */
12650       polynomialdataApplyChildmap(exprdata, perm);
12651       polynomialdataSortMonomials(exprdata);
12652 
12653       for( p = 0; p < nparentcands; ++p )
12654       {
12655          assert(parentcands[p]->op        == op);        /* that was the first  criterium for adding a node to parentcands */
12656          assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12657 
12658          canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12659          assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
12660          assert(canddata->constant   == exprdata->constant);   /* that was a criterium for adding a node to parentcands */  /*lint !e777*/
12661 
12662          /* sort parentcands[p]->children and store inverse permutation in invperm */
12663          for( i = 0; i < nchildren; ++i )
12664             invperm[i] = i;
12665 
12666          SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12667 
12668          /* compute permutation from its inverse */
12669          for( i = 0; i < nchildren; ++i )
12670             perm[invperm[i]] = i;
12671 
12672          /* apply permutation to canddata and sort again */
12673          polynomialdataApplyChildmap(canddata, perm);
12674          polynomialdataSortMonomials(canddata);
12675 
12676          /* check if children are equal */
12677          for( i = 0; i < nchildren; ++i )
12678             if( children[i] != parentcands[p]->children[i] )
12679                break;
12680          if( i < nchildren )
12681             continue;
12682 
12683          /* check if monomials are equal */
12684          for( i = 0; i < exprdata->nmonomials; ++i )
12685             if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12686                break;
12687          if( i == exprdata->nmonomials )
12688          {
12689             /* yeah, parentcands[p] is same polynomial expression as expr */
12690             *parent = parentcands[p];
12691             break;
12692          }
12693       }
12694 
12695       BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm,    nchildren);
12696       BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12697 
12698       break;
12699    }
12700 
12701    case SCIP_EXPR_USER:
12702    {
12703       /* @todo need comparison function on user data to decide whether a parent candidate fits */
12704       break;
12705    }
12706 
12707    case SCIP_EXPR_VARIDX:
12708    case SCIP_EXPR_PARAM:
12709    case SCIP_EXPR_CONST:
12710    case SCIP_EXPR_LAST:
12711       SCIPerrorMessage("expression operand %d unexpected here\n", op);
12712       return SCIP_ERROR;
12713    }
12714 
12715    BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12716 
12717    return SCIP_OKAY;
12718 }
12719 
12720 /** adds an expression into an expression graph
12721  *
12722  *  Enables corresponding nodes.
12723  */
12724 static
exprgraphAddExpr(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPR * expr,void ** vars,SCIP_Real * params,SCIP_EXPRGRAPHNODE ** exprnode,SCIP_Bool * exprnodeisnew)12725 SCIP_RETCODE exprgraphAddExpr(
12726    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
12727    SCIP_EXPR*            expr,               /**< expression to add */
12728    void**                vars,               /**< variables corresponding to VARIDX expressions */
12729    SCIP_Real*            params,             /**< parameter values */
12730    SCIP_EXPRGRAPHNODE**  exprnode,           /**< buffer to store expression graph node corresponding to root of this expression */
12731    SCIP_Bool*            exprnodeisnew       /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12732    )
12733 {
12734    SCIP_EXPRGRAPHNODE** childnodes;
12735    SCIP_Bool childisnew;
12736    SCIP_Bool nochildisnew;
12737    SCIP_EXPROPDATA opdata;
12738    int i;
12739 
12740    assert(exprgraph != NULL);
12741    assert(expr != NULL);
12742    assert(exprnode != NULL);
12743    assert(exprnodeisnew != NULL);
12744 
12745    if( expr->op == SCIP_EXPR_VARIDX )
12746    {
12747       /* find node corresponding to variable and add if not existing yet */
12748       assert(expr->nchildren == 0);
12749 
12750       SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12751       assert(*exprnode != NULL);
12752       assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12753       assert((*exprnode)->data.intval >= 0);
12754       assert((*exprnode)->data.intval < exprgraph->nvars);
12755       assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12756 
12757       *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12758 
12759       return SCIP_OKAY;
12760    }
12761 
12762    if( expr->op == SCIP_EXPR_CONST )
12763    {
12764       /* find node corresponding to constant and add if not existing yet */
12765       assert(expr->nchildren == 0);
12766 
12767       SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12768       assert(*exprnode != NULL);
12769       assert((*exprnode)->op == SCIP_EXPR_CONST);
12770       assert((*exprnode)->data.dbl == expr->data.dbl);  /*lint !e777*/
12771 
12772       *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12773 
12774       return SCIP_OKAY;
12775    }
12776 
12777    if( expr->op == SCIP_EXPR_PARAM )
12778    {
12779       /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12780       assert(expr->nchildren == 0);
12781       assert(params != NULL);
12782 
12783       SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12784       assert(*exprnode != NULL);
12785       assert((*exprnode)->op == SCIP_EXPR_CONST);
12786       assert((*exprnode)->data.dbl == params[expr->data.intval]);  /*lint !e777*/
12787 
12788       *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12789 
12790       return SCIP_OKAY;
12791    }
12792 
12793    /* expression should be variable or constant or have children */
12794    assert(expr->nchildren > 0);
12795 
12796    /* add children expressions into expression graph
12797     * check if we can find a common parent
12798     */
12799    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12800    nochildisnew = TRUE;
12801    for( i = 0; i < expr->nchildren; ++i )
12802    {
12803       SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) );  /*lint !e644*/
12804       assert(childnodes[i] != NULL);
12805       nochildisnew &= !childisnew;  /*lint !e514*/
12806    }
12807 
12808    /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12809    if( nochildisnew )
12810    {
12811       SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12812 
12813       if( *exprnode != NULL )
12814       {
12815          /* node already existing, make sure it is enabled */
12816          (*exprnode)->enabled = TRUE;
12817          *exprnodeisnew = FALSE;
12818 
12819          /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12820           * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12821           * SCIPdebugPrintf("\n");
12822           */
12823 
12824          BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12825          return SCIP_OKAY;
12826       }
12827    }
12828 
12829    SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12830 
12831    /* copy expression data */
12832    if( exprOpTable[expr->op].copydata != NULL )
12833    {
12834       SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12835    }
12836    else
12837    {
12838       opdata = expr->data;
12839    }
12840 
12841    SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12842    SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12843    *exprnodeisnew = TRUE;
12844 
12845    BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12846 
12847    /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12848     * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12849     * SCIPdebugPrintf("\n");
12850     */
12851 
12852    return SCIP_OKAY;
12853 }
12854 
12855 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12856 static
exprgraphUpdateVarNodeBounds(SCIP_EXPRGRAPH * exprgraph,SCIP_Bool * clearreverseprop,SCIP_Bool * boundchanged)12857 void exprgraphUpdateVarNodeBounds(
12858    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
12859    SCIP_Bool*            clearreverseprop,   /**< flag to set if we had reset bound tightenings from reverse propagation */
12860    SCIP_Bool*            boundchanged        /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12861    )
12862 {
12863    SCIP_EXPRGRAPHNODE* node;
12864    int i;
12865    int p;
12866 
12867    assert(exprgraph != NULL);
12868    assert(clearreverseprop != NULL);
12869    assert(boundchanged != NULL);
12870 
12871    *boundchanged = FALSE;
12872    for( i = 0; i < exprgraph->nvars; ++i )
12873    {
12874       node = exprgraph->varnodes[i];
12875 
12876       if( node->bounds.inf == exprgraph->varbounds[i].inf &&  /*lint !e777*/
12877          +node->bounds.sup == exprgraph->varbounds[i].sup )   /*lint !e777*/
12878       {
12879          node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
12880          continue;
12881       }
12882 
12883       if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12884       {
12885          /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12886          SCIP_Real tmp;
12887 
12888          tmp = exprgraph->varbounds[i].inf;
12889          exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12890          exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12891       }
12892 
12893       if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12894          +exprgraph->varbounds[i].sup > node->bounds.sup )
12895       {
12896          for( p = 0; p < node->nparents; ++p )
12897             node->parents[p]->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
12898 
12899          node->bounds = exprgraph->varbounds[i];
12900          SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12901 
12902          *boundchanged = TRUE;
12903 
12904          /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12905          *clearreverseprop = TRUE;
12906       }
12907       else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12908          (     isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12909       {
12910          for( p = 0; p < node->nparents; ++p )
12911             node->parents[p]->boundstatus |= SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
12912 
12913          node->bounds = exprgraph->varbounds[i];
12914          SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12915 
12916          *boundchanged = TRUE;
12917       }
12918       else
12919       {
12920          node->bounds = exprgraph->varbounds[i];
12921          SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12922       }
12923 
12924       node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
12925    }
12926 }
12927 
12928 /**@} */
12929 
12930 /**@name Expression graph node methods */
12931 /**@{ */
12932 
12933 /* In debug mode, the following methods are implemented as function calls to ensure
12934  * type validity.
12935  * In optimized mode, the methods are implemented as defines to improve performance.
12936  * However, we want to have them in the library anyways, so we have to undef the defines.
12937  */
12938 
12939 #undef SCIPexprgraphCaptureNode
12940 #undef SCIPexprgraphIsNodeEnabled
12941 #undef SCIPexprgraphGetNodeNChildren
12942 #undef SCIPexprgraphGetNodeChildren
12943 #undef SCIPexprgraphGetNodeNParents
12944 #undef SCIPexprgraphGetNodeParents
12945 #undef SCIPexprgraphGetNodeDepth
12946 #undef SCIPexprgraphGetNodePosition
12947 #undef SCIPexprgraphGetNodeOperator
12948 #undef SCIPexprgraphGetNodeOperatorIndex
12949 #undef SCIPexprgraphGetNodeOperatorReal
12950 #undef SCIPexprgraphGetNodeVar
12951 #undef SCIPexprgraphGetNodeRealPowerExponent
12952 #undef SCIPexprgraphGetNodeIntPowerExponent
12953 #undef SCIPexprgraphGetNodeSignPowerExponent
12954 #undef SCIPexprgraphGetNodeLinearCoefs
12955 #undef SCIPexprgraphGetNodeLinearConstant
12956 #undef SCIPexprgraphGetNodeQuadraticConstant
12957 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12958 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12959 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12960 #undef SCIPexprgraphGetNodePolynomialMonomials
12961 #undef SCIPexprgraphGetNodePolynomialNMonomials
12962 #undef SCIPexprgraphGetNodePolynomialConstant
12963 #undef SCIPexprgraphGetNodeUserData
12964 #undef SCIPexprgraphHasNodeUserEstimator
12965 #undef SCIPexprgraphGetNodeBounds
12966 #undef SCIPexprgraphGetNodeVal
12967 #undef SCIPexprgraphGetNodeCurvature
12968 
12969 /** captures node, i.e., increases number of uses */
SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE * node)12970 void SCIPexprgraphCaptureNode(
12971    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node to capture */
12972    )
12973 {
12974    assert(node->nuses >= 0);
12975 
12976    SCIPdebugMessage("capture node %p\n", (void*)node);
12977 
12978    ++node->nuses;
12979 }
12980 
12981 /** returns whether a node is currently enabled */
SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE * node)12982 SCIP_Bool SCIPexprgraphIsNodeEnabled(
12983    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node to enable */
12984    )
12985 {
12986    assert(node != NULL);
12987 
12988    return node->enabled;
12989 }
12990 
12991 /** gets number of children of a node in an expression graph */
SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE * node)12992 int SCIPexprgraphGetNodeNChildren(
12993    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
12994    )
12995 {
12996    assert(node != NULL);
12997 
12998    return node->nchildren;
12999 }
13000 
13001 /** gets children of a node in an expression graph */
SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE * node)13002 SCIP_EXPRGRAPHNODE** SCIPexprgraphGetNodeChildren(
13003    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13004    )
13005 {
13006    assert(node != NULL);
13007 
13008    return node->children;
13009 }
13010 
13011 /** gets number of parents of a node in an expression graph */
SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE * node)13012 int SCIPexprgraphGetNodeNParents(
13013    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13014    )
13015 {
13016    assert(node != NULL);
13017 
13018    return node->nparents;
13019 }
13020 
13021 /** gets parents of a node in an expression graph */
SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE * node)13022 SCIP_EXPRGRAPHNODE** SCIPexprgraphGetNodeParents(
13023    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13024    )
13025 {
13026    assert(node != NULL);
13027 
13028    return node->parents;
13029 }
13030 
13031 /** gets depth of node in expression graph */
SCIPexprgraphGetNodeDepth(SCIP_EXPRGRAPHNODE * node)13032 int SCIPexprgraphGetNodeDepth(
13033    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13034    )
13035 {
13036    assert(node != NULL);
13037 
13038    return node->depth;
13039 }
13040 
13041 /** gets position of node in expression graph at its depth level */
SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE * node)13042 int SCIPexprgraphGetNodePosition(
13043    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13044    )
13045 {
13046    assert(node != NULL);
13047 
13048    return node->pos;
13049 }
13050 
13051 /** gets operator of a node in an expression graph */
SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE * node)13052 SCIP_EXPROP SCIPexprgraphGetNodeOperator(
13053    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13054    )
13055 {
13056    assert(node != NULL);
13057 
13058    return node->op;
13059 }
13060 
13061 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
SCIPexprgraphGetNodeOperatorIndex(SCIP_EXPRGRAPHNODE * node)13062 int SCIPexprgraphGetNodeOperatorIndex(
13063    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13064    )
13065 {
13066    assert(node != NULL);
13067    assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
13068 
13069    return node->data.intval;
13070 }
13071 
13072 /** gives real belonging to a SCIP_EXPR_CONST operand */
SCIPexprgraphGetNodeOperatorReal(SCIP_EXPRGRAPHNODE * node)13073 SCIP_Real SCIPexprgraphGetNodeOperatorReal(
13074    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13075    )
13076 {
13077    assert(node != NULL);
13078    assert(node->op == SCIP_EXPR_CONST);
13079 
13080    return node->data.dbl;
13081 }
13082 
13083 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node)13084 void* SCIPexprgraphGetNodeVar(
13085    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
13086    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13087    )
13088 {
13089    assert(exprgraph != NULL);
13090    assert(node != NULL);
13091    assert(node->op == SCIP_EXPR_VARIDX);
13092    assert(node->data.intval >= 0);
13093    assert(node->data.intval < exprgraph->nvars);
13094 
13095    return exprgraph->vars[node->data.intval];
13096 }
13097 
13098 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE * node)13099 SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(
13100    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13101    )
13102 {
13103    assert(node != NULL);
13104    assert(node->op == SCIP_EXPR_REALPOWER);
13105 
13106    return node->data.dbl;
13107 }
13108 
13109 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE * node)13110 int SCIPexprgraphGetNodeIntPowerExponent(
13111    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13112    )
13113 {
13114    assert(node != NULL);
13115    assert(node->op == SCIP_EXPR_INTPOWER);
13116 
13117    return node->data.intval;
13118 }
13119 
13120 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE * node)13121 SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(
13122    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13123    )
13124 {
13125    assert(node != NULL);
13126    assert(node->op == SCIP_EXPR_SIGNPOWER);
13127 
13128    return node->data.dbl;
13129 }
13130 
13131 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE * node)13132 SCIP_Real* SCIPexprgraphGetNodeLinearCoefs(
13133    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13134    )
13135 {
13136    assert(node != NULL);
13137    assert(node->op == SCIP_EXPR_LINEAR);
13138 
13139    return (SCIP_Real*)node->data.data;
13140 }
13141 
13142 /** gives constant belonging to a SCIP_EXPR_LINEAR expression  */
SCIPexprgraphGetNodeLinearConstant(SCIP_EXPRGRAPHNODE * node)13143 SCIP_Real SCIPexprgraphGetNodeLinearConstant(
13144    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13145    )
13146 {
13147    assert(node != NULL);
13148    assert(node->op == SCIP_EXPR_LINEAR);
13149    assert(node->data.data != NULL);
13150 
13151    return ((SCIP_Real*)node->data.data)[node->nchildren];
13152 }
13153 
13154 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE * node)13155 SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(
13156    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13157    )
13158 {
13159    assert(node != NULL);
13160    assert(node->op == SCIP_EXPR_QUADRATIC);
13161    assert(node->data.data != NULL);
13162 
13163    return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
13164 }
13165 
13166 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE * node)13167 SCIP_Real* SCIPexprgraphGetNodeQuadraticLinearCoefs(
13168    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13169    )
13170 {
13171    assert(node != NULL);
13172    assert(node->op == SCIP_EXPR_QUADRATIC);
13173    assert(node->data.data != NULL);
13174 
13175    return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
13176 }
13177 
13178 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE * node)13179 SCIP_QUADELEM* SCIPexprgraphGetNodeQuadraticQuadElements(
13180    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13181    )
13182 {
13183    assert(node != NULL);
13184    assert(node->op == SCIP_EXPR_QUADRATIC);
13185    assert(node->data.data != NULL);
13186 
13187    return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
13188 }
13189 
13190 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE * node)13191 int SCIPexprgraphGetNodeQuadraticNQuadElements(
13192    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13193    )
13194 {
13195    assert(node != NULL);
13196    assert(node->op == SCIP_EXPR_QUADRATIC);
13197    assert(node->data.data != NULL);
13198 
13199    return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
13200 }
13201 
13202 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE * node)13203 SCIP_EXPRDATA_MONOMIAL** SCIPexprgraphGetNodePolynomialMonomials(
13204    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13205    )
13206 {
13207    assert(node != NULL);
13208    assert(node->op == SCIP_EXPR_POLYNOMIAL);
13209    assert(node->data.data != NULL);
13210 
13211    return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
13212 }
13213 
13214 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE * node)13215 int SCIPexprgraphGetNodePolynomialNMonomials(
13216    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13217    )
13218 {
13219    assert(node != NULL);
13220    assert(node->op == SCIP_EXPR_POLYNOMIAL);
13221    assert(node->data.data != NULL);
13222 
13223    return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
13224 }
13225 
13226 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE * node)13227 SCIP_Real SCIPexprgraphGetNodePolynomialConstant(
13228    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13229    )
13230 {
13231    assert(node != NULL);
13232    assert(node->op == SCIP_EXPR_POLYNOMIAL);
13233    assert(node->data.data != NULL);
13234 
13235    return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
13236 }
13237 
13238 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
13239  *
13240  *  Assumes that curvature of children and bounds of children and node itself are valid.
13241  */
SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE * node,int monomialidx,SCIP_Real infinity,SCIP_EXPRCURV * curv)13242 SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(
13243    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node */
13244    int                   monomialidx,        /**< index of monomial */
13245    SCIP_Real             infinity,           /**< value for infinity in interval arithmetics */
13246    SCIP_EXPRCURV*        curv                /**< buffer to store monomial curvature */
13247    )
13248 {
13249    SCIP_EXPRDATA_MONOMIAL* monomial;
13250    SCIP_INTERVAL  childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13251    SCIP_EXPRCURV  childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13252    SCIP_INTERVAL* childbounds = NULL;
13253    SCIP_EXPRCURV* childcurv = NULL;
13254    SCIP_EXPRGRAPHNODE* child;
13255    SCIP_RETCODE retcode = SCIP_OKAY;
13256    int i;
13257 
13258    assert(node != NULL);
13259    assert(node->depth >= 0); /* node should be in graph */
13260    assert(node->pos >= 0);   /* node should be in graph */
13261    assert(node->enabled);    /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13262    assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID);  /* we assume node bounds to be valid */
13263    assert(node->op == SCIP_EXPR_POLYNOMIAL);
13264    assert(node->data.data != NULL);
13265    assert(monomialidx >= 0);
13266    assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13267    assert(curv != NULL);
13268 
13269    if( SCIPintervalIsEmpty(infinity, node->bounds) )
13270    {
13271       *curv = SCIP_EXPRCURV_LINEAR;
13272       return SCIP_OKAY;
13273    }
13274 
13275    monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13276    assert(monomial != NULL);
13277 
13278    /* if many children, get large enough memory to store children bounds */
13279    if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13280    {
13281       SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13282       SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, monomial->nfactors), TERMINATE );
13283    }
13284    else
13285    {
13286       childbounds = childboundsstatic;
13287       childcurv   = childcurvstatic;
13288    }
13289 
13290    /* assemble bounds and curvature of children */
13291    for( i = 0; i < monomial->nfactors; ++i )
13292    {
13293       child = node->children[monomial->childidxs[i]];
13294       assert(child != NULL);
13295 
13296       /* child should have valid and non-empty bounds */
13297       assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13298       assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13299       /* nodes at depth 0 are always linear */
13300       assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13301 
13302       childbounds[i] = child->bounds;  /*lint !e644*/
13303       childcurv[i]   = child->curv;    /*lint !e644*/
13304    }
13305 
13306    /* check curvature */
13307    *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13308    *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13309 
13310    /* free memory, if allocated before */
13311 TERMINATE:
13312    if( childbounds != childboundsstatic )
13313    {
13314       BMSfreeMemoryArrayNull(&childbounds);
13315       BMSfreeMemoryArrayNull(&childcurv);
13316    }
13317 
13318    return retcode;
13319 }
13320 
13321 /** gives the user data belonging to a SCIP_EXPR_USER expression */
SCIPexprgraphGetNodeUserData(SCIP_EXPRGRAPHNODE * node)13322 SCIP_USEREXPRDATA* SCIPexprgraphGetNodeUserData(
13323    SCIP_EXPRGRAPHNODE*   node
13324    )
13325 {
13326    assert(node != NULL);
13327    assert(node->op == SCIP_EXPR_USER);
13328    assert(node->data.data != NULL);
13329 
13330    return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13331 }
13332 
13333 /** indicates whether a user expression has the estimator callback defined */
SCIPexprgraphHasNodeUserEstimator(SCIP_EXPRGRAPHNODE * node)13334 SCIP_Bool SCIPexprgraphHasNodeUserEstimator(
13335    SCIP_EXPRGRAPHNODE*   node
13336    )
13337 {
13338    assert(node != NULL);
13339    assert(node->op == SCIP_EXPR_USER);
13340    assert(node->data.data != NULL);
13341 
13342    return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13343 }
13344 
13345 /** gets bounds of a node in an expression graph */
SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE * node)13346 SCIP_INTERVAL SCIPexprgraphGetNodeBounds(
13347    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13348    )
13349 {
13350    assert(node != NULL);
13351 
13352    return node->bounds;
13353 }
13354 
13355 /** gets value of expression associated to node from last evaluation call */
SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE * node)13356 SCIP_Real SCIPexprgraphGetNodeVal(
13357    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13358    )
13359 {
13360    assert(node != NULL);
13361 
13362    return node->value;
13363 }
13364 
13365 /** gets curvature of expression associated to node from last curvature check call */
SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE * node)13366 SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(
13367    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
13368    )
13369 {
13370    assert(node != NULL);
13371 
13372    return node->curv;
13373 }
13374 
13375 /** creates an expression graph node */
SCIPexprgraphCreateNode(BMS_BLKMEM * blkmem,SCIP_EXPRGRAPHNODE ** node,SCIP_EXPROP op,...)13376 SCIP_RETCODE SCIPexprgraphCreateNode(
13377    BMS_BLKMEM*           blkmem,             /**< block memory */
13378    SCIP_EXPRGRAPHNODE**  node,               /**< buffer to store expression graph node */
13379    SCIP_EXPROP           op,                 /**< operator type of expression */
13380    ...
13381    )
13382 {
13383    va_list         ap;
13384    SCIP_EXPROPDATA opdata;
13385 
13386    assert(blkmem != NULL);
13387    assert(node   != NULL);
13388 
13389    *node = NULL;
13390 
13391    switch( op )
13392    {
13393    case SCIP_EXPR_VARIDX    :
13394    case SCIP_EXPR_PARAM     :
13395    case SCIP_EXPR_CONST     :
13396    case SCIP_EXPR_LINEAR    :
13397    case SCIP_EXPR_QUADRATIC :
13398    case SCIP_EXPR_POLYNOMIAL:
13399    case SCIP_EXPR_USER      :
13400    {
13401       SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n", op);
13402       SCIPABORT();
13403       return SCIP_ERROR;  /*lint !e527*/
13404    }
13405 
13406    /* operands without data */
13407    case SCIP_EXPR_PLUS   :
13408    case SCIP_EXPR_MINUS  :
13409    case SCIP_EXPR_MUL    :
13410    case SCIP_EXPR_DIV    :
13411    case SCIP_EXPR_MIN    :
13412    case SCIP_EXPR_MAX    :
13413    case SCIP_EXPR_SQUARE :
13414    case SCIP_EXPR_SQRT   :
13415    case SCIP_EXPR_EXP    :
13416    case SCIP_EXPR_LOG    :
13417    case SCIP_EXPR_SIN    :
13418    case SCIP_EXPR_COS    :
13419    case SCIP_EXPR_TAN    :
13420       /* case SCIP_EXPR_ERF : */
13421       /* case SCIP_EXPR_ERFI: */
13422    case SCIP_EXPR_ABS    :
13423    case SCIP_EXPR_SIGN   :
13424    case SCIP_EXPR_SUM    :
13425    case SCIP_EXPR_PRODUCT:
13426       opdata.data = NULL;
13427       break;
13428 
13429    case SCIP_EXPR_REALPOWER:
13430    case SCIP_EXPR_SIGNPOWER:
13431    {
13432       va_start(ap, op );  /*lint !e838*/
13433       opdata.dbl = va_arg( ap, SCIP_Real);  /*lint !e416 !e826*/
13434       va_end( ap );  /*lint !e826*/
13435 
13436       break;
13437    }
13438 
13439    case SCIP_EXPR_INTPOWER:
13440    {
13441       va_start(ap, op );  /*lint !e838*/
13442       opdata.intval = va_arg( ap, int);  /*lint !e416 !e826*/
13443       va_end( ap );  /*lint !e826*/
13444 
13445       break;
13446    }
13447 
13448    case SCIP_EXPR_LAST:
13449       SCIPABORT();
13450       return SCIP_INVALIDDATA; /*lint !e527*/
13451    }
13452 
13453    SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13454 
13455    return SCIP_OKAY;
13456 }
13457 
13458 /** creates an expression graph node for a linear expression */
SCIPexprgraphCreateNodeLinear(BMS_BLKMEM * blkmem,SCIP_EXPRGRAPHNODE ** node,int ncoefs,SCIP_Real * coefs,SCIP_Real constant)13459 SCIP_RETCODE SCIPexprgraphCreateNodeLinear(
13460    BMS_BLKMEM*           blkmem,             /**< block memory */
13461    SCIP_EXPRGRAPHNODE**  node,               /**< buffer to store expression graph node */
13462    int                   ncoefs,             /**< number of coefficients */
13463    SCIP_Real*            coefs,              /**< coefficients of linear expression */
13464    SCIP_Real             constant            /**< constant of linear expression */
13465    )
13466 {
13467    SCIP_EXPROPDATA opdata;
13468    SCIP_Real* data;
13469 
13470    assert(blkmem != NULL);
13471    assert(node   != NULL);
13472 
13473    /* we store the coefficients and the constant in a single array and make this our operand data */
13474    SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13475    BMScopyMemoryArray(data, coefs, ncoefs);  /*lint !e644*/
13476    data[ncoefs] = constant;
13477 
13478    opdata.data = data;
13479    SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13480 
13481    return SCIP_OKAY;
13482 }
13483 
13484 /** creates an expression graph node for a quadratic expression */
SCIPexprgraphCreateNodeQuadratic(BMS_BLKMEM * blkmem,SCIP_EXPRGRAPHNODE ** node,int nchildren,SCIP_Real * lincoefs,int nquadelems,SCIP_QUADELEM * quadelems,SCIP_Real constant)13485 SCIP_RETCODE SCIPexprgraphCreateNodeQuadratic(
13486    BMS_BLKMEM*           blkmem,             /**< block memory */
13487    SCIP_EXPRGRAPHNODE**  node,               /**< buffer to store expression graph node */
13488    int                   nchildren,          /**< number of children */
13489    SCIP_Real*            lincoefs,           /**< linear coefficients for children, or NULL */
13490    int                   nquadelems,         /**< number of quadratic elements */
13491    SCIP_QUADELEM*        quadelems,          /**< quadratic elements, or NULL if nquadelems == 0 */
13492    SCIP_Real             constant            /**< constant */
13493    )
13494 {
13495    SCIP_EXPROPDATA opdata;
13496    SCIP_EXPRDATA_QUADRATIC* data;
13497 
13498    assert(blkmem != NULL);
13499    assert(node   != NULL);
13500    assert(quadelems != NULL || nquadelems == 0);
13501 
13502    SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13503 
13504    opdata.data = data;
13505    SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13506 
13507    return SCIP_OKAY;
13508 }
13509 
13510 /** creates an expression graph node for a polynomial expression */
SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM * blkmem,SCIP_EXPRGRAPHNODE ** node,int nmonomials,SCIP_EXPRDATA_MONOMIAL ** monomials,SCIP_Real constant,SCIP_Bool copymonomials)13511 SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(
13512    BMS_BLKMEM*           blkmem,             /**< block memory */
13513    SCIP_EXPRGRAPHNODE**  node,               /**< buffer to store expression graph node */
13514    int                   nmonomials,         /**< number of monomials */
13515    SCIP_EXPRDATA_MONOMIAL** monomials,       /**< monomials */
13516    SCIP_Real             constant,           /**< constant of polynomial */
13517    SCIP_Bool             copymonomials       /**< whether to copy monomials or to assume ownership */
13518    )
13519 {
13520    SCIP_EXPROPDATA opdata;
13521    SCIP_EXPRDATA_POLYNOMIAL* data;
13522 
13523    assert(blkmem != NULL);
13524    assert(node   != NULL);
13525    assert(monomials != NULL || nmonomials == 0);
13526 
13527    SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13528 
13529    opdata.data = data;
13530    SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13531 
13532    return SCIP_OKAY;
13533 }
13534 
13535 /** adds monomials to an expression graph node that is a polynomial expression */
SCIPexprgraphNodePolynomialAddMonomials(BMS_BLKMEM * blkmem,SCIP_EXPRGRAPHNODE * node,int nmonomials,SCIP_EXPRDATA_MONOMIAL ** monomials,SCIP_Bool copymonomials)13536 SCIP_RETCODE SCIPexprgraphNodePolynomialAddMonomials(
13537    BMS_BLKMEM*           blkmem,             /**< block memory */
13538    SCIP_EXPRGRAPHNODE*   node,               /**< store expression graph node with polynomial operator */
13539    int                   nmonomials,         /**< number of monomials */
13540    SCIP_EXPRDATA_MONOMIAL** monomials,       /**< monomials */
13541    SCIP_Bool             copymonomials       /**< whether to copy monomials or to assume ownership */
13542    )
13543 {
13544    assert(blkmem != NULL);
13545    assert(node != NULL);
13546    assert(SCIPexprgraphGetNodeOperator(node) == SCIP_EXPR_POLYNOMIAL);
13547    assert(monomials != NULL || nmonomials == 0);
13548 
13549    SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13550 
13551    return SCIP_OKAY;
13552 }
13553 
13554 /** creates an expression graph node for a user expression */
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)))13555 SCIP_RETCODE SCIPexprgraphCreateNodeUser(
13556    BMS_BLKMEM*           blkmem,             /**< block memory */
13557    SCIP_EXPRGRAPHNODE**  node,               /**< buffer to store expression graph node */
13558    SCIP_USEREXPRDATA*    data,               /**< user data for expression, node assumes ownership */
13559    SCIP_EXPRINTCAPABILITY evalcapability,    /**< evaluation capability */
13560    SCIP_DECL_USEREXPREVAL    ((*eval)),      /**< evaluation function */
13561    SCIP_DECL_USEREXPRINTEVAL ((*inteval)),   /**< interval evaluation function */
13562    SCIP_DECL_USEREXPRCURV    ((*curv)),      /**< curvature check function */
13563    SCIP_DECL_USEREXPRPROP    ((*prop)),      /**< interval propagation function */
13564    SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13565    SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13566    SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
13567    SCIP_DECL_USEREXPRPRINT ((*print))        /**< expression print function, or NULL for default string "user" */
13568    )
13569 {
13570    SCIP_EXPROPDATA opdata;
13571    SCIP_EXPRDATA_USER* exprdata;
13572 
13573    assert(blkmem != NULL);
13574    assert(node   != NULL);
13575    assert(eval != NULL);
13576    assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0);  /* the function evaluation is not optional */
13577    assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL);  /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13578    assert(copydata != NULL || data == NULL);
13579    assert(freedata != NULL || data == NULL);
13580 
13581    SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13582 
13583    exprdata->userdata = data;
13584    exprdata->evalcapability = evalcapability;
13585    exprdata->eval = eval;
13586    exprdata->estimate = estimate;
13587    exprdata->inteval = inteval;
13588    exprdata->curv = curv;
13589    exprdata->prop = prop;
13590    exprdata->copydata = copydata;
13591    exprdata->freedata = freedata;
13592    exprdata->print = print;
13593 
13594    opdata.data = (void*) exprdata;
13595 
13596    SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13597 
13598    return SCIP_OKAY;
13599 }
13600 
13601 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13602  *
13603  *  E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13604  *  If the node is a linear expression, it may be freed.
13605  *  If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13606  *  It is assumed that the user had captured the node.
13607  *  It is assumed that the expression graph has been simplified before.
13608  */
SCIPexprgraphNodeSplitOffLinear(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE ** node,int linvarssize,int * nlinvars,void ** linvars,SCIP_Real * lincoefs,SCIP_Real * constant)13609 SCIP_RETCODE SCIPexprgraphNodeSplitOffLinear(
13610    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
13611    SCIP_EXPRGRAPHNODE**  node,               /**< expression graph node where to splitup linear part */
13612    int                   linvarssize,        /**< length of linvars and lincoefs arrays */
13613    int*                  nlinvars,           /**< buffer to store length of linear term that have been splitup */
13614    void**                linvars,            /**< buffer to store variables of linear part */
13615    SCIP_Real*            lincoefs,           /**< buffer to store coefficients of linear part */
13616    SCIP_Real*            constant            /**< buffer to store constant part */
13617    )
13618 {
13619    int orignvars;
13620    int* varsusage;
13621    SCIP_EXPRGRAPHNODE* orignode;
13622    SCIP_Bool havechange;
13623    int i;
13624 
13625    assert(exprgraph != NULL);
13626    assert(node != NULL);
13627    assert(*node != NULL);
13628    assert((*node)->nuses > 0);
13629    assert(nlinvars != NULL);
13630    assert(linvars  != NULL || linvarssize == 0);
13631    assert(lincoefs != NULL || linvarssize == 0);
13632    assert(constant != NULL);
13633 
13634    *constant = 0.0;
13635    *nlinvars = 0;
13636 
13637    SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13638 
13639    /* do some obvious and easy cases */
13640    switch( (*node)->op )
13641    {
13642    case SCIP_EXPR_VARIDX:
13643    {
13644       if( linvarssize >= 1 )
13645       {
13646          *nlinvars = 1;
13647          linvars[0]  = exprgraph->vars[(*node)->data.intval];  /*lint !e613*/
13648          lincoefs[0] = 1.0;                                    /*lint !e613*/
13649 
13650          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13651       }
13652       return SCIP_OKAY;
13653    }
13654 
13655    case SCIP_EXPR_CONST:
13656    {
13657       *constant = (*node)->data.dbl;
13658       SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13659 
13660       return SCIP_OKAY;
13661    }
13662 
13663    case SCIP_EXPR_REALPOWER:
13664    case SCIP_EXPR_SIGNPOWER:
13665    {
13666       if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13667       {
13668          *nlinvars = 1;
13669          linvars[0]  = exprgraph->vars[(*node)->children[0]->data.intval];  /*lint !e613*/
13670          lincoefs[0] = 1.0;                                                 /*lint !e613*/
13671 
13672          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13673       }
13674       return SCIP_OKAY;
13675    }
13676 
13677    case SCIP_EXPR_INTPOWER:
13678    {
13679       if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13680       {
13681          *nlinvars = 1;
13682          linvars[0]  = exprgraph->vars[(*node)->children[0]->data.intval];  /*lint !e613*/
13683          lincoefs[0] = 1.0;                                                 /*lint !e613*/
13684 
13685          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13686       }
13687       return SCIP_OKAY;
13688    }
13689 
13690    case SCIP_EXPR_PLUS:
13691    {
13692       if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13693       {
13694          *constant = (*node)->children[0]->data.dbl;
13695          *nlinvars = 1;
13696          linvars[0]  = exprgraph->vars[(*node)->children[1]->data.intval];  /*lint !e613*/
13697          lincoefs[0] = 1.0;                                                 /*lint !e613*/
13698 
13699          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13700 
13701          return SCIP_OKAY;
13702       }
13703       else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13704       {
13705          *constant = (*node)->children[1]->data.dbl;
13706          *nlinvars = 1;
13707          linvars[0]  = exprgraph->vars[(*node)->children[0]->data.intval];  /*lint !e613*/
13708          lincoefs[0] = 1.0;                                                 /*lint !e613*/
13709 
13710          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13711 
13712          return SCIP_OKAY;
13713       }
13714       else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13715       {
13716          *nlinvars = 2;
13717          linvars[0]  = exprgraph->vars[(*node)->children[0]->data.intval];  /*lint !e613*/
13718          lincoefs[0] = 1.0;                                                 /*lint !e613*/
13719          linvars[1]  = exprgraph->vars[(*node)->children[1]->data.intval];  /*lint !e613*/
13720          lincoefs[1] = 1.0;                                                 /*lint !e613*/
13721 
13722          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13723 
13724          return SCIP_OKAY;
13725       }
13726       else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13727       {
13728          /* handle this one later */
13729          break;
13730       }
13731       return SCIP_OKAY;
13732    }
13733 
13734    case SCIP_EXPR_MINUS:
13735    {
13736       if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13737       {
13738          *constant = (*node)->children[0]->data.dbl;
13739          *nlinvars = 1;
13740          linvars[0]  = exprgraph->vars[(*node)->children[1]->data.intval];  /*lint !e613*/
13741          lincoefs[0] = -1.0;                                                /*lint !e613*/
13742 
13743          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13744 
13745          return SCIP_OKAY;
13746       }
13747       else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13748       {
13749          *constant = -(*node)->children[1]->data.dbl;
13750          *nlinvars = 1;
13751          linvars[0]  = exprgraph->vars[(*node)->children[0]->data.intval];  /*lint !e613*/
13752          lincoefs[0] = 1.0;                                                 /*lint !e613*/
13753 
13754          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13755 
13756          return SCIP_OKAY;
13757       }
13758       else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13759       {
13760          *nlinvars = 2;
13761          linvars[0]  = exprgraph->vars[(*node)->children[0]->data.intval];  /*lint !e613*/
13762          lincoefs[0] = 1.0;                                                 /*lint !e613*/
13763          linvars[1]  = exprgraph->vars[(*node)->children[1]->data.intval];  /*lint !e613*/
13764          lincoefs[1] = -1.0;                                                /*lint !e613*/
13765 
13766          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13767 
13768          return SCIP_OKAY;
13769       }
13770       else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13771       {
13772          /* handle this one later */
13773          break;
13774       }
13775       return SCIP_OKAY;
13776    }
13777 
13778    case SCIP_EXPR_MUL:
13779    {
13780       if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13781       {
13782          *nlinvars = 1;
13783          linvars[0]  = exprgraph->vars[(*node)->children[1]->data.intval];  /*lint !e613*/
13784          lincoefs[0] = (*node)->children[0]->data.dbl;                      /*lint !e613*/
13785 
13786          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13787       }
13788       else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13789       {
13790          *nlinvars = 1;
13791          linvars[0]  = exprgraph->vars[(*node)->children[0]->data.intval];  /*lint !e613*/
13792          lincoefs[0] = (*node)->children[1]->data.dbl;                      /*lint !e613*/
13793 
13794          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13795       }
13796       return SCIP_OKAY;
13797    }
13798 
13799    case SCIP_EXPR_DIV:
13800    {
13801       if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13802          return SCIP_OKAY;
13803 
13804       if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13805       {
13806          *nlinvars = 1;
13807          linvars[0]  = exprgraph->vars[(*node)->children[0]->data.intval];  /*lint !e613*/
13808          lincoefs[0] = 1.0/(*node)->children[1]->data.dbl;                  /*lint !e613*/
13809 
13810          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13811       }
13812       return SCIP_OKAY;
13813    }
13814 
13815    case SCIP_EXPR_SQUARE:
13816    case SCIP_EXPR_SQRT:
13817    case SCIP_EXPR_EXP:
13818    case SCIP_EXPR_LOG:
13819    case SCIP_EXPR_SIN:
13820    case SCIP_EXPR_COS:
13821    case SCIP_EXPR_TAN:
13822       /* case SCIP_EXPR_ERF: */
13823       /* case SCIP_EXPR_ERFI: */
13824    case SCIP_EXPR_ABS:
13825    case SCIP_EXPR_SIGN:
13826    case SCIP_EXPR_MIN:
13827    case SCIP_EXPR_MAX:
13828       return SCIP_OKAY;
13829 
13830    case SCIP_EXPR_PRODUCT:
13831    case SCIP_EXPR_USER:
13832       return SCIP_OKAY;
13833 
13834    case SCIP_EXPR_SUM:
13835    case SCIP_EXPR_LINEAR:
13836    case SCIP_EXPR_QUADRATIC:
13837    case SCIP_EXPR_POLYNOMIAL:
13838    default:
13839    {
13840       /* check if there is a child that is a variable */
13841       for( i = 0; i < (*node)->nchildren; ++i )
13842       {
13843          if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13844             break;
13845       }
13846 
13847       if( i == (*node)->nchildren )
13848          return SCIP_OKAY;
13849 
13850       break;
13851    }
13852    }  /*lint !e788*/
13853 
13854    /* count how often variables are used in this expression */
13855    assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13856    orignvars = exprgraph->nvars;
13857    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13858    BMSclearMemoryArray(varsusage, exprgraph->nvars);  /*lint !e644*/
13859 
13860    exprgraphNodeGetVarsUsage(*node, varsusage);
13861 
13862    /* duplicate node if it has parents or more than one user */
13863    orignode = NULL;
13864    if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13865    {
13866       SCIP_EXPROPDATA data;
13867 
13868       orignode = *node;
13869 
13870       if( exprOpTable[orignode->op].copydata != NULL )
13871       {
13872          SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13873       }
13874       else
13875          data = orignode->data;
13876 
13877       SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13878       SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13879       SCIPexprgraphCaptureNode(*node);
13880    }
13881 
13882    havechange = FALSE;
13883    /* split up constant and linear part */
13884    switch( (*node)->op )
13885    {
13886    case SCIP_EXPR_PLUS:
13887    case SCIP_EXPR_MINUS:
13888    {
13889       SCIP_EXPRGRAPHNODE* varchild;
13890       SCIP_EXPRGRAPHNODE* otherchild;
13891       int varidx;
13892 
13893       /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13894       assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13895       assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13896       assert(linvarssize >= 1);
13897 
13898       varchild   = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13899       otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13900       varidx = varchild->data.intval;
13901       /* if variable is used in other child (which should be nonlinear), we don't take it */
13902       if( varsusage[varidx] > 1 )
13903          break;
13904 
13905       /* add to linear variables */
13906       *nlinvars = 1;
13907       linvars[0]  = exprgraph->vars[varidx];  /*lint !e613*/
13908       if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13909          lincoefs[0] = -1.0;  /*lint !e613*/
13910       else
13911          lincoefs[0] =  1.0;  /*lint !e613*/
13912 
13913       if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13914       {
13915          /* replace *node by otherchild */
13916          SCIPexprgraphCaptureNode(otherchild);
13917          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13918          *node = otherchild;
13919       }
13920       else
13921       {
13922          SCIP_Real* lindata;
13923 
13924          /* turn *node into linear expression -1.0 * otherchild */
13925 
13926          /* reduce to one child */
13927          SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) );  /*lint !e506*/
13928          (*node)->children[0] = otherchild;
13929          (*node)->nchildren = 1;
13930          (*node)->op = SCIP_EXPR_LINEAR;
13931 
13932          /* setup linear data -1.0 * child0 + 0.0 */
13933          SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) );  /*lint !e506*/
13934          lindata[0] = -1.0;
13935          lindata[1] =  0.0;
13936          (*node)->data.data = (void*)lindata;
13937 
13938          /* remove *node as parent of varchild */
13939          SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13940       }
13941 
13942       havechange = TRUE;
13943 
13944       break;
13945    }
13946 
13947    case SCIP_EXPR_SUM:
13948    {
13949       int nchildren;
13950 
13951       i = 0;
13952       nchildren = (*node)->nchildren;
13953       while( i < nchildren )
13954       {
13955          /* sort out constants */
13956          if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13957          {
13958             *constant += (*node)->children[i]->data.dbl;
13959             SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13960 
13961             if( i < nchildren-1 )
13962             {
13963                (*node)->children[i] = (*node)->children[nchildren-1];
13964                (*node)->children[nchildren-1] = NULL;
13965             }
13966             --nchildren;
13967 
13968             continue;
13969          }
13970 
13971          /* keep every child that is not a constant or variable */
13972          if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13973          {
13974             ++i;
13975             continue;
13976          }
13977 
13978          /* skip variables that are used in other parts of the expression */
13979          if( varsusage[(*node)->children[i]->data.intval] > 1 )
13980          {
13981             ++i;
13982             continue;
13983          }
13984 
13985          /* move variable into linear part, if still space */
13986          if( *nlinvars < linvarssize )
13987          {
13988             linvars[*nlinvars]  = exprgraph->vars[(*node)->children[i]->data.intval];  /*lint !e613*/
13989             lincoefs[*nlinvars] = 1.0;                                                 /*lint !e613*/
13990             ++*nlinvars;
13991 
13992             SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13993             if( i < nchildren-1 )
13994             {
13995                (*node)->children[i] = (*node)->children[nchildren-1];
13996                (*node)->children[nchildren-1] = NULL;
13997             }
13998             --nchildren;
13999 
14000             continue;
14001          }
14002       }
14003       assert(i == nchildren);
14004 
14005       if( nchildren == 0 )
14006       {
14007          /* all children were removed */
14008          havechange = TRUE;
14009          BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14010          (*node)->nchildren = 0;
14011          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14012          break;
14013       }
14014 
14015       if( nchildren < (*node)->nchildren )
14016       {
14017          /* some children were removed */
14018          havechange = TRUE;
14019          SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14020          (*node)->nchildren = nchildren;
14021       }
14022 
14023       if( havechange && (*node)->nchildren == 1 )
14024       {
14025          /* replace node by its child */
14026          SCIP_EXPRGRAPHNODE* child;
14027 
14028          child = (*node)->children[0];
14029          SCIPexprgraphCaptureNode(child);
14030          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14031          *node = child;
14032 
14033          break;
14034       }
14035 
14036       break;
14037    }
14038 
14039    case SCIP_EXPR_LINEAR:
14040    {
14041       int nchildren;
14042       SCIP_Real* coefs;
14043 
14044       coefs = (SCIP_Real*)(*node)->data.data;
14045       assert(coefs != NULL);
14046 
14047       /* remove constant, if nonzero */
14048       if( coefs[(*node)->nchildren] != 0.0 )
14049       {
14050          *constant = coefs[(*node)->nchildren];
14051          coefs[(*node)->nchildren] = 0.0;
14052          havechange = TRUE;
14053       }
14054 
14055       i = 0;
14056       nchildren = (*node)->nchildren;
14057       while( i < nchildren )
14058       {
14059          /* sort out constants */
14060          if( (*node)->children[i]->op == SCIP_EXPR_CONST )
14061          {
14062             *constant += coefs[i] * (*node)->children[i]->data.dbl;
14063             SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14064 
14065             if( i < nchildren-1 )
14066             {
14067                (*node)->children[i] = (*node)->children[nchildren-1];
14068                (*node)->children[nchildren-1] = NULL;
14069                coefs[i] = coefs[nchildren-1];
14070                coefs[nchildren-1] = 0.0;
14071             }
14072             --nchildren;
14073 
14074             continue;
14075          }
14076 
14077          /* keep everything that is not a constant or variable */
14078          if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14079          {
14080             ++i;
14081             continue;
14082          }
14083 
14084          /* skip variables that are used in other parts of the expression */
14085          if( varsusage[(*node)->children[i]->data.intval] > 1 )
14086          {
14087             ++i;
14088             continue;
14089          }
14090 
14091          /* move variable into linear part, if still space */
14092          if( *nlinvars < linvarssize )
14093          {
14094             linvars[*nlinvars]  = exprgraph->vars[(*node)->children[i]->data.intval];  /*lint !e613*/
14095             lincoefs[*nlinvars] = coefs[i];                                            /*lint !e613*/
14096             ++*nlinvars;
14097 
14098             SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14099             if( i < nchildren-1 )
14100             {
14101                (*node)->children[i] = (*node)->children[nchildren-1];
14102                (*node)->children[nchildren-1] = NULL;
14103                coefs[i] = coefs[nchildren-1];
14104                coefs[nchildren-1] = 0.0;
14105             }
14106             --nchildren;
14107 
14108             continue;
14109          }
14110       }
14111       assert(i == nchildren);
14112 
14113       if( nchildren == 0 )
14114       {
14115          /* all children were removed */
14116          havechange = TRUE;
14117          BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14118          BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
14119          (*node)->data.data = NULL;
14120          (*node)->nchildren = 0;
14121          (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
14122          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14123          break;
14124       }
14125 
14126       if( nchildren < (*node)->nchildren )
14127       {
14128          /* some children were removed */
14129          havechange = TRUE;
14130          SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14131          SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
14132          coefs[nchildren] = 0.0;
14133          (*node)->data.data = (void*)coefs;
14134          (*node)->nchildren = nchildren;
14135       }
14136 
14137       if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
14138       {
14139          /* replace node by its child */
14140          SCIP_EXPRGRAPHNODE* child;
14141 
14142          child = (*node)->children[0];
14143          SCIPexprgraphCaptureNode(child);
14144          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14145          *node = child;
14146 
14147          break;
14148       }
14149 
14150       break;
14151    }
14152 
14153    case SCIP_EXPR_QUADRATIC:
14154    {
14155       SCIP_EXPRDATA_QUADRATIC* quaddata;
14156       SCIP_Bool* childused;
14157       int* childmap;
14158       int nchildren;
14159 
14160       quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
14161       assert(quaddata != NULL);
14162 
14163       /* remove constant, if nonzero */
14164       if( quaddata->constant != 0.0 )
14165       {
14166          *constant = quaddata->constant;
14167          quaddata->constant = 0.0;
14168          havechange = TRUE;
14169       }
14170 
14171       /* if there is no linear part or no space left for linear variables, then stop */
14172       if( quaddata->lincoefs == NULL || linvarssize == 0 )
14173          break;
14174 
14175       /* check which childs are used in quadratic terms */
14176       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14177       BMSclearMemoryArray(childused, (*node)->nchildren);  /*lint !e644*/
14178 
14179       for( i = 0; i < quaddata->nquadelems; ++i )
14180       {
14181          childused[quaddata->quadelems[i].idx1] = TRUE;
14182          childused[quaddata->quadelems[i].idx2] = TRUE;
14183       }
14184 
14185       /* alloc space for mapping of children indices */
14186       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
14187 
14188       nchildren = (*node)->nchildren;
14189       for( i = 0; i < nchildren; ++i )
14190       {
14191          childmap[i] = i;  /*lint !e644*/
14192          if( *nlinvars >= linvarssize )
14193             continue;
14194          /* skip child if not variable or also used in quadratic part or other parts of expression */
14195          if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14196             continue;
14197          if( childused[i] )
14198             continue;
14199          if( varsusage[(*node)->children[i]->data.intval] > 1 )
14200             continue;
14201 
14202          /* put variable into linear part */
14203          linvars[*nlinvars]  = exprgraph->vars[(*node)->children[i]->data.intval];  /*lint !e613*/
14204          lincoefs[*nlinvars] = quaddata->lincoefs[i];                               /*lint !e613*/
14205          quaddata->lincoefs[i] = 0.0;
14206          ++*nlinvars;
14207 
14208          SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14209 
14210          /* move last child to position i */
14211          if( i < nchildren-1 )
14212          {
14213             (*node)->children[i] = (*node)->children[nchildren-1];
14214             quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
14215             childused[i] = childused[nchildren-1];
14216             childmap[nchildren-1] = i;
14217          }
14218          --nchildren;
14219          childmap[i] = -1;
14220 
14221          havechange = TRUE;
14222          --i; /* look at i again */
14223       }
14224 
14225       BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);  /*lint !e850*/
14226 
14227       if( nchildren < (*node)->nchildren )
14228       {
14229          /* apply childmap to quadratic term */
14230          for( i = 0; i < quaddata->nquadelems; ++i )
14231          {
14232             quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
14233             quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
14234             if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
14235             {
14236                int tmp;
14237                tmp = quaddata->quadelems[i].idx1;
14238                quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
14239                quaddata->quadelems[i].idx2 = tmp;
14240             }
14241          }
14242          quaddata->sorted = FALSE;
14243       }
14244       BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
14245 
14246       if( nchildren == 0 )
14247       {
14248          /* all children were removed (so it was actually a linear expression) */
14249          havechange = TRUE;
14250          BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14251          exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
14252          (*node)->data.data = NULL;
14253          (*node)->nchildren = 0;
14254          (*node)->op = SCIP_EXPR_SUM;
14255          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14256          break;
14257       }
14258 
14259       if( nchildren < (*node)->nchildren )
14260       {
14261          /* reduce number of children */
14262          SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14263          SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14264          (*node)->nchildren = nchildren;
14265       }
14266 
14267       break;
14268    }
14269 
14270    case SCIP_EXPR_POLYNOMIAL:
14271    {
14272       SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14273       SCIP_EXPRDATA_MONOMIAL* monomial;
14274       SCIP_Bool* childused;
14275       int childidx;
14276       int j;
14277 
14278       polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14279       assert(polynomialdata != NULL);
14280 
14281       /* make sure linear monomials are merged */
14282       polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14283 
14284       /* remove constant, if nonzero */
14285       if( polynomialdata->constant != 0.0 )
14286       {
14287          *constant = polynomialdata->constant;
14288          polynomialdata->constant = 0.0;
14289          havechange = TRUE;
14290       }
14291 
14292       /* if there is no space for linear variables, then stop */
14293       if( linvarssize == 0 )
14294          break;
14295 
14296       /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14297       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14298       BMSclearMemoryArray(childused, (*node)->nchildren);  /*lint !e644*/
14299       for( i = 0; i < polynomialdata->nmonomials; ++i )
14300       {
14301          monomial = polynomialdata->monomials[i];
14302          assert(monomial != NULL);
14303          if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14304             continue;
14305          for( j = 0; j < monomial->nfactors; ++j )
14306          {
14307             assert(monomial->childidxs[j] >= 0);
14308             assert(monomial->childidxs[j] < (*node)->nchildren);
14309             childused[monomial->childidxs[j]] = TRUE;
14310          }
14311       }
14312 
14313       /* move linear monomials out of polynomial */
14314       for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14315       {
14316          monomial = polynomialdata->monomials[i];
14317          assert(monomial != NULL);
14318 
14319          /* sort out constants */
14320          if( monomial->nfactors == 0 )
14321          {
14322             if( monomial->coef != 0.0 )
14323             {
14324                *constant += monomial->coef;
14325                havechange = TRUE;
14326             }
14327             continue;
14328          }
14329 
14330          if( monomial->nfactors != 1 )
14331             continue;
14332          if( monomial->exponents[0] != 1.0 )
14333             continue;
14334          childidx = monomial->childidxs[0];
14335          assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14336          if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14337             continue;
14338          if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14339             continue;
14340 
14341          /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14342 
14343          /* put variable into linear part */
14344          linvars[*nlinvars]  = exprgraph->vars[(*node)->children[childidx]->data.intval];  /*lint !e613*/
14345          lincoefs[*nlinvars] = monomial->coef;                                             /*lint !e613*/
14346          ++*nlinvars;
14347 
14348          monomial->coef = 0.0;
14349          monomial->nfactors = 0;
14350          polynomialdata->sorted = FALSE;
14351 
14352          SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14353          (*node)->children[childidx] = NULL;
14354 
14355          havechange = TRUE;
14356       }
14357 
14358       BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14359 
14360       if( *nlinvars > 0 )
14361       {
14362          /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14363          polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14364          SCIP_CALL( exprgraphNodeRemovePolynomialNullChildren(exprgraph->blkmem, *node) );
14365       }
14366 
14367       if( (*node)->nchildren == 0 )
14368       {
14369          assert(polynomialdata->nmonomials == 0);
14370          assert(polynomialdata->constant == 0.0);
14371          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14372          havechange = TRUE;
14373          break;
14374       }
14375 
14376       break;
14377    }
14378 
14379    default: ;
14380    }  /*lint !e788*/
14381 
14382    BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14383 
14384    if( orignode != NULL )
14385    {
14386       /* if node was duplicated, we need to forget about original or duplicate */
14387       if( !havechange )
14388       {
14389          /* if nothing has changed, then forget about duplicate */
14390          assert(*constant == 0.0);
14391          assert(*nlinvars == 0);
14392          assert(*node != NULL);
14393          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14394          *node = orignode;
14395       }
14396       else
14397       {
14398          /* if something changed, then release original node */
14399          SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14400       }
14401    }
14402    else if( havechange && *node != NULL )
14403    {
14404       /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14405       (*node)->value = SCIP_INVALID;
14406       (*node)->simplified = FALSE;
14407       (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14408       SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14409       exprgraph->needvarboundprop = TRUE;
14410    }
14411 
14412    return SCIP_OKAY;
14413 }
14414 
14415 /** moves parents from a one node to another node
14416  *
14417  *  In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14418  *  srcnode may be freed, if not captured.
14419  *  It is assumed that targetnode represents the same expression as srcnode.
14420  */
SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE ** srcnode,SCIP_EXPRGRAPHNODE * targetnode)14421 SCIP_RETCODE SCIPexprgraphMoveNodeParents(
14422    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
14423    SCIP_EXPRGRAPHNODE**  srcnode,            /**< node which parents to move */
14424    SCIP_EXPRGRAPHNODE*   targetnode          /**< node where to move parents to */
14425    )
14426 {
14427    assert(exprgraph != NULL);
14428    assert(srcnode != NULL);
14429    assert(*srcnode != NULL);
14430    assert(targetnode != NULL);
14431 
14432    while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14433    {
14434       if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14435       {
14436          SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14437       }
14438       SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14439    }
14440    assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14441 
14442    return SCIP_OKAY;
14443 }
14444 
14445 /** releases node, i.e., decreases number of uses
14446  *
14447  *  node is freed if no parents and no other uses.
14448  *  Children are recursively released if they have no other parents.
14449  *  Nodes that are removed are also freed.
14450  *  If node correspond to a variable, then the variable is removed from the expression graph;
14451  *  similarly for constants.
14452  */
SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE ** node)14453 SCIP_RETCODE SCIPexprgraphReleaseNode(
14454    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
14455    SCIP_EXPRGRAPHNODE**  node                /**< expression graph node to release */
14456    )
14457 {
14458    int i;
14459 
14460    assert(exprgraph != NULL);
14461    assert(node  != NULL);
14462    assert(*node != NULL);
14463    assert((*node)->depth >= 0); /* node should be in graph */
14464    assert((*node)->pos   >= 0); /* node should be in graph */
14465    assert((*node)->depth < exprgraph->depth);
14466    assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14467    assert((*node)->nuses >= 1);
14468    assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14469 
14470    SCIPdebugMessage("release node %p\n", (void*)*node);
14471 
14472    --(*node)->nuses;
14473 
14474    /* do nothing if node still has parents or is still in use */
14475    if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14476    {
14477       SCIPdebugMessage("skip removing node %p (%d, %d) with %d parents and %d uses from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, (*node)->nparents, (*node)->nuses);
14478       *node = NULL;
14479       return SCIP_OKAY;
14480    }
14481 
14482    SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14483 
14484    /* notify children about removal of its parent
14485     * they are also freed, if possible */
14486    for( i = 0; i < (*node)->nchildren; ++i )
14487    {
14488       SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14489       (*node)->children[i] = NULL;
14490    }
14491 
14492    if( (*node)->op == SCIP_EXPR_VARIDX )
14493    {
14494       assert((*node)->depth == 0);
14495       SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14496    }
14497    else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14498    {
14499       int constidx;
14500 
14501       (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14502       assert(constidx >= 0);
14503       assert(constidx < exprgraph->nconsts);
14504       assert(exprgraph->constnodes[constidx] == *node);
14505 
14506       /* move last constant to position constidx */
14507       if( constidx < exprgraph->nconsts-1 )
14508       {
14509          exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14510          exprgraph->constssorted = (exprgraph->nconsts <= 2);
14511       }
14512       --exprgraph->nconsts;
14513    }
14514    else
14515    {
14516       /* only variables and constants are allowed at depth 0 */
14517       assert((*node)->depth > 0);
14518    }
14519 
14520    /* remove node from nodes array in expression graph */
14521    if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14522    {
14523       /* move last node at depth of *node to position of *node */
14524       exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14525       exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14526 
14527       /* moving the node may change the order in the parents array of each child */
14528       for( i = 0; i < exprgraph->nodes[(*node)->depth][(*node)->pos]->nchildren; ++i )
14529          exprgraph->nodes[(*node)->depth][(*node)->pos]->children[i]->parentssorted = FALSE;
14530    }
14531    --exprgraph->nnodes[(*node)->depth];
14532 
14533    /* node is now not in graph anymore */
14534    (*node)->depth = -1;
14535    (*node)->pos   = -1;
14536 
14537    /* free node */
14538    SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14539 
14540    *node = NULL;
14541 
14542    return SCIP_OKAY;
14543 }
14544 
14545 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14546 /** frees a node of an expression graph */
SCIPexprgraphFreeNode(BMS_BLKMEM * blkmem,SCIP_EXPRGRAPHNODE ** node)14547 void SCIPexprgraphFreeNode(
14548    BMS_BLKMEM*           blkmem,             /**< block memory */
14549    SCIP_EXPRGRAPHNODE**  node                /**< pointer to expression graph node that should be freed */
14550    )
14551 {
14552    assert(blkmem != NULL);
14553    assert( node != NULL);
14554    assert(*node != NULL);
14555    assert((*node)->depth == -1); /* node should not be in graph anymore */
14556    assert((*node)->pos   == -1); /* node should not be in graph anymore */
14557    assert((*node)->nuses == 0); /* node should not be in use */
14558 
14559    /* free operator data, if needed */
14560    if( exprOpTable[(*node)->op].freedata != NULL )
14561       exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14562 
14563    /* free arrays of children and parent nodes */
14564    BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14565    BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents,  (*node)->parentssize);
14566 
14567    /* free node struct */
14568    BMSfreeBlockMemory(blkmem, node);
14569 }
14570 
14571 /** enables a node and recursively all its children in an expression graph */
SCIPexprgraphEnableNode(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node)14572 void SCIPexprgraphEnableNode(
14573    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
14574    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node to enable */
14575    )
14576 {
14577    int i;
14578 
14579    assert(exprgraph != NULL);
14580    assert(node != NULL);
14581    assert(node->depth >= 0);
14582    assert(node->pos >= 0);
14583 
14584    if( node->enabled )
14585       return;
14586 
14587    SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14588 
14589    node->enabled = TRUE;
14590    for( i = 0; i < node->nchildren; ++i )
14591       SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14592 
14593    /* make sure bounds are updated in next bound propagation round */
14594    SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
14595    exprgraph->needvarboundprop = TRUE;
14596 }
14597 
14598 /** disables a node and recursively all children which have no enabled parents in an expression graph */
SCIPexprgraphDisableNode(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node)14599 void SCIPexprgraphDisableNode(
14600    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
14601    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node to enable */
14602    )
14603 {
14604    int i;
14605 
14606    assert(exprgraph != NULL);
14607    assert(node != NULL);
14608    assert(node->depth >= 0);
14609    assert(node->pos >= 0);
14610 
14611    if( !node->enabled )
14612       return;
14613 
14614    /* workaround: don't disable nodes if there could be more users than the one who is disabling the node
14615     * otherwise, if there are several nonlinear constraints using the same expression graph node as root node,
14616     * we might get enabled constraints with disabled node
14617     */
14618    if( node->nuses > 1 )
14619       return;
14620 
14621    /* if all parents of node are disabled, then also node can be disabled */
14622    node->enabled = FALSE;
14623    for( i = 0; i < node->nparents; ++i )
14624       if( node->parents[i]->enabled )
14625       {
14626          node->enabled = TRUE;
14627          return;
14628       }
14629 
14630    SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14631 
14632    for( i = 0; i < node->nchildren; ++i )
14633       SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14634 }
14635 
14636 /** returns whether the node has siblings in the expression graph */
SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE * node)14637 SCIP_Bool SCIPexprgraphHasNodeSibling(
14638    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
14639    )
14640 {
14641    int p;
14642 
14643    assert(node != NULL);
14644 
14645    for( p = 0; p < node->nparents; ++p )
14646       if( node->parents[p]->nchildren > 1 )
14647          return TRUE;
14648 
14649    return FALSE;
14650 }
14651 
14652 /** returns whether all children of an expression graph node are variable nodes
14653  *
14654  *  Returns TRUE for nodes without children.
14655  */
SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE * node)14656 SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(
14657    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
14658    )
14659 {
14660    int i;
14661 
14662    assert(node != NULL);
14663 
14664    for( i = 0; i < node->nchildren; ++i )
14665       if( node->children[i]->op != SCIP_EXPR_VARIDX )
14666          return FALSE;
14667 
14668    return TRUE;
14669 }
14670 
14671 /** returns whether the node has an ancestor which has a nonlinear expression operand */
SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE * node)14672 SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(
14673    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
14674    )
14675 {
14676    int p;
14677 
14678    for( p = 0; p < node->nparents; ++p )
14679    {
14680       assert(node->parents[p]->depth > node->depth);
14681       switch( node->parents[p]->op )
14682       {
14683       case SCIP_EXPR_PLUS:
14684       case SCIP_EXPR_MINUS:
14685       case SCIP_EXPR_SUM:
14686       case SCIP_EXPR_LINEAR:
14687          if( SCIPexprgraphHasNodeNonlinearAncestor(node->parents[p]) )
14688             return TRUE;
14689          break;
14690 
14691 #ifndef NDEBUG
14692       case SCIP_EXPR_VARIDX:
14693       case SCIP_EXPR_CONST:
14694       case SCIP_EXPR_PARAM:
14695          assert(0); /* these expressions cannot have children */
14696          break;
14697 #endif
14698 
14699       default:
14700          /* parent has nonlinear expression operand */
14701          return TRUE;
14702       }/*lint !e788*/
14703    }
14704 
14705    return FALSE;
14706 }
14707 
14708 /** prints an expression graph node */
SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE * node,SCIP_MESSAGEHDLR * messagehdlr,FILE * file)14709 void SCIPexprgraphPrintNode(
14710    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node */
14711    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
14712    FILE*                 file                /**< file to print to, or NULL for stdout */
14713    )
14714 {
14715    assert(node != NULL);
14716 
14717    exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14718 }
14719 
14720 /** tightens the bounds in a node of the graph
14721  *
14722  *  Preparation for reverse propagation.
14723  *  Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14724  */
SCIPexprgraphTightenNodeBounds(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,SCIP_INTERVAL nodebounds,SCIP_Real minstrength,SCIP_Real infinity,SCIP_Bool * cutoff)14725 void SCIPexprgraphTightenNodeBounds(
14726    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
14727    SCIP_EXPRGRAPHNODE*   node,               /**< node in expression graph with no parents */
14728    SCIP_INTERVAL         nodebounds,         /**< new bounds for node */
14729    SCIP_Real             minstrength,        /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes (set to negative value if propagation should always be triggered) */
14730    SCIP_Real             infinity,           /**< value for infinity in interval arithmetics */
14731    SCIP_Bool*            cutoff              /**< buffer to store whether a node's bounds were propagated to an empty interval */
14732    )
14733 {
14734    assert(exprgraph != NULL);
14735    assert(node != NULL);
14736    assert(node->depth >= 0);
14737    assert(node->pos >= 0);
14738    assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14739    assert(cutoff != NULL);
14740 
14741    *cutoff = FALSE;
14742 
14743    /* if node is disabled, then ignore new bounds */
14744    if( !node->enabled )
14745    {
14746       SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14747       return;
14748    }
14749 
14750    SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14751       (void*)node, node->depth, node->pos,
14752       node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14753 
14754    /* bounds in node should be valid */
14755    assert(!(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14756 
14757    if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14758    {
14759       *cutoff = TRUE;
14760       SCIPdebugPrintf(" -> cutoff\n");
14761       return;
14762    }
14763 
14764    /* if minstrength is negative, always mark that node has recently tightened bounds,
14765     * if bounds are considerably improved or tightening leads to an empty interval,
14766     * mark that node has recently tightened bounds
14767     * if bounds are only slightly improved, set the status to tightened by parent,
14768     * so next propagateVarBound round will reset the bounds
14769     */
14770    if( minstrength < 0.0 )
14771       node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE;
14772    else if(
14773       isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14774       isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14775       node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT;
14776    else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14777       node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
14778 
14779    SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14780    SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14781 }
14782 
14783 /** ensures that bounds and curvature information in a node is uptodate
14784  *
14785  *  Assumes that bounds and curvature in children are uptodate.
14786  */
SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE * node,SCIP_Real infinity,SCIP_Real minstrength,SCIP_Bool clearreverseprop)14787 SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(
14788    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node */
14789    SCIP_Real             infinity,           /**< value for infinity in interval arithmetics */
14790    SCIP_Real             minstrength,        /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14791    SCIP_Bool             clearreverseprop    /**< whether to reset bound tightenings from reverse propagation */
14792    )
14793 {
14794    SCIP_INTERVAL  childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14795    SCIP_EXPRCURV  childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14796    SCIP_INTERVAL* childbounds = NULL;
14797    SCIP_EXPRCURV* childcurv = NULL;
14798    SCIP_RETCODE retcode = SCIP_OKAY;
14799    int i;
14800 
14801    assert(node != NULL);
14802    assert(node->depth >= 0); /* node should be in graph */
14803    assert(node->pos >= 0);   /* node should be in graph */
14804    assert(node->enabled);    /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14805 
14806    if( node->depth == 0 )
14807    {
14808       /* we cannot update bound tightenings in variable nodes here */
14809       assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14810       return SCIP_OKAY;
14811    }
14812 
14813    assert(node->op != SCIP_EXPR_VARIDX);
14814    assert(node->op != SCIP_EXPR_PARAM);
14815 
14816    /* if many children, get large enough memory to store children bounds */
14817    if( node->nchildren > SCIP_EXPRESSION_MAXCHILDEST )
14818    {
14819       SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14820       SCIP_ALLOC_TERMINATE(retcode, BMSallocMemoryArray(&childcurv, node->nchildren), TERMINATE);
14821    }
14822    else
14823    {
14824       childbounds = childboundsstatic;
14825       childcurv   = childcurvstatic;
14826    }
14827 
14828    /* assemble bounds and curvature of children */
14829    for( i = 0; i < node->nchildren; ++i )
14830    {
14831       /* child should have valid and non-empty bounds */
14832       assert(!(node->children[i]->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14833       assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14834       /* nodes at depth 0 are always linear */
14835       assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14836 
14837       childbounds[i] = node->children[i]->bounds;  /*lint !e644*/
14838       childcurv[i]   = node->children[i]->curv;    /*lint !e644*/
14839    }
14840 
14841    /* if we do not have valid bounds, then update
14842     * code below is copied from exprgraphNodeUpdateBounds */
14843    if( node->boundstatus != SCIP_EXPRBOUNDSTATUS_VALID )
14844    {
14845       SCIP_INTERVAL newbounds;
14846 
14847       /* calling interval evaluation function for this operand */
14848       assert( exprOpTable[node->op].inteval != NULL );
14849       SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds), TERMINATE );
14850 
14851       /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14852        * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14853        *
14854        * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14855        *
14856        * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14857        */
14858       if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14859          ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && clearreverseprop)) )
14860       {
14861          for( i = 0; i < node->nparents; ++i )
14862             node->parents[i]->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
14863 
14864          node->bounds = newbounds;
14865       }
14866       else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14867          (     isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14868       {
14869          for( i = 0; i < node->nparents; ++i )
14870             node->parents[i]->boundstatus |= SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14871 
14872          node->bounds = newbounds;
14873       }
14874       else
14875       {
14876          SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14877       }
14878 
14879       SCIPdebugMessage("updated bounds of node %p (%d,%d) op %s to [%g,%g]\n", (void*)node, node->depth, node->pos, SCIPexpropGetName(node->op), node->bounds.inf, node->bounds.sup);
14880 
14881       /* node now has valid bounds */
14882       node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
14883    }
14884 
14885    /* update curvature */
14886    if( SCIPintervalIsEmpty(infinity, node->bounds) )
14887    {
14888       node->curv = SCIP_EXPRCURV_LINEAR;
14889 
14890       SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14891    }
14892    else
14893    {
14894       SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv), TERMINATE );
14895 
14896       /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14897        * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14898        * SCIPdebugPrintf("\n");
14899        */
14900    }
14901 TERMINATE:
14902    /* free memory, if allocated before */
14903    if( childbounds != childboundsstatic )
14904    {
14905       BMSfreeMemoryArrayNull(&childbounds);
14906       BMSfreeMemoryArrayNull(&childcurv);
14907    }
14908 
14909    return retcode;
14910 }
14911 
14912 /**@} */
14913 
14914 /**@name Expression graph methods */
14915 /**@{ */
14916 
14917 /* In debug mode, the following methods are implemented as function calls to ensure
14918  * type validity.
14919  * In optimized mode, the methods are implemented as defines to improve performance.
14920  * However, we want to have them in the library anyways, so we have to undef the defines.
14921  */
14922 
14923 #undef SCIPexprgraphGetDepth
14924 #undef SCIPexprgraphGetNNodes
14925 #undef SCIPexprgraphGetNodes
14926 #undef SCIPexprgraphGetNVars
14927 #undef SCIPexprgraphGetVars
14928 #undef SCIPexprgraphGetVarNodes
14929 #undef SCIPexprgraphSetVarNodeValue
14930 #undef SCIPexprgraphSetVarsBounds
14931 #undef SCIPexprgraphSetVarBounds
14932 #undef SCIPexprgraphSetVarNodeBounds
14933 #undef SCIPexprgraphSetVarNodeLb
14934 #undef SCIPexprgraphSetVarNodeUb
14935 #undef SCIPexprgraphGetVarsBounds
14936 
14937 /** get current maximal depth of expression graph */
SCIPexprgraphGetDepth(SCIP_EXPRGRAPH * exprgraph)14938 int SCIPexprgraphGetDepth(
14939    SCIP_EXPRGRAPH*       exprgraph           /**< expression graph */
14940    )
14941 {
14942    assert(exprgraph != NULL);
14943 
14944    return exprgraph->depth;
14945 }
14946 
14947 /** gets array with number of nodes at each depth of expression graph */
SCIPexprgraphGetNNodes(SCIP_EXPRGRAPH * exprgraph)14948 int* SCIPexprgraphGetNNodes(
14949    SCIP_EXPRGRAPH*       exprgraph           /**< expression graph */
14950    )
14951 {
14952    assert(exprgraph != NULL);
14953 
14954    return exprgraph->nnodes;
14955 }
14956 
14957 /** gets nodes of expression graph, one array per depth */
SCIPexprgraphGetNodes(SCIP_EXPRGRAPH * exprgraph)14958 SCIP_EXPRGRAPHNODE*** SCIPexprgraphGetNodes(
14959    SCIP_EXPRGRAPH*       exprgraph           /**< expression graph */
14960    )
14961 {
14962    assert(exprgraph != NULL);
14963 
14964    return exprgraph->nodes;
14965 }
14966 
14967 /** gets number of variables in expression graph */
SCIPexprgraphGetNVars(SCIP_EXPRGRAPH * exprgraph)14968 int SCIPexprgraphGetNVars(
14969    SCIP_EXPRGRAPH*       exprgraph           /**< pointer to expression graph that should be freed */
14970    )
14971 {
14972    assert(exprgraph != NULL);
14973 
14974    return exprgraph->nvars;
14975 }
14976 
14977 /** gets array of variables in expression graph */
SCIPexprgraphGetVars(SCIP_EXPRGRAPH * exprgraph)14978 void** SCIPexprgraphGetVars(
14979    SCIP_EXPRGRAPH*       exprgraph           /**< pointer to expression graph that should be freed */
14980    )
14981 {
14982    assert(exprgraph != NULL);
14983 
14984    return exprgraph->vars;
14985 }
14986 
14987 /** gets array of expression graph nodes corresponding to variables */
SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH * exprgraph)14988 SCIP_EXPRGRAPHNODE** SCIPexprgraphGetVarNodes(
14989    SCIP_EXPRGRAPH*       exprgraph           /**< pointer to expression graph that should be freed */
14990    )
14991 {
14992    assert(exprgraph != NULL);
14993 
14994    return exprgraph->varnodes;
14995 }
14996 
14997 /** sets value for a single variable given as expression graph node */
SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE * varnode,SCIP_Real value)14998 void SCIPexprgraphSetVarNodeValue(
14999    SCIP_EXPRGRAPHNODE*   varnode,            /**< expression graph node corresponding to variable */
15000    SCIP_Real             value               /**< new value for variable */
15001    )
15002 {
15003    assert(varnode != NULL);
15004    assert(varnode->op == SCIP_EXPR_VARIDX);
15005 
15006    varnode->value = value;
15007 }
15008 
15009 /** sets bounds for variables */
SCIPexprgraphSetVarsBounds(SCIP_EXPRGRAPH * exprgraph,SCIP_INTERVAL * varbounds)15010 void SCIPexprgraphSetVarsBounds(
15011    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15012    SCIP_INTERVAL*        varbounds           /**< new bounds for variables */
15013    )
15014 {
15015    assert(exprgraph != NULL);
15016    assert(varbounds != NULL || exprgraph->nvars == 0);
15017 
15018    BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
15019 }
15020 
15021 /** sets bounds for a single variable */
SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH * exprgraph,void * var,SCIP_INTERVAL varbounds)15022 void SCIPexprgraphSetVarBounds(
15023    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15024    void*                 var,                /**< variable */
15025    SCIP_INTERVAL         varbounds           /**< new bounds of variable */
15026    )
15027 {
15028    int pos;
15029 
15030    assert(exprgraph != NULL);
15031    assert(var != NULL);
15032    assert(SCIPhashmapExists(exprgraph->varidxs, var));
15033 
15034    pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15035    assert(pos < exprgraph->nvars);
15036    assert(exprgraph->vars[pos] == var);
15037 
15038    exprgraph->varbounds[pos] = varbounds;
15039 }
15040 
15041 /** sets bounds for a single variable given as expression graph node */
SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * varnode,SCIP_INTERVAL varbounds)15042 void SCIPexprgraphSetVarNodeBounds(
15043    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15044    SCIP_EXPRGRAPHNODE*   varnode,            /**< expression graph node corresponding to variable */
15045    SCIP_INTERVAL         varbounds           /**< new bounds of variable */
15046    )
15047 {
15048    int pos;
15049 
15050    assert(exprgraph != NULL);
15051    assert(varnode != NULL);
15052 
15053    pos = varnode->data.intval;
15054    assert(pos >= 0);
15055    assert(pos < exprgraph->nvars);
15056    assert(exprgraph->varnodes[pos] == varnode);
15057 
15058    exprgraph->varbounds[pos] = varbounds;
15059 }
15060 
15061 /** sets lower bound for a single variable given as expression graph node */
SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * varnode,SCIP_Real lb)15062 void SCIPexprgraphSetVarNodeLb(
15063    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15064    SCIP_EXPRGRAPHNODE*   varnode,            /**< expression graph node corresponding to variable */
15065    SCIP_Real             lb                  /**< new lower bound for variable */
15066    )
15067 {
15068    int pos;
15069 
15070    assert(exprgraph != NULL);
15071    assert(varnode != NULL);
15072 
15073    pos = varnode->data.intval;
15074    assert(pos >= 0);
15075    assert(pos < exprgraph->nvars);
15076    assert(exprgraph->varnodes[pos] == varnode);
15077 
15078    exprgraph->varbounds[pos].inf = lb;
15079 }
15080 
15081 /** sets upper bound for a single variable given as expression graph node */
SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * varnode,SCIP_Real ub)15082 void SCIPexprgraphSetVarNodeUb(
15083    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15084    SCIP_EXPRGRAPHNODE*   varnode,            /**< expression graph node corresponding to variable */
15085    SCIP_Real             ub                  /**< new upper bound for variable */
15086    )
15087 {
15088    int pos;
15089 
15090    assert(exprgraph != NULL);
15091    assert(varnode != NULL);
15092 
15093    pos = varnode->data.intval;
15094    assert(pos >= 0);
15095    assert(pos < exprgraph->nvars);
15096    assert(exprgraph->varnodes[pos] == varnode);
15097 
15098    exprgraph->varbounds[pos].sup = ub;
15099 }
15100 
15101 /** gets bounds that are stored for all variables */
SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH * exprgraph)15102 SCIP_INTERVAL* SCIPexprgraphGetVarsBounds(
15103    SCIP_EXPRGRAPH*       exprgraph           /**< expression graph */
15104    )
15105 {
15106    return exprgraph->varbounds;
15107 }
15108 
15109 /** creates an empty expression graph */
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)15110 SCIP_RETCODE SCIPexprgraphCreate(
15111    BMS_BLKMEM*           blkmem,             /**< block memory */
15112    SCIP_EXPRGRAPH**      exprgraph,          /**< buffer to store pointer to expression graph */
15113    int                   varssizeinit,       /**< minimal initial size for variables array, or -1 to choose automatically */
15114    int                   depthinit,          /**< minimal initial depth of expression graph, or -1 to choose automatically */
15115    SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
15116    SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
15117    SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
15118    void*                 userdata            /**< user data to pass to callback functions */
15119    )
15120 {
15121    assert(blkmem != NULL);
15122    assert(exprgraph != NULL);
15123 
15124    SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
15125    BMSclearMemory(*exprgraph);
15126    (*exprgraph)->blkmem = blkmem;
15127 
15128    /* create nodes's arrays */
15129    SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
15130    assert((*exprgraph)->depth >= 1);
15131 
15132    /* create var's arrays and hashmap */
15133    ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
15134    SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, (*exprgraph)->varssize) );
15135 
15136    /* empty array of constants is sorted */
15137    (*exprgraph)->constssorted = TRUE;
15138 
15139    /* store callback functions and user data */
15140    (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
15141    (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
15142    (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
15143    (*exprgraph)->userdata = userdata;
15144 
15145    return SCIP_OKAY;
15146 }
15147 
15148 /** frees an expression graph */
SCIPexprgraphFree(SCIP_EXPRGRAPH ** exprgraph)15149 SCIP_RETCODE SCIPexprgraphFree(
15150    SCIP_EXPRGRAPH**      exprgraph           /**< pointer to expression graph that should be freed */
15151    )
15152 {
15153    BMS_BLKMEM* blkmem;
15154    int d;
15155 
15156    assert( exprgraph != NULL);
15157    assert(*exprgraph != NULL);
15158    assert((*exprgraph)->nvars == 0);
15159    assert((*exprgraph)->nconsts == 0);
15160 
15161    blkmem = (*exprgraph)->blkmem;
15162    assert(blkmem != NULL);
15163 
15164    /* free nodes arrays */
15165    for( d = 0; d < (*exprgraph)->depth; ++d )
15166    {
15167       assert((*exprgraph)->nnodes[d] == 0);
15168       BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]);  /*lint !e866*/
15169    }
15170    assert((*exprgraph)->nodes     != NULL);
15171    assert((*exprgraph)->nnodes    != NULL);
15172    assert((*exprgraph)->nodessize != NULL);
15173    BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes,     (*exprgraph)->depth);
15174    BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes,    (*exprgraph)->depth);
15175    BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
15176 
15177    /* free variables arrays and hashmap */
15178    BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars,      (*exprgraph)->varssize);
15179    BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes,  (*exprgraph)->varssize);
15180    BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
15181    SCIPhashmapFree(&(*exprgraph)->varidxs);
15182 
15183    /* free constants array */
15184    BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
15185 
15186    /* free graph struct */
15187    BMSfreeBlockMemory(blkmem, exprgraph);
15188 
15189    return SCIP_OKAY;
15190 }
15191 
15192 /** adds an expression graph node to an expression graph
15193  *
15194  *  Expression graph assumes ownership of node.
15195  *  Children are notified about new parent.
15196  *  Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
15197  */
SCIPexprgraphAddNode(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,int mindepth,int nchildren,SCIP_EXPRGRAPHNODE ** children)15198 SCIP_RETCODE SCIPexprgraphAddNode(
15199    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15200    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node to add */
15201    int                   mindepth,           /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
15202    int                   nchildren,          /**< number of children */
15203    SCIP_EXPRGRAPHNODE**  children            /**< children nodes, or NULL if no children */
15204    )
15205 {
15206    SCIP_Bool childvalsvalid;
15207    int depth;
15208    int i;
15209 
15210    assert(exprgraph != NULL);
15211    assert(node != NULL);
15212    assert(node->pos < 0);          /* node should have no position in graph yet */
15213    assert(node->depth < 0);        /* node should have no position in graph yet */
15214    assert(node->nchildren == 0);   /* node should not have stored children yet */
15215    assert(node->children == NULL); /* node should not have stored children yet */
15216    assert(node->nparents == 0);    /* node should not have parents stored yet */
15217    assert(children != NULL || nchildren == 0);
15218 
15219    /* choose depth as maximal depth of children + 1, and at least mindepth */
15220    depth = MAX(0, mindepth);
15221    for( i = 0; i < nchildren; ++i )
15222    {
15223       if( children[i]->depth >= depth )  /*lint !e613*/
15224          depth = children[i]->depth + 1;  /*lint !e613*/
15225    }
15226 
15227    /* ensure that expression graph is deep enough */
15228    SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
15229    assert(exprgraph->depth > depth);
15230 
15231    /* ensure enough space for nodes at depth depth */
15232    ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1);  /*lint !e866*/
15233 
15234    /* add node to graph */
15235    node->depth = depth;
15236    node->pos   = exprgraph->nnodes[depth];
15237    exprgraph->nodes[depth][node->pos] = node;
15238    ++exprgraph->nnodes[depth];
15239 
15240    /* add as parent to children
15241     * and check if children has valid values */
15242    childvalsvalid = TRUE;
15243    for( i = 0; i < nchildren; ++i )
15244    {
15245       SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) );  /*lint !e613*/
15246       childvalsvalid &= (children[i]->value != SCIP_INVALID);  /*lint !e777 !e514 !e613*/
15247    }
15248    /* store children */
15249    if( nchildren > 0 )
15250    {
15251       SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
15252       node->nchildren = nchildren;
15253    }
15254 
15255    if( node->op == SCIP_EXPR_CONST )
15256    {
15257       /* set bounds to constant value of node */
15258       node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
15259       SCIPintervalSet(&node->bounds, node->data.dbl);
15260    }
15261    else
15262    {
15263       /* set bounds to entire, set status to "should recompute", and note that we have to update something */
15264       node->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
15265       SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
15266       exprgraph->needvarboundprop = TRUE;
15267    }
15268 
15269    /* if not a variable, set value of node according to values of children (if all have valid values) */
15270    if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
15271    {
15272       SCIP_CALL( exprgraphNodeEval(node, NULL) );
15273    }
15274 
15275    return SCIP_OKAY;
15276 }
15277 
15278 /** adds variables to an expression graph, if not existing yet
15279  *
15280  *  Also already existing nodes are enabled.
15281  */
SCIPexprgraphAddVars(SCIP_EXPRGRAPH * exprgraph,int nvars,void ** vars,SCIP_EXPRGRAPHNODE ** varnodes)15282 SCIP_RETCODE SCIPexprgraphAddVars(
15283    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15284    int                   nvars,              /**< number of variables to add */
15285    void**                vars,               /**< variables to add */
15286    SCIP_EXPRGRAPHNODE**  varnodes            /**< array to store nodes corresponding to variables, or NULL if not of interest */
15287    )
15288 {
15289    SCIP_EXPRGRAPHNODE* node;
15290    SCIP_EXPROPDATA opdata;
15291    int i;
15292 
15293    assert(exprgraph != NULL);
15294    assert(exprgraph->depth >= 1);
15295    assert(vars != NULL || nvars == 0);
15296 
15297    /* if there are no variables yet, then it's quite likely that we will create new nodes for all vars, so can easily estimate how much space we will need in variables array and nodes at depth 0 arrays */
15298    if( exprgraph->nvars == 0 )
15299    {
15300       ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15301       ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15302    }
15303 
15304    for( i = 0; i < nvars; ++i )
15305    {
15306       /* skip variables that exist already */
15307       if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15308       {
15309          (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node);  /*lint !e613*/
15310          assert(node != NULL);
15311 
15312          /* enable node */
15313          node->enabled = TRUE;
15314 
15315          if( varnodes != NULL )
15316             varnodes[i] = node;
15317 
15318          continue;
15319       }
15320 
15321       /* create new variable expression */
15322       opdata.intval = exprgraph->nvars;
15323       SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15324 
15325       /* add expression node to expression graph at depth 0 */
15326       SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15327 
15328       /* add variable node to vars arrays and hashmap */
15329       ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15330       exprgraph->vars[exprgraph->nvars] = vars[i];  /*lint !e613*/
15331       exprgraph->varnodes[exprgraph->nvars] = node;
15332       SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15333       SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[i], exprgraph->nvars) ); /*lint !e613*/
15334       ++exprgraph->nvars;
15335 
15336       if( varnodes != NULL )
15337          varnodes[i] = node;
15338 
15339       SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15340 
15341       /* call callback method, if set */
15342       if( exprgraph->exprgraphvaradded != NULL )
15343       {
15344          SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) );  /*lint !e613*/
15345       }
15346    }
15347 
15348    return SCIP_OKAY;
15349 }
15350 
15351 /** adds a constant to an expression graph, if not existing yet
15352  *
15353  *  Also already existing nodes are enabled.
15354  */
SCIPexprgraphAddConst(SCIP_EXPRGRAPH * exprgraph,SCIP_Real constant,SCIP_EXPRGRAPHNODE ** constnode)15355 SCIP_RETCODE SCIPexprgraphAddConst(
15356    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15357    SCIP_Real             constant,           /**< constant to add */
15358    SCIP_EXPRGRAPHNODE**  constnode           /**< buffer to store pointer to expression graph node corresponding to constant */
15359    )
15360 {
15361    SCIP_EXPROPDATA opdata;
15362 
15363    assert(exprgraph != NULL);
15364    assert(constnode != NULL);
15365 
15366    /* check if there is already an expression for this constant */
15367    if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15368    {
15369       assert(*constnode != NULL);
15370       assert((*constnode)->op == SCIP_EXPR_CONST);
15371       assert((*constnode)->data.dbl == constant);  /*lint !e777*/
15372       (*constnode)->enabled = TRUE;
15373       return SCIP_OKAY;
15374    }
15375 
15376    /* create new node for constant */
15377    opdata.dbl = constant;
15378    SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15379 
15380    /* add node to expression graph at depth 0 */
15381    SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15382    assert((*constnode)->depth == 0);
15383    assert((*constnode)->pos   == exprgraph->nnodes[0]-1);
15384 
15385    /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15386    ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15387    exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15388    ++exprgraph->nconsts;
15389    exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15390 
15391    SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15392 
15393    return SCIP_OKAY;
15394 }
15395 
15396 /** adds sum of expression trees into expression graph
15397  *
15398  *  node will also be captured.
15399  *
15400  *  @note Parameters will be converted into constants
15401  */
SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH * exprgraph,int nexprtrees,SCIP_EXPRTREE ** exprtrees,SCIP_Real * coefs,SCIP_EXPRGRAPHNODE ** rootnode,SCIP_Bool * rootnodeisnew)15402 SCIP_RETCODE SCIPexprgraphAddExprtreeSum(
15403    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15404    int                   nexprtrees,         /**< number of expression trees to add */
15405    SCIP_EXPRTREE**       exprtrees,          /**< expression trees that should be added */
15406    SCIP_Real*            coefs,              /**< coefficients of expression trees, or NULL if all 1.0 */
15407    SCIP_EXPRGRAPHNODE**  rootnode,           /**< buffer to store expression graph node corresponding to root of expression tree */
15408    SCIP_Bool*            rootnodeisnew       /**< buffer to indicate whether the node in *rootnode has been newly created for this expression tree (otherwise, expression tree was already in graph) */
15409    )
15410 {
15411    SCIP_Bool allone;
15412 
15413    assert(exprgraph != NULL);
15414    assert(nexprtrees > 0);
15415    assert(exprtrees != NULL);
15416    assert(rootnode != NULL);
15417    assert(rootnodeisnew != NULL);
15418 
15419    *rootnode = NULL;
15420 
15421    if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15422    {
15423       assert(exprtrees[0] != NULL);
15424       assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15425 
15426       /* coverity[var_deref_model] */
15427       SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15428    }
15429    else
15430    {
15431       SCIP_EXPROP op;
15432       SCIP_EXPRGRAPHNODE** rootnodes;
15433       SCIP_Bool rootnodeisnew_;
15434       int i;
15435 
15436       *rootnodeisnew = TRUE;
15437       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15438 
15439       allone = TRUE;
15440       for( i = 0; i < nexprtrees; ++i )
15441       {
15442          assert(exprtrees[i] != NULL);
15443          assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15444 
15445          SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) );  /*lint !e644*/
15446          assert(rootnodes[i] != NULL);
15447          *rootnodeisnew &= rootnodeisnew_;
15448 
15449          allone &= (coefs == NULL || coefs[i] == 1.0);  /*lint !e514*/
15450       }
15451 
15452       /* decide which operand we want to use for the root node */
15453       if( coefs == NULL || allone )
15454          op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15455       else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15456          op = SCIP_EXPR_MINUS;
15457       else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15458       {
15459          SCIP_EXPRGRAPHNODE* tmp;
15460 
15461          tmp = rootnodes[0];
15462          rootnodes[0] = rootnodes[1];
15463          rootnodes[1] = tmp;
15464          op = SCIP_EXPR_MINUS;
15465       }
15466       else
15467          op = SCIP_EXPR_LINEAR;
15468 
15469       if( op != SCIP_EXPR_LINEAR )
15470       {
15471          SCIP_EXPROPDATA data;
15472          data.data = NULL;
15473 
15474          if( !*rootnodeisnew )
15475          {
15476             /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15477             SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15478          }
15479 
15480          if( *rootnode == NULL )
15481          {
15482             /* create new node for sum of rootnodes and add to exprgraph */
15483             SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15484             SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15485             *rootnodeisnew = TRUE;
15486          }
15487          else
15488          {
15489             /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15490             *rootnodeisnew = FALSE;
15491          }
15492       }
15493       else
15494       {
15495          SCIP_EXPROPDATA data;
15496          SCIP_Real* lindata;
15497 
15498          assert(op == SCIP_EXPR_LINEAR);
15499 
15500          /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15501          SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15502          BMScopyMemoryArray(lindata, coefs, nexprtrees);  /*lint !e644*/
15503          lindata[nexprtrees] = 0.0;
15504          data.data = lindata;
15505 
15506          if( !*rootnodeisnew )
15507          {
15508             /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15509             SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15510          }
15511 
15512          if( *rootnode == NULL )
15513          {
15514             /* create new node for linear combination of rootnodes and add to exprgraph */
15515             SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15516             SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15517             *rootnodeisnew = TRUE;
15518          }
15519          else
15520          {
15521             /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15522             *rootnodeisnew = FALSE;
15523             BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15524          }
15525       }
15526 
15527       BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15528    }
15529    assert(*rootnode != NULL);
15530 
15531    SCIPexprgraphCaptureNode(*rootnode);
15532 
15533    SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15534       rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15535 
15536    return SCIP_OKAY;
15537 }
15538 
15539 /** replaces variable in expression graph by a linear sum of variables
15540  *
15541  *  Variables will be added if not in the graph yet.
15542  */
SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH * exprgraph,void * var,int ncoefs,SCIP_Real * coefs,void ** vars,SCIP_Real constant)15543 SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(
15544    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15545    void*                 var,                /**< variable to replace */
15546    int                   ncoefs,             /**< number of coefficients in linear term */
15547    SCIP_Real*            coefs,              /**< coefficients in linear term, or NULL if ncoefs == 0 */
15548    void**                vars,               /**< variables in linear term */
15549    SCIP_Real             constant            /**< constant offset */
15550    )
15551 {
15552    SCIP_EXPRGRAPHNODE* varnode;
15553    SCIP_Real* lindata;
15554    int varidx;
15555    int i;
15556 
15557    assert(exprgraph != NULL);
15558    assert(var != NULL);
15559    assert(SCIPhashmapExists(exprgraph->varidxs, var));
15560    assert(coefs != NULL || ncoefs == 0);
15561    assert(vars  != NULL || ncoefs == 0);
15562 
15563    varidx = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15564    assert(varidx < exprgraph->nvars);
15565    assert(exprgraph->vars[varidx] == var);
15566    varnode = exprgraph->varnodes[varidx];
15567    assert(varnode != NULL);
15568    assert(varnode->data.intval == varidx);
15569 
15570    if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) )  /*lint !e613*/
15571    {
15572       /* variable is replaced by constant or variable */
15573       SCIP_EXPRGRAPHNODE* node;
15574 
15575       /* check if there is already a node for this constant or variable */
15576       node = NULL;
15577       if( ncoefs == 0 )
15578       {
15579          (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15580          assert(node == NULL || node->data.dbl == constant);  /*lint !e777*/
15581       }
15582       else
15583       {
15584          (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node);  /*lint !e613*/
15585          assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]);  /*lint !e613*/
15586       }
15587 
15588       if( node != NULL )
15589       {
15590          SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15591 
15592          /* tell parents of varnode to replace child varnode by node, this may free varnode */
15593          SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15594 
15595          /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15596          if( varnode != NULL )
15597          {
15598             assert(varnode->nuses > 0);
15599             assert(varnode->nparents == 0);
15600 
15601             /* remove variable (but don't free it's node) from graph */
15602             SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15603 
15604             /* move varnode up to depth 1 */
15605             SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15606 
15607             /* turn into EXPR_SUM expression */
15608             varnode->op = SCIP_EXPR_SUM;
15609             varnode->data.data = NULL;
15610             SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) );  /*lint !e506*/
15611             varnode->children[0] = node;
15612             varnode->nchildren = 1;
15613             SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15614 
15615             varnode->value = node->value;
15616             varnode->bounds = node->bounds;
15617             varnode->boundstatus = (node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID) ? SCIP_EXPRBOUNDSTATUS_VALID : SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15618          }
15619       }
15620       else if( ncoefs == 0 )
15621       {
15622          /* turn node into EXPR_CONST node */
15623 
15624          /* remove variable (but don't free it's node) from graph */
15625          SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15626 
15627          /* convert into EXPR_CONST node */
15628          varnode->op = SCIP_EXPR_CONST;
15629          varnode->data.dbl = constant;
15630 
15631          varnode->value = constant;
15632          SCIPintervalSet(&varnode->bounds, constant);
15633          varnode->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
15634 
15635          /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15636          ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15637          exprgraph->constnodes[exprgraph->nconsts] = varnode;
15638          ++exprgraph->nconsts;
15639          exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15640       }
15641       else
15642       {
15643          /* turn node into EXPR_VARIDX node for new variable */
15644 
15645          /* remove variable (but don't free it's node) from graph */
15646          SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15647 
15648          varnode->data.intval = exprgraph->nvars;
15649 
15650          /* add variable node to vars arrays and hashmap */
15651          ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15652          exprgraph->vars[exprgraph->nvars] = vars[0];  /*lint !e613*/
15653          exprgraph->varnodes[exprgraph->nvars] = varnode;
15654          SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15655          SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[0], exprgraph->nvars) ); /*lint !e613*/
15656          ++exprgraph->nvars;
15657 
15658          /* call callback method, if set */
15659          if( exprgraph->exprgraphvaradded != NULL )
15660          {
15661             SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) );  /*lint !e613*/
15662          }
15663       }
15664 
15665       /* mark varnode and its parents as not simplified */
15666       if( varnode != NULL )
15667       {
15668          varnode->simplified = FALSE;
15669          for( i = 0; i < varnode->nparents; ++i )
15670             varnode->parents[i]->simplified = FALSE;
15671       }
15672 
15673       return SCIP_OKAY;
15674    }
15675 
15676    /* turn varnode into EXPR_LINEAR */
15677 
15678    /* remove variable (but don't free it's node) from graph */
15679    SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15680 
15681    /* move varnode up to depth 1 */
15682    SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15683 
15684    /* convert into EXPR_LINEAR node */
15685    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15686    BMScopyMemoryArray(lindata, coefs, ncoefs);  /*lint !e644*/
15687    lindata[ncoefs] = constant;
15688    varnode->data.data = (void*)lindata;
15689    varnode->op = SCIP_EXPR_LINEAR;
15690 
15691    /* add nodes corresponding to vars to expression graph, if not existing yet */
15692    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15693    SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15694    varnode->nchildren = ncoefs;
15695 
15696    /* notify vars about new parent varnode */
15697    for( i = 0; i < ncoefs; ++i )
15698    {
15699       SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15700    }
15701 
15702    /* set value and bounds to invalid, curvature can remain (still linear) */
15703    varnode->value = SCIP_INVALID;
15704    varnode->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15705 
15706    /* mark varnode and its parents as not simplified */
15707    varnode->simplified = FALSE;
15708    for( i = 0; i < varnode->nparents; ++i )
15709       varnode->parents[i]->simplified = FALSE;
15710 
15711    return SCIP_OKAY;
15712 }
15713 
15714 /** finds expression graph node corresponding to a variable */
SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH * exprgraph,void * var,SCIP_EXPRGRAPHNODE ** varnode)15715 SCIP_Bool SCIPexprgraphFindVarNode(
15716    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15717    void*                 var,                /**< variable to search for */
15718    SCIP_EXPRGRAPHNODE**  varnode             /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15719    )
15720 {
15721    int pos;
15722 
15723    assert(exprgraph != NULL);
15724    assert(var != NULL);
15725    assert(varnode != NULL);
15726 
15727    if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15728    {
15729       *varnode = NULL;
15730       return FALSE;
15731    }
15732 
15733    pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15734    assert(pos < exprgraph->nvars);
15735 
15736    *varnode = exprgraph->varnodes[pos];
15737    assert(*varnode != NULL);
15738    assert((*varnode)->op == SCIP_EXPR_VARIDX);
15739 
15740    return TRUE;
15741 }
15742 
15743 /** finds expression graph node corresponding to a constant */
SCIPexprgraphFindConstNode(SCIP_EXPRGRAPH * exprgraph,SCIP_Real constant,SCIP_EXPRGRAPHNODE ** constnode)15744 SCIP_Bool SCIPexprgraphFindConstNode(
15745    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15746    SCIP_Real             constant,           /**< constant to search for */
15747    SCIP_EXPRGRAPHNODE**  constnode           /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15748    )
15749 {
15750    int left;
15751    int right;
15752    int middle;
15753 
15754    assert(exprgraph != NULL);
15755    assert(constnode != NULL);
15756    assert(constant == constant); /* cannot search for nan */  /*lint !e777*/
15757 
15758    exprgraphSortConstNodes(exprgraph);
15759    assert(exprgraph->constssorted);
15760 
15761    /* find node using binary search */
15762    left = 0;
15763    right = exprgraph->nconsts-1;
15764    *constnode = NULL;
15765 
15766    while( left <= right )
15767    {
15768       middle = (left+right)/2;
15769       assert(0 <= middle && middle < exprgraph->nconsts);
15770 
15771       if( constant < exprgraph->constnodes[middle]->data.dbl )
15772          right = middle - 1;
15773       else if( constant > exprgraph->constnodes[middle]->data.dbl )
15774          left  = middle + 1;
15775       else
15776       {
15777          *constnode = exprgraph->constnodes[middle];
15778          break;
15779       }
15780    }
15781    if( left == right+1 )
15782       return FALSE;
15783 
15784    assert(*constnode != NULL);
15785    assert((*constnode)->op == SCIP_EXPR_CONST);
15786    assert((*constnode)->data.dbl == constant);  /*lint !e777*/
15787 
15788    return TRUE;
15789 }
15790 
15791 /** prints an expression graph in dot format */
SCIPexprgraphPrintDot(SCIP_EXPRGRAPH * exprgraph,SCIP_MESSAGEHDLR * messagehdlr,FILE * file,const char ** varnames)15792 SCIP_RETCODE SCIPexprgraphPrintDot(
15793    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15794    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
15795    FILE*                 file,               /**< file to print to, or NULL for stdout */
15796    const char**          varnames            /**< variable names, or NULL for generic names */
15797    )
15798 {
15799    int d;
15800    int i;
15801 
15802    assert(exprgraph != NULL);
15803 
15804    if( file == NULL )
15805       file = stdout;
15806 
15807    SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15808    SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15809 
15810    for( d = 0; d < exprgraph->depth; ++d )
15811    {
15812       if( exprgraph->nnodes[d] == 0 )
15813          continue;
15814 
15815       for( i = 0; i < exprgraph->nnodes[d]; ++i )
15816       {
15817          exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15818       }
15819    }
15820 
15821    /* tell dot that all nodes of depth 0 have the same rank */
15822    SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15823    for( i = 0; i < exprgraph->nnodes[0]; ++i )
15824       SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15825    SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15826 
15827    /* tell dot that all nodes without parent have the same rank */
15828    SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15829    for( d = 0; d < exprgraph->depth; ++d )
15830       for( i = 0; i < exprgraph->nnodes[d]; ++i )
15831          if( exprgraph->nodes[d][i]->nparents == 0 )
15832             SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15833    SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15834 
15835    SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15836 
15837    return SCIP_OKAY;
15838 }
15839 
15840 /** evaluates nodes of expression graph for given values of variables */
SCIPexprgraphEval(SCIP_EXPRGRAPH * exprgraph,SCIP_Real * varvals)15841 SCIP_RETCODE SCIPexprgraphEval(
15842    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15843    SCIP_Real*            varvals             /**< values for variables */
15844    )
15845 {
15846    int d;
15847    int i;
15848 
15849    assert(exprgraph != NULL);
15850    assert(varvals != NULL || exprgraph->nvars == 0);
15851 
15852    for( d = 0; d < exprgraph->depth; ++d )
15853       for( i = 0; i < exprgraph->nnodes[d]; ++i )
15854       {
15855          SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15856       }
15857 
15858    return SCIP_OKAY;
15859 }
15860 
15861 /** propagates bound changes in variables forward through the expression graph */
SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH * exprgraph,SCIP_Real infinity,SCIP_Bool clearreverseprop,SCIP_Bool * domainerror)15862 SCIP_RETCODE SCIPexprgraphPropagateVarBounds(
15863    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15864    SCIP_Real             infinity,           /**< value for infinity in interval arithmetics */
15865    SCIP_Bool             clearreverseprop,   /**< whether to reset bound tightenings from reverse propagation */
15866    SCIP_Bool*            domainerror         /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15867    )
15868 {
15869    SCIP_EXPRGRAPHNODE* node;
15870    SCIP_Bool boundchanged;
15871    int d;
15872    int i;
15873 
15874    assert(exprgraph != NULL);
15875    assert(domainerror != NULL);
15876 
15877    *domainerror = FALSE;
15878 
15879    /* update bounds in varnodes of expression graph */
15880    exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15881 
15882    /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15883    if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15884    {
15885       SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15886       return SCIP_OKAY;
15887    }
15888 
15889    /* propagate bound changes, interrupt if we get to a node with empty bounds */
15890    for( d = 1; d < exprgraph->depth; ++d )
15891    {
15892       for( i = 0; i < exprgraph->nnodes[d]; ++i )
15893       {
15894          node = exprgraph->nodes[d][i];
15895          SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15896          if( SCIPintervalIsEmpty(infinity, node->bounds) )
15897          {
15898             SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15899             /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15900             *domainerror = TRUE;
15901             return SCIP_OKAY;
15902          }
15903       }
15904    }
15905 
15906    exprgraph->needvarboundprop = FALSE;
15907 
15908    return SCIP_OKAY;
15909 }
15910 
15911 /** propagates bound changes in nodes backward through the graph
15912  *
15913  *  New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15914  *  NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15915  */
SCIPexprgraphPropagateNodeBounds(SCIP_EXPRGRAPH * exprgraph,SCIP_Real infinity,SCIP_Real minstrength,SCIP_Bool * cutoff)15916 void SCIPexprgraphPropagateNodeBounds(
15917    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15918    SCIP_Real             infinity,           /**< value for infinity in interval arithmetics */
15919    SCIP_Real             minstrength,        /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15920    SCIP_Bool*            cutoff              /**< buffer to store whether a node's bounds were propagated to an empty interval */
15921    )
15922 {
15923    SCIP_EXPRGRAPHNODE* node;
15924    int d;
15925    int i;
15926 
15927    assert(exprgraph != NULL);
15928    assert(cutoff != NULL);
15929 
15930    *cutoff = FALSE;
15931 
15932    for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15933    {
15934       for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15935       {
15936          node = exprgraph->nodes[d][i];
15937          exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15938       }
15939    }
15940    if( *cutoff )
15941       return;
15942 }
15943 
15944 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15945  *
15946  *  Implies update of bounds in expression graph.
15947  */
SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH * exprgraph,SCIP_Real infinity,SCIP_Bool clearreverseprop)15948 SCIP_RETCODE SCIPexprgraphCheckCurvature(
15949    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15950    SCIP_Real             infinity,           /**< value for infinity in interval arithmetics */
15951    SCIP_Bool             clearreverseprop    /**< whether to reset bound tightenings from reverse propagation */
15952    )
15953 {
15954    SCIP_EXPRGRAPHNODE* node;
15955    SCIP_Bool boundchanged;
15956    int d;
15957    int i;
15958 
15959    assert(exprgraph != NULL);
15960 
15961    /* update bounds in varnodes of expression graph */
15962    exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15963 
15964 #ifndef NDEBUG
15965    for( i = 0; i < exprgraph->nnodes[0]; ++i )
15966       assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15967 #endif
15968 
15969    for( d = 1; d < exprgraph->depth; ++d )
15970       for( i = 0; i < exprgraph->nnodes[d]; ++i )
15971       {
15972          node = exprgraph->nodes[d][i];
15973          assert(node != NULL);
15974 
15975          SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15976 
15977          if( SCIPintervalIsEmpty(infinity, node->bounds) )
15978          {
15979             SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15980             return SCIP_OKAY;
15981          }
15982       }
15983 
15984    return SCIP_OKAY;
15985 }
15986 
15987 /** aims at simplifying an expression graph
15988  *
15989  *  A domain error can occur when variables were fixed to values for which a parent expression is not defined (e.g., 0^(-1) or log(-1)).
15990  */
SCIPexprgraphSimplify(SCIP_EXPRGRAPH * exprgraph,SCIP_MESSAGEHDLR * messagehdlr,SCIP_Real eps,int maxexpansionexponent,SCIP_Bool * havechange,SCIP_Bool * domainerror)15991 SCIP_RETCODE SCIPexprgraphSimplify(
15992    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
15993    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
15994    SCIP_Real             eps,                /**< threshold, under which positive values are treat as 0 */
15995    int                   maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15996    SCIP_Bool*            havechange,         /**< buffer to indicate whether the graph has been modified */
15997    SCIP_Bool*            domainerror         /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15998    )
15999 {
16000    SCIP_EXPRGRAPHNODE* node;
16001    SCIP_Bool havechangenode;
16002    SCIP_Bool allsimplified;
16003    int d;
16004    int i;
16005    int j;
16006 
16007 #ifndef NDEBUG
16008    SCIP_Real* testx;
16009    SCIP_HASHMAP* testvalidx;
16010    SCIP_Real* testvals;
16011    SCIP_RANDNUMGEN* randnumgen;
16012    int testvalssize;
16013    int ntestvals;
16014 #endif
16015 
16016    assert(exprgraph != NULL);
16017    assert(eps >= 0.0);
16018    assert(havechange != NULL);
16019    assert(domainerror != NULL);
16020 
16021 #ifndef NDEBUG
16022    SCIP_CALL( SCIPrandomCreate(&randnumgen, exprgraph->blkmem, 862) ); /* see also #1848 */
16023    SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
16024    testvals = NULL;
16025    ntestvals = 0;
16026    testvalssize = 0;
16027 
16028    SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
16029    for( i = 0; i < exprgraph->nvars; ++i )
16030       testx[i] = SCIPrandomGetReal(randnumgen,
16031          exprgraph->varbounds[i].inf < -100.0 ? MIN(-100.0, exprgraph->varbounds[i].sup) : exprgraph->varbounds[i].inf,
16032          exprgraph->varbounds[i].sup >  100.0 ? MAX( 100.0, exprgraph->varbounds[i].inf) : exprgraph->varbounds[i].sup);  /*lint !e644*/
16033    SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
16034    for( d = 1; d < exprgraph->depth; ++d )
16035       for( i = 0; i < exprgraph->nnodes[d]; ++i )
16036       {
16037          node = exprgraph->nodes[d][i];
16038          assert(node != NULL);
16039 
16040          /* nodes that are in use should not be removed by simplifier, so for those we store their value and check if it remains the same after simplifier was run */
16041          if( node->nuses > 0 )
16042          {
16043             ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
16044             SCIP_CALL( SCIPhashmapInsertInt(testvalidx, (void*)node, ntestvals) );
16045             testvals[ntestvals] = SCIPexprgraphGetNodeVal(node);  /*lint !e613 !e794*/
16046             ++ntestvals;
16047          }
16048       }
16049 
16050    SCIPrandomFree(&randnumgen, exprgraph->blkmem);
16051 #endif
16052 
16053 #ifdef SCIP_OUTPUT
16054    {
16055       FILE* file;
16056       file = fopen("exprgraph_beforesimplify.dot", "w");
16057       if( file != NULL )
16058       {
16059          SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16060          fclose(file);
16061       }
16062    }
16063 #endif
16064 
16065    *havechange = FALSE;  /* we have not changed any node yet */
16066    *domainerror = FALSE; /* no domain errors encountered so far */
16067    allsimplified = TRUE; /* all nodes we looked at are simplified */
16068 
16069    /* call node simplifier from bottom up
16070     * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
16071     */
16072    for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
16073    {
16074       for( i = 0; i < exprgraph->nnodes[d]; ++i )
16075       {
16076          node = exprgraph->nodes[d][i];
16077          assert(node != NULL);
16078 
16079          havechangenode = FALSE; /* node did not change yet */
16080 
16081          if( node->op != SCIP_EXPR_CONST )
16082          {
16083             /* skip nodes that are already simplified */
16084             if( node->simplified )
16085                continue;
16086 
16087             allsimplified = FALSE;  /* looks like we found a node that has not been simplified */
16088 
16089             /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
16090             SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
16091             assert(node->simplified == TRUE);
16092             *havechange |= havechangenode;
16093          }
16094 
16095          /* if node was or has been converted into constant, may move to depth 0 */
16096          if( node->op == SCIP_EXPR_CONST )
16097          {
16098             SCIP_EXPRGRAPHNODE* constnode;
16099 
16100             if( !SCIPisFinite(node->value) )  /*lint !e777*/
16101             {
16102                SCIPdebugMessage("Expression graph simplify turned node into NaN or inf.\n");
16103                *domainerror = TRUE;
16104                break;
16105             }
16106 
16107             /* check if there is already a node for this constant */
16108             if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
16109             {
16110                assert(constnode->op == SCIP_EXPR_CONST);
16111                assert(constnode->data.dbl == node->value);  /*lint !e777*/
16112 
16113                if( node->nparents > 0 )
16114                {
16115                   /* move parents of this node to constnode, node may be freed if not in use */
16116                   SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
16117                   /* node should have no parents anymore, so it should have been freed if not in use */
16118                   assert(node == NULL || node->nuses > 0);
16119                   havechangenode = TRUE;
16120 
16121                   /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
16122                   if( node == NULL )
16123                   {
16124                      --i;
16125                      continue;
16126                   }
16127                }
16128                assert(node != NULL);
16129                assert(node->nuses > 0);
16130 
16131                if( constnode->nuses == 0 )
16132                {
16133                   /* move node to depth 0, adding it to constnodes */
16134                   SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16135 
16136                   /* move parents of constnode to node, so constnode is freed */
16137                   SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
16138                   assert(constnode == NULL);
16139                   havechangenode = TRUE;
16140 
16141                   /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16142                   --i;
16143                   continue;
16144                }
16145             }
16146             else
16147             {
16148                /* move to depth 0, adding it to constnodes */
16149                SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16150 
16151                /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16152                --i;
16153             }
16154          }
16155 
16156          /* if there was a change, mark parents as not simplified */
16157          if( havechangenode )
16158             for( j = 0; j < node->nparents; ++j )
16159                node->parents[j]->simplified = FALSE;
16160       }
16161    }  /*lint !e850*/
16162 
16163    /* if we did nothing, clean up and escape from here */
16164    if( allsimplified || *domainerror )
16165       goto EXPRGRAPHSIMPLIFY_CLEANUP;
16166 
16167    /* @todo find duplicate subexpressions in expression graph */
16168 
16169    /* unconvert polynomials into simpler expressions, where possible */
16170    for( d = 1; d < exprgraph->depth; ++d )
16171    {
16172       for( i = 0; i < exprgraph->nnodes[d]; ++i )
16173       {
16174          node = exprgraph->nodes[d][i];
16175          assert(node != NULL);
16176 
16177          if( node->op != SCIP_EXPR_POLYNOMIAL )
16178             continue;
16179 
16180          SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
16181 
16182          if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
16183          {
16184             /* node is identity w.r.t only child
16185              * replace node as child of parents by child of node
16186              */
16187 
16188             for( j = 0; node != NULL && j < node->nparents; ++j )
16189             {
16190                SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
16191             }
16192             /* node should have no parents anymore, so it should have been freed if not in use */
16193             assert(node == NULL || node->nuses > 0);
16194 
16195             /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
16196             if( node == NULL )
16197                --i;
16198          }
16199       }
16200    }  /*lint !e850*/
16201 
16202 #ifdef SCIP_OUTPUT
16203    {
16204       FILE* file;
16205       file = fopen("exprgraph_aftersimplify.dot", "w");
16206       if( file != NULL )
16207       {
16208          SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16209          fclose(file);
16210       }
16211    }
16212 #endif
16213 
16214 #ifndef NDEBUG
16215    for( d = 1; d < exprgraph->depth; ++d )
16216       for( i = 0; i < exprgraph->nnodes[d]; ++i )
16217       {
16218          int idx;
16219          SCIP_Real testval_before;
16220          SCIP_Real testval_after;
16221 
16222          node = exprgraph->nodes[d][i];
16223          assert(node != NULL);
16224 
16225          SCIP_CALL( exprgraphNodeEval(node, NULL) );
16226 
16227          /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
16228          if( node->nuses > 0 )
16229          {
16230             assert(SCIPhashmapExists(testvalidx, (void*)node));
16231 
16232             idx = SCIPhashmapGetImageInt(testvalidx, (void*)node);
16233             assert(idx < ntestvals);
16234             assert(testvals != NULL);
16235 
16236             testval_before = testvals[idx];  /*lint !e613*/
16237             testval_after = SCIPexprgraphGetNodeVal(node);
16238 
16239             assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), 10*eps));  /*lint !e777*/
16240          }
16241       }
16242 #endif
16243 
16244  EXPRGRAPHSIMPLIFY_CLEANUP:
16245 #ifndef NDEBUG
16246    BMSfreeMemoryArray(&testx);
16247    BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
16248    SCIPhashmapFree(&testvalidx);
16249 #endif
16250 
16251    return SCIP_OKAY;
16252 }
16253 
16254 /** creates an expression tree from a given node in an expression graph */
SCIPexprgraphGetTree(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * rootnode,SCIP_EXPRTREE ** exprtree)16255 SCIP_RETCODE SCIPexprgraphGetTree(
16256    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
16257    SCIP_EXPRGRAPHNODE*   rootnode,           /**< expression graph node that should represent root of expression tree */
16258    SCIP_EXPRTREE**       exprtree            /**< buffer to store pointer to created expression tree */
16259    )
16260 {
16261    SCIP_EXPR* root;
16262    int nexprvars;
16263    int* varidx;
16264    int i;
16265 
16266    assert(exprgraph != NULL);
16267    assert(rootnode  != NULL);
16268    assert(rootnode->depth >= 0);
16269    assert(rootnode->pos >= 0);
16270    assert(exprtree != NULL);
16271 
16272    /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16273    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16274 
16275    /* initially, no variable appears in the expression tree */
16276    for( i = 0; i < exprgraph->nvars; ++i )
16277       varidx[i] = -1;  /*lint !e644*/
16278    nexprvars = 0;
16279 
16280    /* create expression from the subgraph that has rootnode as root */
16281    SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16282 
16283    /* create expression tree for this expression */
16284    SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16285 
16286    /* copy variables into expression tree */
16287    if( nexprvars > 0 )
16288    {
16289       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16290       for( i = 0; i < exprgraph->nvars; ++i )
16291       {
16292          assert(varidx[i] >= -1);
16293          assert(varidx[i] < nexprvars);
16294          if( varidx[i] >= 0 )
16295             (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16296       }
16297    }
16298 
16299    BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16300 
16301    return SCIP_OKAY;
16302 }
16303 
16304 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16305  *
16306  *  Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16307  */
SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,int exprtreessize,int * nexprtrees,SCIP_EXPRTREE ** exprtrees,SCIP_Real * exprtreecoefs)16308 SCIP_RETCODE SCIPexprgraphGetSeparableTrees(
16309    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
16310    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node which represents expression to get */
16311    int                   exprtreessize,      /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16312    int*                  nexprtrees,         /**< buffer to store number of expression trees */
16313    SCIP_EXPRTREE**       exprtrees,          /**< array where to store expression trees */
16314    SCIP_Real*            exprtreecoefs       /**< array where to store coefficients of expression trees */
16315    )
16316 {
16317    int ncomponents;
16318    int* childcomp;
16319    int* varcomp;
16320    int compnr;
16321    SCIP_Bool haveoverlap;
16322    int i;
16323    int j;
16324    int k;
16325 
16326    SCIP_EXPR** exprs;
16327    int nexprs;
16328    int* childmap;
16329    int* childmapinv;
16330    int* varidx;
16331    int nexprvars;
16332 
16333    assert(exprgraph != NULL);
16334    assert(node != NULL);
16335    assert(node->depth >= 0);
16336    assert(node->pos >= 0);
16337    assert(exprtreessize > 0);
16338    assert(nexprtrees != NULL);
16339    assert(exprtrees != NULL);
16340    assert(exprtreecoefs != NULL);
16341 
16342    /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16343     * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16344    if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16345       (  node->op  != SCIP_EXPR_PLUS   &&
16346          node->op  != SCIP_EXPR_MINUS  &&
16347          node->op  != SCIP_EXPR_SUM    &&
16348          node->op  != SCIP_EXPR_LINEAR &&
16349          (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16350          (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16351    {
16352       *nexprtrees = 1;
16353       exprtreecoefs[0] = 1.0;
16354       SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16355 
16356       return SCIP_OKAY;
16357    }
16358 
16359    /* find components in node->children <-> variables graph */
16360    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16361    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16362    for( i = 0; i < exprgraph->nvars; ++i )
16363       varcomp[i] = -1;  /*lint !e644*/
16364 
16365    haveoverlap = FALSE;
16366    for( i = 0; i < node->nchildren; ++i )
16367    {
16368       compnr = i;
16369       exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp);  /*lint !e644*/
16370       assert(compnr >= 0);
16371       assert(compnr < node->nchildren);
16372       childcomp[i] = compnr;
16373 
16374       /* remember if component number was changed by CheckComponent */
16375       if( compnr != i )
16376          haveoverlap = TRUE;
16377    }
16378 
16379    BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16380 
16381    if( node->op == SCIP_EXPR_QUADRATIC )
16382    {
16383       /* merge components for products of children from different components */
16384       SCIP_EXPRDATA_QUADRATIC* data;
16385 
16386       data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16387       assert(data != NULL);
16388 
16389       for( i = 0; i < data->nquadelems; ++i )
16390          if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16391          {
16392             /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16393             compnr = childcomp[data->quadelems[i].idx2];
16394             for( j = 0; j < node->nchildren; ++j )
16395                if( childcomp[j] == compnr )
16396                   childcomp[j] = childcomp[data->quadelems[i].idx1];
16397             assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16398             haveoverlap = TRUE;
16399          }
16400    }
16401    else if( node->op == SCIP_EXPR_POLYNOMIAL )
16402    {
16403       /* merge components for monomials of children from different components */
16404       SCIP_EXPRDATA_POLYNOMIAL* data;
16405 
16406       data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16407       assert(data != NULL);
16408 
16409       for( i = 0; i < data->nmonomials; ++i )
16410          for( j = 1; j < data->monomials[i]->nfactors; ++j )
16411             if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16412             {
16413                /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16414                compnr = childcomp[data->monomials[i]->childidxs[j]];
16415                for( k = 0; k < node->nchildren; ++k )
16416                   if( childcomp[k] == compnr )
16417                      childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16418                assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16419                haveoverlap = TRUE;
16420             }
16421    }
16422 
16423    if( haveoverlap )
16424    {
16425       /* some component numbers are unused, thus relabel and count final number of components */
16426       int* compmap;
16427 
16428       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16429       for( i = 0; i < node->nchildren; ++i )
16430          compmap[i] = -1;  /*lint !e644*/
16431 
16432       ncomponents = 0;
16433       for( i = 0; i < node->nchildren; ++i )
16434       {
16435          if( compmap[childcomp[i]] == -1 )
16436             compmap[childcomp[i]] = ncomponents++;
16437          childcomp[i] = compmap[childcomp[i]];
16438       }
16439 
16440       BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16441    }
16442    else
16443    {
16444       ncomponents = node->nchildren;
16445    }
16446 
16447    if( ncomponents == 1 )
16448    {
16449       /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16450       BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16451 
16452       *nexprtrees = 1;
16453       exprtreecoefs[0] = 1.0;
16454       SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16455 
16456       return SCIP_OKAY;
16457    }
16458 
16459    if( ncomponents > exprtreessize )
16460    {
16461       /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16462       for( i = 0; i < node->nchildren; ++i )
16463          if( childcomp[i] >= exprtreessize )
16464             childcomp[i] = exprtreessize-1;
16465       ncomponents = exprtreessize;
16466    }
16467 
16468    assert(ncomponents >= 2);
16469 
16470    /* setup expression trees for each component */
16471    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16472    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16473    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16474    SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16475    for( i = 0; i < ncomponents; ++i )
16476    {
16477       /* initially, no variable appears in the expression tree */
16478       for( j = 0; j < exprgraph->nvars; ++j )
16479          varidx[j] = -1;  /*lint !e644*/
16480       nexprvars = 0;
16481 
16482       /* collect expressions from children belonging to component i */
16483       nexprs = 0;
16484       for( j = 0; j < node->nchildren; ++j )
16485       {
16486          assert(childcomp[j] >= 0);
16487          assert(childcomp[j] < ncomponents);
16488          if( childcomp[j] != i )
16489             continue;
16490 
16491          /* create expression from the subgraph that has child j as root */
16492          SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) );  /*lint !e644*/
16493          childmap[j] = nexprs;     /*lint !e644*/
16494          childmapinv[nexprs] = j;  /*lint !e644*/
16495          ++nexprs;
16496       }
16497 
16498       /* setup expression tree for component i */
16499       switch( node->op )
16500       {
16501       case SCIP_EXPR_PLUS:
16502       {
16503          assert(ncomponents == 2);
16504          assert(nexprs == 1);
16505 
16506          SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16507          exprtreecoefs[i] = 1.0;
16508 
16509          break;
16510       }
16511 
16512       case SCIP_EXPR_MINUS:
16513       {
16514          assert(ncomponents == 2);
16515          assert(nexprs == 1);
16516 
16517          SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16518          /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16519          assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16520          exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16521 
16522          break;
16523       }
16524 
16525       case SCIP_EXPR_SUM:
16526       {
16527          if( nexprs == 1 )
16528          {
16529             /* component corresponds to exactly one child of node */
16530             SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16531          }
16532          else
16533          {
16534             /* component corresponds to a sum of children of node */
16535             SCIP_EXPR* sumexpr;
16536 
16537             SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16538             SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16539          }
16540          exprtreecoefs[i] = 1.0;
16541 
16542          break;
16543       }
16544 
16545       case SCIP_EXPR_LINEAR:
16546       {
16547          SCIP_Real* nodecoefs;
16548          SCIP_EXPR* sumexpr;
16549 
16550          nodecoefs = (SCIP_Real*)node->data.data;
16551 
16552          /* if there is a constant, then we put it into the expression of the first component */
16553          if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16554          {
16555             /* component corresponds to exactly one child of node */
16556             SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16557             exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16558          }
16559          else if( nexprs == 1 )
16560          {
16561             /* component corresponds to a sum of one child and a constant */
16562             assert(i == 0);
16563             assert(nodecoefs[node->nchildren] != 0.0);
16564             assert(nodecoefs[childmapinv[0]] != 0.0);
16565             SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16566             SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16567             SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16568             exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16569          }
16570          else
16571          {
16572             /* component corresponds to a linear combination of children of node */
16573 
16574             if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) )  /*lint !e777*/
16575             {
16576                /* if two expressions with equal sign, then create PLUS expression */
16577                SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16578                exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16579             }
16580             else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) )  /*lint !e777*/
16581             {
16582                /* if two expressions with opposite sign, then create MINUS expression */
16583                SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16584                exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16585             }
16586             else
16587             {
16588                /* assemble coefficents and create SUM or LINEAR expression */
16589                SCIP_Real* coefs;
16590                SCIP_Bool allcoefsequal;
16591 
16592                SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16593                allcoefsequal = TRUE;
16594                coefs[0] = nodecoefs[childmapinv[0]];  /*lint !e644*/
16595                for( j = 0; j < nexprs; ++j )
16596                {
16597                   coefs[j] = nodecoefs[childmapinv[j]];
16598                   allcoefsequal &= (coefs[j] == coefs[0]);  /*lint !e777 !e514*/
16599                }
16600 
16601                /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16602                if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16603                {
16604                   SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16605                   exprtreecoefs[i] = coefs[0];
16606                }
16607                else
16608                {
16609                   SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16610                   exprtreecoefs[i] = 1.0;
16611                }
16612 
16613                BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16614             }
16615 
16616             SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16617          }
16618 
16619          break;
16620       }
16621 
16622       case SCIP_EXPR_QUADRATIC:
16623       {
16624          SCIP_EXPR* quadexpr;
16625          SCIP_EXPRDATA_QUADRATIC* nodedata;
16626          SCIP_Real* lincoefs;
16627          SCIP_QUADELEM* quadelems;
16628          int nquadelems;
16629 
16630          nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16631 
16632          exprtreecoefs[i] = 1.0;
16633 
16634          /* assemble coefficients corresponding to component i */
16635          if( nodedata->lincoefs != NULL )
16636          {
16637             SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16638             for( j = 0; j < nexprs; ++j )
16639                lincoefs[j] = nodedata->lincoefs[childmapinv[j]];  /*lint !e771*/
16640          }
16641          else
16642             lincoefs = NULL;
16643 
16644          SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16645          nquadelems = 0;
16646          for( j = 0; j < nodedata->nquadelems; ++j )
16647          {
16648             assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16649             if( childcomp[nodedata->quadelems[j].idx1] != i )
16650                continue;
16651             quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);  /*lint !e644*/
16652             quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16653             quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16654             ++nquadelems;
16655          }
16656 
16657          /* put constant into first component */
16658          SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16659          SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16660 
16661          BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16662          BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16663 
16664          break;
16665       }
16666 
16667       case SCIP_EXPR_POLYNOMIAL:
16668       {
16669          SCIP_EXPR* polyexpr;
16670          SCIP_EXPRDATA_POLYNOMIAL* nodedata;
16671          SCIP_EXPRDATA_MONOMIAL** monomials;
16672          SCIP_Real constant;
16673          int nmonomials;
16674 
16675          nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16676 
16677          constant = nodedata->constant;
16678          exprtreecoefs[i] = 1.0;
16679 
16680          /* collect monomials belonging to component i */
16681          SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16682          nmonomials = 0;
16683          for( j = 0; j < nodedata->nmonomials; ++j )
16684          {
16685             if( nodedata->monomials[j]->nfactors == 0 )
16686             {
16687                constant += nodedata->monomials[j]->coef;
16688                continue;
16689             }
16690             if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16691                continue;
16692 
16693             SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16694                   nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) );  /*lint !e644*/
16695             for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16696             {
16697                assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16698                monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16699             }
16700             ++nmonomials;
16701          }
16702 
16703          SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16704          SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16705 
16706          BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16707 
16708          break;
16709       }
16710 
16711       default:
16712          SCIPerrorMessage("unexpected operator type %d\n", node->op);
16713          return SCIP_ERROR;
16714       }  /*lint !e788*/
16715 
16716       /* copy variables into expression tree */
16717       if( nexprvars > 0 )
16718       {
16719          SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16720          for( j = 0; j < exprgraph->nvars; ++j )
16721          {
16722             assert(varidx[j] >= -1);
16723             assert(varidx[j] < nexprvars);
16724             if( varidx[j] >= 0 )
16725                exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16726          }
16727       }
16728    }
16729 
16730    BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16731    BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16732    BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16733    BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16734    BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16735 
16736    *nexprtrees = ncomponents;
16737 
16738    return SCIP_OKAY;
16739 }
16740 
16741 /** returns how often expression graph variables are used in a subtree of the expression graph */
SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,int * varsusage)16742 void SCIPexprgraphGetSubtreeVarsUsage(
16743    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
16744    SCIP_EXPRGRAPHNODE*   node,               /**< root node of expression graph subtree */
16745    int*                  varsusage           /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16746    )
16747 {
16748    assert(exprgraph != NULL);
16749    assert(node != NULL);
16750    assert(varsusage != NULL);
16751 
16752    BMSclearMemoryArray(varsusage, exprgraph->nvars);
16753 
16754    exprgraphNodeGetVarsUsage(node, varsusage);
16755 }
16756 
16757 /** gives the number of summands which the expression of an expression graph node consists of */
SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE * node)16758 int SCIPexprgraphGetSumTreesNSummands(
16759    SCIP_EXPRGRAPHNODE*   node                /**< expression graph node */
16760    )
16761 {
16762    switch( node->op )
16763    {
16764    case SCIP_EXPR_PLUS:
16765    case SCIP_EXPR_MINUS:
16766       return 2;
16767 
16768    case SCIP_EXPR_SUM:
16769    case SCIP_EXPR_LINEAR:
16770       return node->nchildren;
16771 
16772    case SCIP_EXPR_QUADRATIC:
16773    {
16774       SCIP_EXPRDATA_QUADRATIC* nodedata;
16775 
16776       nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16777       return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16778    }
16779 
16780    case SCIP_EXPR_POLYNOMIAL:
16781    {
16782       SCIP_EXPRDATA_POLYNOMIAL* nodedata;
16783 
16784       nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16785       return nodedata->nmonomials;
16786    }
16787 
16788    default:
16789       return 1;
16790    }  /*lint !e788*/
16791 }
16792 
16793 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH * exprgraph,SCIP_EXPRGRAPHNODE * node,int exprtreessize,int * nexprtrees,SCIP_EXPRTREE ** exprtrees,SCIP_Real * exprtreecoefs)16794 SCIP_RETCODE SCIPexprgraphGetSumTrees(
16795    SCIP_EXPRGRAPH*       exprgraph,          /**< expression graph */
16796    SCIP_EXPRGRAPHNODE*   node,               /**< expression graph node which represents expression to get */
16797    int                   exprtreessize,      /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16798    int*                  nexprtrees,         /**< buffer to store number of expression trees */
16799    SCIP_EXPRTREE**       exprtrees,          /**< array where to store expression trees */
16800    SCIP_Real*            exprtreecoefs       /**< array where to store coefficients of expression trees */
16801    )
16802 {
16803    int* varidx;
16804    int nexprvars;
16805    int i;
16806 
16807    assert(exprgraph != NULL);
16808    assert(node != NULL);
16809    assert(node->depth >= 0);
16810    assert(node->pos >= 0);
16811    assert(exprtreessize > 0);
16812    assert(nexprtrees != NULL);
16813    assert(exprtrees != NULL);
16814    assert(exprtreecoefs != NULL);
16815 
16816    /* if node is not separable, fallback to SCIPexprgraphGetTree */
16817    if( node->op != SCIP_EXPR_PLUS  &&
16818       node->op  != SCIP_EXPR_MINUS &&
16819       node->op  != SCIP_EXPR_SUM   &&
16820       (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16821       (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16822       (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16823    {
16824       *nexprtrees = 1;
16825       exprtreecoefs[0] = 1.0;
16826       SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16827 
16828       return SCIP_OKAY;
16829    }
16830 
16831    switch( node->op )
16832    {
16833    case SCIP_EXPR_PLUS:
16834    {
16835       assert(exprtreessize >= 2);
16836 
16837       SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16838       SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16839 
16840       exprtreecoefs[0] = 1.0;
16841       exprtreecoefs[1] = 1.0;
16842 
16843       *nexprtrees = 2;
16844       break;
16845    }
16846 
16847    case SCIP_EXPR_MINUS:
16848    {
16849       assert(exprtreessize >= 2);
16850 
16851       SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16852       SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16853 
16854       exprtreecoefs[0] =  1.0;
16855       exprtreecoefs[1] = -1.0;
16856 
16857       *nexprtrees = 2;
16858       break;
16859    }
16860 
16861    case SCIP_EXPR_SUM:
16862    {
16863       assert(exprtreessize >= node->nchildren);
16864 
16865       for( i = 0; i < node->nchildren; ++i )
16866       {
16867          SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16868          exprtreecoefs[i] = 1.0;
16869       }
16870 
16871       *nexprtrees = node->nchildren;
16872       break;
16873    }
16874 
16875    case SCIP_EXPR_LINEAR:
16876    {
16877       SCIP_Real* nodecoefs;
16878 
16879       assert(exprtreessize >= node->nchildren);
16880       assert(node->nchildren > 0);
16881 
16882       nodecoefs = (SCIP_Real*)node->data.data;
16883       assert(nodecoefs != NULL);
16884 
16885       for( i = 0; i < node->nchildren; ++i )
16886       {
16887          SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16888          exprtreecoefs[i] = nodecoefs[i];
16889       }
16890 
16891       /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16892       if( nodecoefs[node->nchildren] != 0.0 )
16893       {
16894          SCIP_EXPR* constexpr_;
16895 
16896          SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16897          SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16898       }
16899 
16900       *nexprtrees = node->nchildren;
16901       break;
16902    }
16903 
16904    case SCIP_EXPR_QUADRATIC:
16905    {
16906       SCIP_EXPRDATA_QUADRATIC* nodedata;
16907       SCIP_Real* lincoefs;
16908       SCIP_QUADELEM* quadelems;
16909       int nquadelems;
16910       SCIP_EXPR* expr;
16911       int j;
16912 
16913       nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16914       lincoefs = nodedata->lincoefs;
16915       quadelems = nodedata->quadelems;
16916       nquadelems = nodedata->nquadelems;
16917 
16918       assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16919       assert(node->nchildren > 0);
16920 
16921       *nexprtrees = 0;
16922       if( lincoefs != NULL )
16923       {
16924          for( i = 0; i < node->nchildren; ++i )
16925          {
16926             if( lincoefs[i] == 0.0 )
16927                continue;
16928             SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16929             exprtreecoefs[*nexprtrees] = lincoefs[i];
16930             ++*nexprtrees;
16931          }
16932       }
16933 
16934       /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16935       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16936 
16937       for( i = 0; i < nquadelems; ++i )
16938       {
16939          /* initially, no variable appears in the expression tree */
16940          for( j = 0; j < exprgraph->nvars; ++j )
16941             varidx[j] = -1;  /*lint !e644*/
16942          nexprvars = 0;
16943 
16944          /* create expression from the subgraph at quadelems[i].idx1 */
16945          SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16946 
16947          if( quadelems[i].idx1 == quadelems[i].idx2 )
16948          {
16949             /* create expression for square of expr */
16950             SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16951          }
16952          else
16953          {
16954             SCIP_EXPR* expr2;
16955 
16956             /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16957             SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16958             /* create expression for product */
16959             SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16960          }
16961 
16962          /* create expression tree for expr */
16963          SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16964 
16965          /* copy variables into expression tree */
16966          if( nexprvars > 0 )
16967          {
16968             SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16969             for( j = 0; j < exprgraph->nvars; ++j )
16970             {
16971                assert(varidx[j] >= -1);
16972                assert(varidx[j] < nexprvars);
16973                if( varidx[j] >= 0 )
16974                   exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16975             }
16976          }
16977 
16978          exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16979 
16980          ++*nexprtrees;
16981       }
16982 
16983       /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16984       if( nodedata->constant != 0.0 )
16985       {
16986          SCIP_EXPR* constexpr_;
16987 
16988          assert(*nexprtrees > 0);
16989          SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16990          SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16991       }
16992 
16993       BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16994 
16995       break;
16996    }
16997 
16998    case SCIP_EXPR_POLYNOMIAL:
16999    {
17000       SCIP_EXPRDATA_POLYNOMIAL* nodedata;
17001       SCIP_EXPRDATA_MONOMIAL** monomials;
17002       SCIP_Real constant;
17003       int nmonomials;
17004       SCIP_EXPR* expr;
17005       int* childidxs;
17006       int j;
17007 
17008       nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
17009       monomials = nodedata->monomials;
17010       nmonomials = nodedata->nmonomials;
17011       constant = nodedata->constant;
17012 
17013       assert(exprtreessize >= nmonomials);
17014       assert(node->nchildren > 0);
17015 
17016       *nexprtrees = 0;
17017 
17018       /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
17019       SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
17020 
17021       for( i = 0; i < nmonomials; ++i )
17022       {
17023          /* initially, no variable appears in the expression tree */
17024          for( j = 0; j < exprgraph->nvars; ++j )
17025             varidx[j] = -1;
17026          nexprvars = 0;
17027 
17028          if( monomials[i]->nfactors == 1 )
17029          {
17030             /* create expression from the subgraph at only factor */
17031             SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17032 
17033             /* put exponent in, if not 1.0 */
17034             if( monomials[i]->exponents[0] == 1.0 )
17035                ;
17036             else if( monomials[i]->exponents[0] == 2.0 )
17037             {
17038                SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
17039             }
17040             else if( EPSISINT(monomials[i]->exponents[0], 0.0) )  /*lint !e835*/
17041             {
17042                SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
17043             }
17044             else
17045             {
17046                SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
17047             }
17048          }
17049          else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
17050          {
17051             SCIP_EXPR* expr2;
17052 
17053             /* create expressions for both factors */
17054             SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr,  &nexprvars, varidx) );
17055             SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
17056 
17057             /* create expression for product of factors */
17058             SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
17059          }
17060          else
17061          {
17062             SCIP_EXPRDATA_MONOMIAL* monomial;
17063             SCIP_EXPR** exprs;
17064             int f;
17065 
17066             /* create expression for each factor, assemble varidx and nexprvars
17067              * create child indices (= identity) */
17068             SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs,     monomials[i]->nfactors) );
17069             SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
17070             for( f = 0; f < monomials[i]->nfactors; ++f )
17071             {
17072                SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) );  /*lint !e644*/
17073                childidxs[f] = f;  /*lint !e644*/
17074             }
17075 
17076             /* create monomial and polynomial expression for this monomial
17077              * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
17078              */
17079             SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
17080             SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
17081             constant = 0.0;
17082 
17083             BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs,     monomials[i]->nfactors);
17084             BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
17085          }
17086 
17087          /* create expression tree for expr */
17088          SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
17089 
17090          /* copy variables into expression tree */
17091          if( nexprvars > 0 )
17092          {
17093             SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
17094             for( j = 0; j < exprgraph->nvars; ++j )
17095             {
17096                assert(varidx[j] >= -1);
17097                assert(varidx[j] < nexprvars);
17098                if( varidx[j] >= 0 )
17099                   exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
17100             }
17101          }
17102 
17103          exprtreecoefs[*nexprtrees] = monomials[i]->coef;
17104 
17105          ++*nexprtrees;
17106       }
17107 
17108       /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
17109       if( constant != 0.0 )
17110       {
17111          SCIP_EXPR* constexpr_;
17112 
17113          assert(*nexprtrees > 0);
17114          SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
17115          SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
17116       }
17117 
17118       BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
17119 
17120       break;
17121    }
17122 
17123    default:
17124       SCIPerrorMessage("unexpected operator type %d\n", node->op);
17125       return SCIP_ERROR;
17126    }  /*lint !e788*/
17127 
17128    return SCIP_OKAY;
17129 }
17130 
17131 /**@} */
17132