Scippy

SCIP

Solving Constraint Integer Programs

expr_pow.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file expr_pow.c
26 * @ingroup DEFPLUGINS_EXPR
27 * @brief power expression handler
28 * @author Benjamin Mueller
29 * @author Ksenia Bestuzheva
30 *
31 * @todo signpower for exponent < 1 ?
32 */
33
34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35
36/*lint --e{835}*/
37/*lint -e777*/
38
39#include <string.h>
40
41#include "scip/expr_pow.h"
42#include "scip/pub_expr.h"
43#include "scip/expr_value.h"
44#include "scip/expr_product.h"
45#include "scip/expr_sum.h"
46#include "scip/expr_exp.h"
47#include "scip/expr_abs.h"
49
50#define POWEXPRHDLR_NAME "pow"
51#define POWEXPRHDLR_DESC "power expression"
52#define POWEXPRHDLR_PRECEDENCE 55000
53#define POWEXPRHDLR_HASHKEY SCIPcalcFibHash(21163.0)
54
55#define SIGNPOWEXPRHDLR_NAME "signpower"
56#define SIGNPOWEXPRHDLR_DESC "signed power expression"
57#define SIGNPOWEXPRHDLR_PRECEDENCE 56000
58#define SIGNPOWEXPRHDLR_HASHKEY SCIPcalcFibHash(21163.1)
59
60#define INITLPMAXPOWVAL 1e+06 /**< maximal allowed absolute value of power expression at bound,
61 * used for adjusting bounds in the convex case in initestimates */
62
63/*
64 * Data structures
65 */
66
67/** sign of a value (-1 or +1)
68 *
69 * 0.0 has sign +1 here (shouldn't matter, though)
70 */
71#define SIGN(x) ((x) >= 0.0 ? 1.0 : -1.0)
72
73#define SIGNPOW_ROOTS_KNOWN 10 /**< up to which (integer) exponents precomputed roots have been stored */
74
75/** The positive root of the polynomial (n-1) y^n + n y^(n-1) - 1 is needed in separation.
76 * Here we store these roots for small integer values of n.
77 */
78static
80 -1.0, /* no root for n=0 */
81 -1.0, /* no root for n=1 */
82 0.41421356237309504880, /* root for n=2 (-1+sqrt(2)) */
83 0.5, /* root for n=3 */
84 0.56042566045031785945, /* root for n=4 */
85 0.60582958618826802099, /* root for n=5 */
86 0.64146546982884663257, /* root for n=6 */
87 0.67033204760309682774, /* root for n=7 */
88 0.69428385661425826738, /* root for n=8 */
89 0.71453772716733489700, /* root for n=9 */
90 0.73192937842370733350 /* root for n=10 */
91};
92
93/** expression handler data */
94struct SCIP_ExprhdlrData
95{
96 SCIP_Real minzerodistance; /**< minimal distance from zero to enforce for child in bound tightening */
97 int expandmaxexponent; /**< maximal exponent when to expand power of sum in simplify */
98 SCIP_Bool distribfracexponent;/**< whether a fractional exponent is distributed onto factors on power of product */
99
100 SCIP_Bool warnedonpole; /**< whether we warned on enforcing a minimal distance from zero for child */
101};
102
103/** expression data */
104struct SCIP_ExprData
105{
106 SCIP_Real exponent; /**< exponent */
107 SCIP_Real root; /**< positive root of (n-1) y^n + n y^(n-1) - 1, or
108 SCIP_INVALID if not computed yet */
109};
110
111/*
112 * Local methods
113 */
114
115/** computes positive root of the polynomial (n-1) y^n + n y^(n-1) - 1 for n > 1 */
116static
118 SCIP* scip, /**< SCIP data structure */
119 SCIP_Real* root, /**< buffer where to store computed root */
120 SCIP_Real exponent /**< exponent n */
121 )
122{
123 SCIP_Real polyval;
124 SCIP_Real gradval;
125 int iter;
126
127 assert(scip != NULL);
128 assert(exponent > 1.0);
129 assert(root != NULL);
130
131 /* lookup for popular integer exponent */
132 if( SCIPisIntegral(scip, exponent) && exponent-0.5 < SIGNPOW_ROOTS_KNOWN )
133 {
134 *root = signpow_roots[(int)SCIPfloor(scip, exponent+0.5)];
135 return SCIP_OKAY;
136 }
137
138 /* lookup for weymouth exponent */
139 if( SCIPisEQ(scip, exponent, 1.852) )
140 {
141 *root = 0.39821689389382575186;
142 return SCIP_OKAY;
143 }
144
145 /* search for a positive root of (n-1) y^n + n y^(n-1) - 1
146 * use the closest precomputed root as starting value
147 */
148 if( exponent >= SIGNPOW_ROOTS_KNOWN )
150 else if( exponent <= 2.0 )
151 *root = signpow_roots[2];
152 else
153 *root = signpow_roots[(int)SCIPfloor(scip, exponent)];
154
155 for( iter = 0; iter < 1000; ++iter )
156 {
157 polyval = (exponent - 1.0) * pow(*root, exponent) + exponent * pow(*root, exponent - 1.0) - 1.0;
158 if( fabs(polyval) < 1e-12 && SCIPisZero(scip, polyval) )
159 break;
160
161 /* gradient of (n-1) y^n + n y^(n-1) - 1 is n(n-1)y^(n-1) + n(n-1)y^(n-2) */
162 gradval = (exponent - 1.0) * exponent * (pow(*root, exponent - 1.0) + pow(*root, exponent - 2.0));
163 if( SCIPisZero(scip, gradval) )
164 break;
165
166 /* update root by adding -polyval/gradval (Newton's method) */
167 *root -= polyval / gradval;
168 if( *root < 0.0 )
169 *root = 0.0;
170 }
171
172 if( !SCIPisZero(scip, polyval) )
173 {
174 SCIPerrorMessage("failed to compute root for exponent %g\n", exponent);
175 return SCIP_ERROR;
176 }
177 SCIPdebugMsg(scip, "root for %g is %.20g, certainty = %g\n", exponent, *root, polyval);
178 /* @todo cache root value for other expressions (an exponent seldom comes alone)?? (they are actually really fast to compute...) */
179
180 return SCIP_OKAY;
181}
182
183/** computes negative root of the polynomial (n-1) y^n - n y^(n-1) + 1 for n < -1 */
184static
186 SCIP* scip, /**< SCIP data structure */
187 SCIP_Real* root, /**< buffer where to store computed root */
188 SCIP_Real exponent /**< exponent n */
189 )
190{
191 SCIP_Real polyval;
192 SCIP_Real gradval;
193 int iter;
194
195 assert(scip != NULL);
196 assert(exponent < -1.0);
197 assert(root != NULL);
198
199 *root = -2.0; /* that's the solution for n=-2 */
200
201 for( iter = 0; iter < 1000; ++iter )
202 {
203 polyval = (exponent - 1.0) * pow(*root, exponent) - exponent * pow(*root, exponent - 1.0) + 1.0;
204 if( fabs(polyval) < 1e-12 && SCIPisZero(scip, polyval) )
205 break;
206
207 /* gradient of (n-1) y^n - n y^(n-1) + 1 is n(n-1)y^(n-1) - n(n-1)y^(n-2) */
208 gradval = (exponent - 1.0) * exponent * (pow(*root, exponent - 1.0) - pow(*root, exponent - 2.0));
209 if( SCIPisZero(scip, gradval) )
210 break;
211
212 /* update root by adding -polyval/gradval (Newton's method) */
213 *root -= polyval / gradval;
214 if( *root >= 0.0 )
215 *root = -1;
216 }
217
218 if( !SCIPisZero(scip, polyval) )
219 {
220 SCIPerrorMessage("failed to compute root for exponent %g\n", exponent);
221 return SCIP_ERROR;
222 }
223 SCIPdebugMsg(scip, "root for %g is %.20g, certainty = %g\n", exponent, *root, polyval);
224 /* @todo cache root value for other expressions (an exponent seldom comes alone)?? (they are actually really fast to compute...) */
225
226 return SCIP_OKAY;
227}
228
229/** creates expression data */
230static
232 SCIP* scip, /**< SCIP data structure */
233 SCIP_EXPRDATA** exprdata, /**< pointer where to store expression data */
234 SCIP_Real exponent /**< exponent of the power expression */
235 )
236{
237 assert(exprdata != NULL);
238
239 SCIP_CALL( SCIPallocBlockMemory(scip, exprdata) );
240
241 (*exprdata)->exponent = exponent;
242 (*exprdata)->root = SCIP_INVALID;
243
244 return SCIP_OKAY;
245}
246
247/** computes a tangent at a reference point by linearization
248 *
249 * for a normal power, linearization in xref is xref^exponent + exponent * xref^(exponent-1) (x - xref)
250 * = (1-exponent) * xref^exponent + exponent * xref^(exponent-1) * x
251 *
252 * for a signpower, linearization is the same if xref is positive
253 * for xref negative it is -(-xref)^exponent + exponent * (-xref)^(exponent-1) (x-xref)
254 * = (1-exponent) * (-xref)^(exponent-1) * xref + exponent * (-xref)^(exponent-1) * x
255 */
256static
258 SCIP* scip, /**< SCIP data structure */
259 SCIP_Bool signpower, /**< are we signpower or normal power */
260 SCIP_Real exponent, /**< exponent */
261 SCIP_Real xref, /**< reference point where to linearize */
262 SCIP_Real* constant, /**< buffer to store constant term of secant */
263 SCIP_Real* slope, /**< buffer to store slope of secant */
264 SCIP_Bool* success /**< buffer to store whether secant could be computed */
265 )
266{
267 SCIP_Real xrefpow;
268
269 assert(scip != NULL);
270 assert(constant != NULL);
271 assert(slope != NULL);
272 assert(success != NULL);
273 assert(xref != 0.0 || exponent > 0.0);
274 /* non-integral exponent -> reference point must be >= 0 or we do signpower */
275 assert(EPSISINT(exponent, 0.0) || signpower || !SCIPisNegative(scip, xref));
276
277 /* TODO power is not differentiable at 0.0 for exponent < 0
278 * should we forbid here that xref > 0, do something smart here, or just return success=FALSE?
279 */
280 /* assert(exponent >= 1.0 || xref > 0.0); */
281
282 if( !EPSISINT(exponent, 0.0) && !signpower && xref < 0.0 )
283 xref = 0.0;
284
285 xrefpow = pow(signpower ? REALABS(xref) : xref, exponent - 1.0);
286
287 /* if huge xref and/or exponent too large, then pow may overflow */
288 if( !SCIPisFinite(xrefpow) )
289 {
290 *success = FALSE;
291 return;
292 }
293
294 *constant = (1.0 - exponent) * xrefpow * xref;
295 *slope = exponent * xrefpow;
296 *success = TRUE;
297}
298
299/** computes a secant between lower and upper bound
300 *
301 * secant is xlb^exponent + (xub^exponent - xlb^exponent) / (xub - xlb) * (x - xlb)
302 * = xlb^exponent - slope * xlb + slope * x with slope = (xub^exponent - xlb^exponent) / (xub - xlb)
303 * same if signpower
304 */
305static
307 SCIP* scip, /**< SCIP data structure */
308 SCIP_Bool signpower, /**< are we signpower or normal power */
309 SCIP_Real exponent, /**< exponent */
310 SCIP_Real xlb, /**< lower bound on x */
311 SCIP_Real xub, /**< upper bound on x */
312 SCIP_Real* constant, /**< buffer to store constant term of secant */
313 SCIP_Real* slope, /**< buffer to store slope of secant */
314 SCIP_Bool* success /**< buffer to store whether secant could be computed */
315 )
316{
317 assert(scip != NULL);
318 assert(constant != NULL);
319 assert(slope != NULL);
320 assert(success != NULL);
321 assert(xlb >= 0.0 || EPSISINT(exponent, 0.0) || signpower);
322 assert(xub >= 0.0 || EPSISINT(exponent, 0.0) || signpower);
323 assert(exponent != 1.0);
324
325 *success = FALSE;
326
327 /* infinite bounds will not work */
328 if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
329 return;
330
331 /* first handle some special cases */
332 if( xlb == xub )
333 {
334 /* usually taken care of in separatePointPow already, but we might be called with different bounds here,
335 * e.g., when handling odd or signed power
336 */
337 *slope = 0.0;
338 *constant = pow(xlb, exponent);
339 }
340 else if( EPSISINT(exponent / 2.0, 0.0) && !signpower && xub > 0.1 && SCIPisFeasEQ(scip, xlb, -xub) )
341 {
342 /* for normal power with even exponents with xlb ~ -xub the slope would be very close to 0
343 * since xub^n - xlb^n is prone to cancellation here, we omit computing this secant (it's probably useless)
344 * unless the bounds are close to 0 as well (xub <= 0.1 in the "if" above)
345 * or we have exactly xlb=-xub, where we can return a clean 0.0 (though it's probably useless)
346 */
347 if( xlb == -xub )
348 {
349 *slope = 0.0;
350 *constant = pow(xlb, exponent);
351 }
352 else
353 {
354 return;
355 }
356 }
357 else if( xlb == 0.0 && exponent > 0.0 )
358 {
359 assert(xub >= 0.0);
360 *slope = pow(xub, exponent-1.0);
361 *constant = 0.0;
362 }
363 else if( xub == 0.0 && exponent > 0.0 )
364 {
365 /* normal pow: slope = - xlb^exponent / (-xlb) = xlb^(exponent-1)
366 * signpower: slope = (-xlb)^exponent / (-xlb) = (-xlb)^(exponent-1)
367 */
368 assert(xlb <= 0.0); /* so signpower or exponent is integral */
369 if( signpower )
370 *slope = pow(-xlb, exponent-1.0);
371 else
372 *slope = pow(xlb, exponent-1.0);
373 *constant = 0.0;
374 }
375 else if( SCIPisEQ(scip, xlb, xub) && (!signpower || xlb >= 0.0 || xub <= 0.0) )
376 {
377 /* Computing the slope as (xub^n - xlb^n)/(xub-xlb) can lead to cancellation.
378 * To avoid this, we replace xub^n by a Taylor expansion of pow at xlb:
379 * xub^n = xlb^n + n xlb^(n-1) (xub-xlb) + 0.5 n*(n-1) xlb^(n-2) (xub-xlb)^2 + 1/6 n*(n-1)*(n-2) xi^(n-3) (xub-xlb)^3 for some xlb < xi < xub
380 * Dropping the last term, the slope is (with an error of O((xub-xlb)^2) = 1e-18)
381 * n*xlb^(n-1) + 0.5 n*(n-1) xlb^(n-2)*(xub-xlb)
382 * = n*xlb^(n-1) (1 - 0.5*(n-1)) + 0.5 n*(n-1) xlb^(n-2)*xub
383 * = 0.5*n*((3-n)*xlb^(n-1) + (n-1) xlb^(n-2)*xub)
384 *
385 * test n=2: 0.5*2*((3-2)*xlb + (2-1) 1*xub) = xlb + xub ok
386 * n=3: 0.5*3*((3-3)*xlb + (3-1) xlb*xub) = 3*xlb*xub ~ xlb^2 + xlb*xub + xub^2 ok
387 *
388 * The constant is
389 * xlb^n - 0.5*n*((3-n) xlb^(n-1) + (n-1) xlb^(n-2)*xub) * xlb
390 * = xlb^n - 0.5*n*(3-n) xlb^n - 0.5*n*(n-1) xlb^(n-1)*xub
391 * = (1-0.5*n*(3-n)) xlb^n - 0.5 n*(n-1) xlb^(n-1) xub
392 *
393 * test n=2: (1-0.5*2*(3-2)) xlb^2 - 0.5 2*(2-1) xlb xub = -xlb*xub
394 * old formula: xlb^2 - (xlb+xub) * xlb = -xlb*xub ok
395 *
396 * For signpower with xub <= 0, we can negate xlb and xub:
397 * slope: (sign(xub)|xub|^n - sign(xlb)*|xlb|^n) / (xub-xlb) = -((-xub)^n - (-xlb)^n) / (xub - xlb) = ((-xub)^n - (-xlb)^n) / (-xub - (-xlb))
398 * constant: sign(xlb)|xlb|^n + slope * (xub - xlb) = -((-xlb)^n - slope * (xub - xlb)) = -((-xlb)^n + slope * ((-xub) - (-xlb)))
399 */
400 SCIP_Real xlb_n; /* xlb^n */
401 SCIP_Real xlb_n1; /* xlb^(n-1) */
402 SCIP_Real xlb_n2; /* xlb^(n-2) */
403
404 if( signpower && xub <= 0.0 )
405 {
406 xlb *= -1.0;
407 xub *= -1.0;
408 }
409
410 xlb_n = pow(xlb, exponent);
411 xlb_n1 = pow(xlb, exponent - 1.0);
412 xlb_n2 = pow(xlb, exponent - 2.0);
413
414 *slope = 0.5*exponent * ((3.0-exponent) * xlb_n1 + (exponent-1.0) * xlb_n2 * xub);
415 *constant = (1.0 - 0.5*exponent*(3.0-exponent)) * xlb_n - 0.5*exponent*(exponent-1.0) * xlb_n1 * xub;
416
417 if( signpower && xub <= 0.0 )
418 *constant *= -1.0;
419 }
420 else
421 {
422 SCIP_Real lbval;
423 SCIP_Real ubval;
424
425 if( signpower )
426 lbval = SIGN(xlb) * pow(REALABS(xlb), exponent);
427 else
428 lbval = pow(xlb, exponent);
429 if( !SCIPisFinite(lbval) )
430 return;
431
432 if( signpower )
433 ubval = SIGN(xub) * pow(REALABS(xub), exponent);
434 else
435 ubval = pow(xub, exponent);
436 if( !SCIPisFinite(ubval) )
437 return;
438
439 /* we still can have bad numerics when xlb^exponent and xub^exponent are very close, but xlb and xub are not
440 * for now, only check that things did not cancel out completely
441 */
442 if( lbval == ubval )
443 return;
444
445 *slope = (ubval - lbval) / (xub - xlb);
446 *constant = lbval - *slope * xlb;
447 }
448
449 /* check whether we had overflows */
450 if( !SCIPisFinite(*slope) || !SCIPisFinite(*constant) )
451 return;
452
453 *success = TRUE;
454}
455
456/** Separation for parabola
457 *
458 * - even positive powers: x^2, x^4, x^6 with x arbitrary, or
459 * - positive powers > 1: x^1.5, x^2.5 with x >= 0
460 <pre>
461 100 +--------------------------------------------------------------------+
462 |* + + + *|
463 90 |** x**2 ********|
464 | * * |
465 80 |-+* *+-|
466 | ** ** |
467 70 |-+ * * +-|
468 | ** ** |
469 60 |-+ * * +-|
470 | ** ** |
471 50 |-+ * * +-|
472 | ** ** |
473 40 |-+ * * +-|
474 | ** ** |
475 30 |-+ ** ** +-|
476 | ** ** |
477 20 |-+ ** ** +-|
478 | *** *** |
479 10 |-+ *** *** +-|
480 | + ***** + ***** + |
481 0 +--------------------------------------------------------------------+
482 -10 -5 0 5 10
483 </pre>
484 */
485static
487 SCIP* scip, /**< SCIP data structure */
488 SCIP_Real exponent, /**< exponent */
489 SCIP_Bool overestimate, /**< should the power be overestimated? */
490 SCIP_Real xlb, /**< lower bound on x */
491 SCIP_Real xub, /**< upper bound on x */
492 SCIP_Real xref, /**< reference point (where to linearize) */
493 SCIP_Real* constant, /**< buffer to store constant term of estimator */
494 SCIP_Real* slope, /**< buffer to store slope of estimator */
495 SCIP_Bool* islocal, /**< buffer to store whether estimator only locally valid, that is,
496 * it depends on given bounds */
497 SCIP_Bool* success /**< buffer to store whether estimator could be computed */
498 )
499{
500 assert(scip != NULL);
501 assert(constant != NULL);
502 assert(slope != NULL);
503 assert(islocal != NULL);
504 assert(success != NULL);
505 assert((exponent >= 0.0 && EPSISINT(exponent/2.0, 0.0)) || (exponent > 1.0 && xlb >= 0.0));
506
507 if( !overestimate )
508 {
509 computeTangent(scip, FALSE, exponent, xref, constant, slope, success);
510 *islocal = FALSE;
511 }
512 else
513 {
514 /* overestimation -> secant */
515 computeSecant(scip, FALSE, exponent, xlb, xub, constant, slope, success);
516 *islocal = TRUE;
517 }
518}
519
520
521/** Separation for signpower
522 *
523 * - odd positive powers, x^3, x^5, x^7
524 * - sign(x)|x|^n for n > 1
525 * - lower bound on x is negative (otherwise one should use separation for parabola)
526 <pre>
527 100 +--------------------------------------------------------------------+
528 | + + + **|
529 | x*abs(x) ******* |
530 | ** |
531 | ** |
532 50 |-+ *** +-|
533 | *** |
534 | *** |
535 | ***** |
536 | ***** |
537 0 |-+ **************** +-|
538 | ***** |
539 | ***** |
540 | *** |
541 | *** |
542 -50 |-+ *** +-|
543 | ** |
544 | ** |
545 | ** |
546 |** + + + |
547 -100 +--------------------------------------------------------------------+
548 -10 -5 0 5 10
549 </pre>
550 */
551static
553 SCIP* scip, /**< SCIP data structure */
554 SCIP_Real exponent, /**< exponent */
555 SCIP_Real root, /**< positive root of the polynomial (n-1) y^n + n y^(n-1) - 1,
556 * if xubglobal > 0 */
557 SCIP_Bool overestimate, /**< should the power be overestimated? */
558 SCIP_Real xlb, /**< lower bound on x, assumed to be non-positive */
559 SCIP_Real xub, /**< upper bound on x */
560 SCIP_Real xref, /**< reference point (where to linearize) */
561 SCIP_Real xlbglobal, /**< global lower bound on x */
562 SCIP_Real xubglobal, /**< global upper bound on x */
563 SCIP_Real* constant, /**< buffer to store constant term of estimator */
564 SCIP_Real* slope, /**< buffer to store slope of estimator */
565 SCIP_Bool* islocal, /**< buffer to store whether estimator only locally valid, that is,
566 * it depends on given bounds */
567 SCIP_Bool* branchcand, /**< buffer to indicate whether estimator would improve by branching
568 * on it */
569 SCIP_Bool* success /**< buffer to store whether estimator could be computed */
570 )
571{
572 assert(scip != NULL);
573 assert(constant != NULL);
574 assert(slope != NULL);
575 assert(islocal != NULL);
576 assert(branchcand != NULL);
577 assert(*branchcand == TRUE); /* the default */
578 assert(success != NULL);
579 assert(exponent >= 1.0);
580 assert(xlb < 0.0); /* otherwise estimateParabola should have been called */
581 assert(xubglobal <= 0.0 || (root > 0.0 && root < 1.0));
582
583 *success = FALSE;
584
585 if( !SCIPisPositive(scip, xub) )
586 {
587 /* easy case */
588 if( !overestimate )
589 {
590 /* underestimator is secant */
591 computeSecant(scip, TRUE, exponent, xlb, xub, constant, slope, success);
592 *islocal = TRUE;
593 }
594 else
595 {
596 /* overestimator is tangent */
597
598 /* we must linearize left of 0 */
599 if( xref > 0.0 )
600 xref = 0.0;
601
602 computeTangent(scip, TRUE, exponent, xref, constant, slope, success);
603
604 /* if global upper bound is > 0, then the tangent is only valid locally if the reference point is right of
605 * -root*xubglobal
606 */
607 *islocal = SCIPisPositive(scip, xubglobal) && xref > -root * xubglobal;
608
609 /* tangent doesn't move after branching */
610 *branchcand = FALSE;
611 }
612 }
613 else
614 {
615 SCIP_Real c;
616
617 if( !overestimate )
618 {
619 /* compute the special point which decides between secant and tangent */
620 c = -xlb * root;
621
622 if( xref < c )
623 {
624 /* underestimator is secant between xlb and c */
625 computeSecant(scip, TRUE, exponent, xlb, c, constant, slope, success);
626 *islocal = TRUE;
627 }
628 else
629 {
630 /* underestimator is tangent */
631 computeTangent(scip, TRUE, exponent, xref, constant, slope, success);
632
633 /* if reference point is left of -root*xlbglobal (c w.r.t. global bounds),
634 * then tangent is not valid w.r.t. global bounds
635 */
636 *islocal = xref < -root * xlbglobal;
637
638 /* tangent doesn't move after branching */
639 *branchcand = FALSE;
640 }
641 }
642 else
643 {
644 /* compute the special point which decides between secant and tangent */
645 c = -xub * root;
646
647 if( xref <= c )
648 {
649 /* overestimator is tangent */
650 computeTangent(scip, TRUE, exponent, xref, constant, slope, success);
651
652 /* if reference point is right of -root*xubglobal (c w.r.t. global bounds),
653 * then tangent is not valid w.r.t. global bounds
654 */
655 *islocal = xref > -root * xubglobal;
656
657 /* tangent doesn't move after branching */
658 *branchcand = FALSE;
659 }
660 else
661 {
662 /* overestimator is secant */
663 computeSecant(scip, TRUE, exponent, c, xub, constant, slope, success);
664 *islocal = TRUE;
665 }
666 }
667 }
668}
669
670/** Separation for positive hyperbola
671 *
672 * - x^-2, x^-4 with x arbitrary
673 * - x^-0.5, x^-1, x^-1.5, x^-3, x^-5 with x >= 0
674 <pre>
675 5 +----------------------------------------------------------------------+
676 | + * +* + |
677 | * * x**(-2) ******* |
678 4 |-+ * * +-|
679 | * * |
680 | * * |
681 | * * |
682 3 |-+ * * +-|
683 | * * |
684 | * * |
685 2 |-+ * * +-|
686 | * * |
687 | * * |
688 1 |-+ * * +-|
689 | * * |
690 | ** ** |
691 | ********** ********** |
692 0 |******************* *******************|
693 | |
694 | + + + |
695 -1 +----------------------------------------------------------------------+
696 -10 -5 0 5 10
697 </pre>
698 */
699static
701 SCIP* scip, /**< SCIP data structure */
702 SCIP_Real exponent, /**< exponent */
703 SCIP_Real root, /**< negative root of the polynomial (n-1) y^n - n y^(n-1) + 1,
704 * if x has mixed sign (w.r.t. global bounds?) and underestimating */
705 SCIP_Bool overestimate, /**< should the power be overestimated? */
706 SCIP_Real xlb, /**< lower bound on x */
707 SCIP_Real xub, /**< upper bound on x */
708 SCIP_Real xref, /**< reference point (where to linearize) */
709 SCIP_Real xlbglobal, /**< global lower bound on x */
710 SCIP_Real xubglobal, /**< global upper bound on x */
711 SCIP_Real* constant, /**< buffer to store constant term of estimator */
712 SCIP_Real* slope, /**< buffer to store slope of estimator */
713 SCIP_Bool* islocal, /**< buffer to store whether estimator only locally valid, that is,
714 * it depends on given bounds */
715 SCIP_Bool* branchcand, /**< buffer to indicate whether estimator would improve by branching
716 * on it */
717 SCIP_Bool* success /**< buffer to store whether estimator could be computed */
718 )
719{
720 assert(scip != NULL);
721 assert(constant != NULL);
722 assert(slope != NULL);
723 assert(islocal != NULL);
724 assert(branchcand != NULL);
725 assert(*branchcand == TRUE); /* the default */
726 assert(success != NULL);
727 assert(exponent < 0.0);
728 assert(EPSISINT(exponent/2.0, 0.0) || xlb >= 0.0);
729
730 *success = FALSE;
731
732 if( !overestimate )
733 {
734 if( xlb >= 0.0 || xub <= 0.0 )
735 {
736 /* underestimate and fixed sign -> tangent */
737
738 /* make sure xref has the same sign as xlb,xub */
739 if( xref < 0.0 && xlb >= 0.0 )
740 xref = xlb;
741 else if( xref > 0.0 && xub <= 0.0 )
742 xref = xub;
743
744 if( SCIPisZero(scip, xref) )
745 {
746 /* estimator would need to have an (essentially) infinite scope
747 * first try to make up a better refpoint
748 */
749 if( xub > 0.0 )
750 {
751 /* thus xlb >= 0.0; stay close to xlb (probably = 0) */
752 if( !SCIPisInfinity(scip, xub) )
753 xref = 0.9 * xlb + 0.1 * xub;
754 else
755 xref = 0.1;
756 }
757 else
758 {
759 /* xub <= 0.0; stay close to xub (probably = 0) */
760 if( !SCIPisInfinity(scip, -xlb) )
761 xref = 0.1 * xlb + 0.9 * xub;
762 else
763 xref = 0.1;
764 }
765
766 /* if still close to 0, then also bounds are close to 0, then just give up */
767 if( SCIPisZero(scip, xref) )
768 return;
769 }
770
771 computeTangent(scip, FALSE, exponent, xref, constant, slope, success);
772
773 /* tangent will not change if branching on x (even if only locally valid, see checks below) */
774 *branchcand = FALSE;
775
776 if( EPSISINT(exponent/2.0, 0.0) )
777 {
778 /* for even exponents (as in the picture):
779 * if x has fixed sign globally, then our tangent is also globally valid
780 * however, if x has mixed sign, then it depends on the constellation between reference point and global
781 * bounds, whether the tangent is globally valid (see also the longer discussion for the mixed-sign
782 * underestimator below )
783 */
784 if( xref > 0.0 && xlbglobal < 0.0 )
785 {
786 assert(xubglobal > 0.0); /* since xref > 0.0 */
787 assert(root < 0.0); /* root needs to be given */
788 /* if on right side, then tangent is only locally valid if xref is too much to the left */
789 *islocal = xref < xlbglobal * root;
790 }
791 else if( xref < 0.0 && xubglobal > 0.0 )
792 {
793 assert(xlbglobal < 0.0); /* since xref < 0.0 */
794 assert(root < 0.0); /* root needs to be given */
795 /* if on left side, then tangent is only locally valid if xref is too much to the right */
796 *islocal = xref > xubglobal * root;
797 }
798 else
799 *islocal = FALSE;
800 }
801 else
802 {
803 /* for odd exponents, the tangent is only locally valid if the sign of x is not fixed globally */
804 *islocal = xlbglobal * xubglobal < 0.0;
805 }
806 }
807 else
808 {
809 /* underestimate but mixed sign */
810 if( SCIPisInfinity(scip, -xlb) )
811 {
812 if( SCIPisInfinity(scip, xub) )
813 {
814 /* underestimator is constant 0, but that is globally valid */
815 *constant = 0.0;
816 *slope = 0.0;
817 *islocal = FALSE;
818 *success = TRUE;
819 return;
820 }
821
822 /* switch sign of x (mirror on ordinate) to make left bound finite and use its estimator */
823 estimateHyperbolaPositive(scip, exponent, root, overestimate, -xub, -xlb, -xref, -xubglobal, -xlbglobal,
824 constant, slope, islocal, branchcand, success);
825 if( *success )
826 *slope = -*slope;
827 }
828 else
829 {
830 /* The convex envelope of x^exponent for x in [xlb, infinity] is a line (secant) between xlb and some positive
831 * coordinate xhat, and x^exponent for x > xhat.
832 * Further, on [xlb,xub] with xub < xhat, the convex envelope is the secant between xlb and xub.
833 *
834 * To find xhat, consider the affine-linear function l(x) = xlb^n + c * (x - xlb) where n = exponent
835 * we look for a value of x such that f(x) and l(x) coincide and such that l(x) will be tangent to f(x) on that
836 * point, that is
837 * xhat > 0 such that f(xhat) = l(xhat) and f'(xhat) = l'(xhat)
838 * => xhat^n = xlb^n + c * (xhat - xlb) and n * xhat^(n-1) = c
839 * => xhat^n = xlb^n + n * xhat^n - n * xhat^(n-1) * xlb
840 * => 0 = xlb^n + (n-1) * xhat^n - n * xhat^(n-1) * xlb
841 *
842 * Divide by xlb^n, one gets a polynomial that looks very much like the one for signpower, but a sign is
843 * different (since this is *not signed* power):
844 * 0 = 1 + (n-1) * y^n - n * y^(n-1) where y = xhat/xlb
845 *
846 * The solution y < 0 (because xlb < 0 and we want xhat > 0) is what we expect to be given as "root".
847 */
848 assert(root < 0.0); /* root needs to be given */
849 if( xref <= xlb * root )
850 {
851 /* If the reference point is left of xhat (=xlb*root), then we can take the
852 * secant between xlb and root*xlb (= tangent at root*xlb).
853 * However, if xub < root*xlb, then we can tilt the estimator to be the secant between xlb and xub.
854 */
855 computeSecant(scip, FALSE, exponent, xlb, MIN(xlb * root, xub), constant, slope, success);
856 *islocal = TRUE;
857 }
858 else
859 {
860 /* If reference point is right of xhat, then take the tangent at xref.
861 * This will still be underestimating for x in [xlb,0], too.
862 * The tangent is globally valid, if we had also generated w.r.t. global bounds.
863 */
864 computeTangent(scip, FALSE, exponent, xref, constant, slope, success);
865 *islocal = xref < xlbglobal * root;
866 *branchcand = FALSE;
867 }
868 }
869 }
870 }
871 else
872 {
873 /* overestimate and mixed sign -> pole is within domain -> cannot overestimate */
874 if( xlb < 0.0 && xub > 0.0 )
875 return;
876
877 /* overestimate and fixed sign -> secant */
878 computeSecant(scip, FALSE, exponent, xlb, xub, constant, slope, success);
879 *islocal = TRUE;
880 }
881}
882
883/** Separation for mixed-sign hyperbola
884 *
885 * - x^-1, x^-3, x^-5 without x >= 0 (either x arbitrary or x negative)
886 <pre>
887 +----------------------------------------------------------------------+
888 | + * + |
889 4 |-+ * x**(-1) *******-|
890 | * |
891 | * |
892 | * |
893 2 |-+ * +-|
894 | * |
895 | ** |
896 | ********* |
897 0 |********************* *********************|
898 | ********* |
899 | ** |
900 | * |
901 -2 |-+ * +-|
902 | * |
903 | * |
904 | * |
905 -4 |-+ * +-|
906 | + *+ + |
907 +----------------------------------------------------------------------+
908 -10 -5 0 5 10
909 </pre>
910 */
911static
913 SCIP* scip, /**< SCIP data structure */
914 SCIP_Real exponent, /**< exponent */
915 SCIP_Bool overestimate, /**< should the power be overestimated? */
916 SCIP_Real xlb, /**< lower bound on x */
917 SCIP_Real xub, /**< upper bound on x */
918 SCIP_Real xref, /**< reference point (where to linearize) */
919 SCIP_Real xlbglobal, /**< global lower bound on x */
920 SCIP_Real xubglobal, /**< global upper bound on x */
921 SCIP_Real* constant, /**< buffer to store constant term of estimator */
922 SCIP_Real* slope, /**< buffer to store slope of estimator */
923 SCIP_Bool* islocal, /**< buffer to store whether estimator only locally valid, that is,
924 it depends on given bounds */
925 SCIP_Bool* branchcand, /**< buffer to indicate whether estimator would improve by branching
926 on it */
927 SCIP_Bool* success /**< buffer to store whether estimator could be computed */
928 )
929{
930 assert(scip != NULL);
931 assert(constant != NULL);
932 assert(slope != NULL);
933 assert(islocal != NULL);
934 assert(branchcand != NULL);
935 assert(*branchcand == TRUE); /* the default */
936 assert(success != NULL);
937 assert(exponent < 0.0);
938 assert(EPSISINT((exponent-1.0)/2.0, 0.0));
939 assert(xlb < 0.0);
940
941 *success = FALSE;
942
943 if( xub <= 0.0 )
944 {
945 /* x is negative */
946 if( !overestimate )
947 {
948 /* underestimation -> secant */
949 computeSecant(scip, FALSE, exponent, xlb, xub, constant, slope, success);
950 *islocal = TRUE;
951 }
952 else if( !SCIPisZero(scip, xlb/10.0) )
953 {
954 /* overestimation -> tangent */
955
956 /* need to linearize left of 0 */
957 if( xref > 0.0 )
958 xref = 0.0;
959
960 if( SCIPisZero(scip, xref) )
961 {
962 /* if xref is very close to 0.0, then slope would be infinite
963 * try to move closer to lower bound (if xlb < -10*eps)
964 */
965 if( !SCIPisInfinity(scip, -xlb) )
966 xref = 0.1*xlb + 0.9*xub;
967 else
968 xref = 0.1;
969 }
970
971 computeTangent(scip, FALSE, exponent, xref, constant, slope, success);
972
973 /* if x does not have a fixed sign globally, then our tangent is not globally valid
974 * (power is not convex on global domain)
975 */
976 *islocal = xlbglobal * xubglobal < 0.0;
977
978 /* tangent doesn't move by branching */
979 *branchcand = FALSE;
980 }
981 /* else: xlb is very close to zero, xub is <= 0, so slope would be infinite
982 * (for any reference point in [xlb, xub]) -> do not estimate
983 */
984 }
985 /* else: x has mixed sign -> pole is within domain -> cannot estimate */
986}
987
988/** builds an estimator for a power function */
989static
991 SCIP* scip, /**< SCIP data structure */
992 SCIP_EXPRDATA* exprdata, /**< expression data */
993 SCIP_Bool overestimate, /**< is this an overestimator? */
994 SCIP_Real childlb, /**< local lower bound on the child */
995 SCIP_Real childub, /**< local upper bound on the child */
996 SCIP_Real childglb, /**< global lower bound on the child */
997 SCIP_Real childgub, /**< global upper bound on the child */
998 SCIP_Bool childintegral, /**< whether child is integral */
999 SCIP_Real refpoint, /**< reference point */
1000 SCIP_Real exponent, /**< esponent */
1001 SCIP_Real* coef, /**< pointer to store the coefficient of the estimator */
1002 SCIP_Real* constant, /**< pointer to store the constant of the estimator */
1003 SCIP_Bool* success, /**< pointer to store whether the estimator was built successfully */
1004 SCIP_Bool* islocal, /**< pointer to store whether the estimator is valid w.r.t. local bounds
1005 * only */
1006 SCIP_Bool* branchcand /**< pointer to indicate whether to consider child for branching
1007 * (initialized to TRUE) */
1008 )
1009{
1010 SCIP_Bool isinteger;
1011 SCIP_Bool iseven;
1012
1013 assert(scip != NULL);
1014 assert(exprdata != NULL);
1015 assert(coef != NULL);
1016 assert(constant != NULL);
1017 assert(success != NULL);
1018 assert(islocal != NULL);
1019 assert(branchcand != NULL);
1020
1021 isinteger = EPSISINT(exponent, 0.0);
1022 iseven = isinteger && EPSISINT(exponent / 2.0, 0.0);
1023
1024 if( exponent == 2.0 )
1025 {
1026 /* important special case: quadratic case */
1027 /* initialize, because SCIPaddSquareXyz only adds to existing values */
1028 *success = TRUE;
1029 *coef = 0.0;
1030 *constant = 0.0;
1031
1032 if( overestimate )
1033 {
1034 SCIPaddSquareSecant(scip, 1.0, childlb, childub, coef, constant, success);
1035 *islocal = TRUE; /* secants are only valid locally */
1036 }
1037 else
1038 {
1039 SCIPaddSquareLinearization(scip, 1.0, refpoint, childintegral, coef, constant, success);
1040 *islocal = FALSE; /* linearizations are globally valid */
1041 *branchcand = FALSE; /* there is no improvement due to branching */
1042 }
1043 }
1044 else if( exponent > 0.0 && iseven )
1045 {
1046 estimateParabola(scip, exponent, overestimate, childlb, childub, refpoint, constant, coef, islocal, success);
1047 /* if estimate is locally valid, then we computed a secant and so branching can improve it */
1048 *branchcand = *islocal;
1049 }
1050 else if( exponent > 1.0 && childlb >= 0.0 )
1051 {
1052 /* make sure we linearize in convex region (if we will linearize) */
1053 if( refpoint < 0.0 )
1054 refpoint = 0.0;
1055
1056 estimateParabola(scip, exponent, overestimate, childlb, childub, refpoint, constant, coef, islocal, success);
1057
1058 /* if estimate is locally valid, then we computed a secant and so branching can improve it */
1059 *branchcand = *islocal;
1060
1061 /* if odd power, then check whether tangent on parabola is also globally valid, that is reference point is
1062 * right of -root*global-lower-bound
1063 */
1064 if( !*islocal && !iseven && childglb < 0.0 )
1065 {
1066 if( SCIPisInfinity(scip, -childglb) )
1067 *islocal = TRUE;
1068 else
1069 {
1070 if( exprdata->root == SCIP_INVALID )
1071 {
1072 SCIP_CALL( computeSignpowerRoot(scip, &exprdata->root, exponent) );
1073 }
1074 *islocal = refpoint < exprdata->root * (-childglb);
1075 }
1076 }
1077 }
1078 else if( exponent > 1.0 ) /* and !iseven && childlb < 0.0 due to previous if */
1079 {
1080 /* compute root if not known yet; only needed if mixed sign (global child ub > 0) */
1081 if( exprdata->root == SCIP_INVALID && childgub > 0.0 )
1082 {
1083 SCIP_CALL( computeSignpowerRoot(scip, &exprdata->root, exponent) );
1084 }
1085 estimateSignedpower(scip, exponent, exprdata->root, overestimate, childlb, childub, refpoint,
1086 -childglb, childgub, constant, coef, islocal, branchcand, success);
1087 }
1088 else if( exponent < 0.0 && (iseven || childlb >= 0.0) )
1089 {
1090 /* compute root if not known yet; only needed if mixed sign (globally) and iseven */
1091 if( exprdata->root == SCIP_INVALID && iseven )
1092 {
1093 SCIP_CALL( computeHyperbolaRoot(scip, &exprdata->root, exponent) );
1094 }
1095 estimateHyperbolaPositive(scip, exponent, exprdata->root, overestimate, childlb, childub, refpoint,
1096 childglb, childgub, constant, coef, islocal, branchcand, success);
1097 }
1098 else if( exponent < 0.0 )
1099 {
1100 assert(!iseven); /* should hold due to previous if */
1101 assert(childlb < 0.0); /* should hold due to previous if */
1102 assert(isinteger); /* should hold because childlb < 0.0 (same as assert above) */
1103
1104 estimateHyperbolaMixed(scip, exponent, overestimate, childlb, childub, refpoint, childglb, childgub,
1105 constant, coef, islocal, branchcand, success);
1106 }
1107 else
1108 {
1109 assert(exponent < 1.0); /* the only case that should be left */
1110 assert(exponent > 0.0); /* should hold due to previous if */
1111
1112 SCIPestimateRoot(scip, exponent, overestimate, childlb, childub, refpoint, constant, coef, islocal, success);
1113
1114 /* if estimate is locally valid, then we computed a secant, and so branching can improve it */
1115 *branchcand = *islocal;
1116 }
1117
1118 return SCIP_OKAY;
1119}
1120
1121/** fills an array of reference points for estimating on the convex side */
1122static
1124 SCIP* scip, /**< SCIP data structure */
1125 SCIP_Real exponent, /**< exponent of the power expression */
1126 SCIP_Real lb, /**< lower bound on the child variable */
1127 SCIP_Real ub, /**< upper bound on the child variable */
1128 SCIP_Real* refpoints /**< array to store the reference points */
1129 )
1130{
1131 SCIP_Real maxabsbnd;
1132
1133 assert(refpoints != NULL);
1134
1135 maxabsbnd = pow(INITLPMAXPOWVAL, 1 / exponent);
1136
1137 /* make sure the absolute values of bounds are not too large */
1138 if( ub > -maxabsbnd )
1139 lb = MAX(lb, -maxabsbnd);
1140 if( lb < maxabsbnd )
1141 ub = MIN(ub, maxabsbnd);
1142
1143 /* in the case when ub < -maxabsbnd or lb > maxabsbnd, we still want to at least make bounds finite */
1144 if( SCIPisInfinity(scip, -lb) )
1145 lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
1146 if( SCIPisInfinity(scip, ub) )
1147 ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
1148
1149 refpoints[0] = (7.0 * lb + ub) / 8.0;
1150 refpoints[1] = (lb + ub) / 2.0;
1151 refpoints[2] = (lb + 7.0 * ub) / 8.0;
1152}
1153
1154/** fills an array of reference points for sign(x)*abs(x)^n or x^n (n odd), where x has mixed signs
1155 *
1156 * The reference points are: the lower and upper bounds (one for secant and one for tangent);
1157 * and for the second tangent, the point on the convex part of the function between the point
1158 * deciding between tangent and secant, and the corresponding bound
1159 */
1160static
1162 SCIP* scip, /**< SCIP data structure */
1163 SCIP_EXPRDATA* exprdata, /**< expression data */
1164 SCIP_Real lb, /**< lower bound on the child variable */
1165 SCIP_Real ub, /**< upper bound on the child variable */
1166 SCIP_Real exponent, /**< exponent */
1167 SCIP_Bool underestimate, /**< are the refpoints for an underestimator */
1168 SCIP_Real* refpoints /**< array to store the reference points */
1169 )
1170{
1171 assert(refpoints != NULL);
1172
1173 if( (underestimate && SCIPisInfinity(scip, -lb)) || (!underestimate && SCIPisInfinity(scip, ub)) )
1174 return SCIP_OKAY;
1175
1176 if( exprdata->root == SCIP_INVALID )
1177 {
1178 SCIP_CALL( computeSignpowerRoot(scip, &exprdata->root, exponent) );
1179 }
1180
1181 /* make bounds finite (due to a previous if, only one can be infinite here) */
1182 if( SCIPisInfinity(scip, -lb) )
1183 lb = -ub * exprdata->root - 1.0;
1184 else if( SCIPisInfinity(scip, ub) )
1185 ub = -lb * exprdata->root + 1.0;
1186
1187 if( underestimate )
1188 {
1189 /* secant point */
1190 refpoints[0] = lb;
1191
1192 /* tangent points, depending on the special point */
1193 if( -lb * exprdata->root < ub - 2.0 )
1194 refpoints[2] = ub;
1195 if( -lb * exprdata->root < ub - 4.0 )
1196 refpoints[1] = (-lb * exprdata->root + ub) / 2.0;
1197 }
1198
1199 if( !underestimate )
1200 {
1201 /* secant point */
1202 refpoints[2] = ub;
1203
1204 /* tangent points, depending on the special point */
1205 if( -ub * exprdata->root > lb + 2.0 )
1206 refpoints[0] = lb;
1207 if( -ub * exprdata->root > lb + 4.0 )
1208 refpoints[1] = (lb - ub * exprdata->root) / 2.0;
1209 }
1210
1211 return SCIP_OKAY;
1212}
1213
1214/** choose reference points for adding initestimates cuts for a power expression */
1215static
1217 SCIP* scip, /**< SCIP data structure */
1218 SCIP_EXPRDATA* exprdata, /**< expression data */
1219 SCIP_Real lb, /**< lower bound on the child variable */
1220 SCIP_Real ub, /**< upper bound on the child variable */
1221 SCIP_Real* refpointsunder, /**< array to store reference points for underestimators */
1222 SCIP_Real* refpointsover, /**< array to store reference points for overestimators */
1223 SCIP_Bool underestimate, /**< whether refpoints for underestimation are needed */
1224 SCIP_Bool overestimate /**< whether refpoints for overestimation are needed */
1225 )
1226{
1227 SCIP_Bool convex;
1228 SCIP_Bool concave;
1229 SCIP_Bool mixedsign;
1230 SCIP_Bool even;
1231 SCIP_Real exponent;
1232
1233 assert(scip != NULL);
1234 assert(exprdata != NULL);
1235 assert(refpointsunder != NULL && refpointsover != NULL);
1236
1237 exponent = exprdata->exponent;
1238 even = EPSISINT(exponent, 0.0) && EPSISINT(exponent / 2.0, 0.0);
1239
1240 convex = FALSE;
1241 concave = FALSE;
1242 mixedsign = lb < 0.0 && ub > 0.0;
1243
1244 /* convex case:
1245 * - parabola with an even degree or positive domain
1246 * - hyperbola with a positive domain
1247 * - even hyperbola with a negative domain
1248 */
1249 if( (exponent > 1.0 && (lb >= 0 || even)) || (exponent < 0.0 && lb >= 0) || (exponent < 0.0 && even && ub <= 0.0) )
1250 convex = TRUE;
1251 /* concave case:
1252 * - parabola or hyperbola with a negative domain and (due to previous if) an uneven degree
1253 * - root
1254 */
1255 else if( ub <= 0 || (exponent > 0.0 && exponent < 1.0) )
1256 concave = TRUE;
1257
1258 if( underestimate )
1259 {
1260 if( convex )
1261 addTangentRefpoints(scip, exponent, lb, ub, refpointsunder);
1262 else if( (concave && !SCIPisInfinity(scip, -lb) && !SCIPisInfinity(scip, ub)) ||
1263 (exponent < 0.0 && even && mixedsign) ) /* concave with finite bounds or mixed even hyperbola */
1264 {
1265 /* for secant, refpoint doesn't matter, but we add it to signal that the corresponding cut should be created */
1266 refpointsunder[0] = (lb + ub) / 2.0;
1267 }
1268 else if( exponent > 1.0 && !even && mixedsign ) /* mixed signpower */
1269 {
1270 SCIP_CALL( addSignpowerRefpoints(scip, exprdata, lb, ub, exponent, TRUE, refpointsunder) );
1271 }
1272 else /* mixed odd hyperbola or an infinite bound */
1273 assert((exponent < 0.0 && !even && mixedsign) || SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub));
1274 }
1275
1276 if( overestimate )
1277 {
1278 if( convex && !SCIPisInfinity(scip, -lb) && !SCIPisInfinity(scip, ub) )
1279 refpointsover[0] = (lb + ub) / 2.0;
1280 else if( concave )
1281 addTangentRefpoints(scip, exponent, lb, ub, refpointsover);
1282 else if( exponent > 1.0 && !even && mixedsign ) /* mixed signpower */
1283 {
1284 SCIP_CALL( addSignpowerRefpoints(scip, exprdata, lb, ub, exponent, FALSE, refpointsover) );
1285 }
1286 else /* mixed hyperbola or an infinite bound */
1287 assert((exponent < 0.0 && mixedsign) || SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub));
1288 }
1289
1290 return SCIP_OKAY;
1291}
1292
1293
1294/*
1295 * Callback methods of expression handler
1296 */
1297
1298/** compares two power expressions
1299 *
1300 * the order of two power (normal or signed) is base_1^expo_1 < base_2^expo_2 if and only if
1301 * base_1 < base2 or, base_1 = base_2 and expo_1 < expo_2
1302 */
1303static
1305{ /*lint --e{715}*/
1306 SCIP_Real expo1;
1307 SCIP_Real expo2;
1308 int compareresult;
1309
1310 /**! [SnippetExprComparePow] */
1311 compareresult = SCIPcompareExpr(scip, SCIPexprGetChildren(expr1)[0], SCIPexprGetChildren(expr2)[0]);
1312 if( compareresult != 0 )
1313 return compareresult;
1314
1315 expo1 = SCIPgetExponentExprPow(expr1);
1316 expo2 = SCIPgetExponentExprPow(expr2);
1317
1318 return expo1 == expo2 ? 0 : expo1 < expo2 ? -1 : 1;
1319 /**! [SnippetExprComparePow] */
1320}
1321
1322/** simplifies a pow expression
1323 *
1324 * Evaluates the power function when its child is a value expression
1325 */
1326static
1328{ /*lint --e{715}*/
1329 SCIP_EXPRHDLR* exprhdlr;
1330 SCIP_EXPRHDLRDATA* exprhdlrdata;
1331 SCIP_EXPR* base;
1332 SCIP_Real exponent;
1333
1334 assert(scip != NULL);
1335 assert(expr != NULL);
1336 assert(simplifiedexpr != NULL);
1337 assert(SCIPexprGetNChildren(expr) == 1);
1338
1339 exprhdlr = SCIPexprGetHdlr(expr);
1340 assert(exprhdlr != NULL);
1341
1342 exprhdlrdata = SCIPexprhdlrGetData(exprhdlr);
1343 assert(exprhdlrdata != NULL);
1344
1345 base = SCIPexprGetChildren(expr)[0];
1346 assert(base != NULL);
1347
1348 exponent = SCIPgetExponentExprPow(expr);
1349
1350 SCIPdebugPrintf("[simplifyPow] simplifying power with expo %g\n", exponent);
1351
1352 /* enforces POW1 */
1353 if( exponent == 0.0 )
1354 {
1355 SCIPdebugPrintf("[simplifyPow] POW1\n");
1356 /* TODO: more checks? */
1357 assert(!SCIPisExprValue(scip, base) || SCIPgetValueExprValue(base) != 0.0);
1358 SCIP_CALL( SCIPcreateExprValue(scip, simplifiedexpr, 1.0, ownercreate, ownercreatedata) );
1359 return SCIP_OKAY;
1360 }
1361
1362 /* enforces POW2 */
1363 if( exponent == 1.0 )
1364 {
1365 SCIPdebugPrintf("[simplifyPow] POW2\n");
1366 *simplifiedexpr = base;
1367 SCIPcaptureExpr(*simplifiedexpr);
1368 return SCIP_OKAY;
1369 }
1370
1371 /* enforces POW3 */
1372 if( SCIPisExprValue(scip, base) )
1373 {
1374 SCIP_Real baseval;
1375
1376 SCIPdebugPrintf("[simplifyPow] POW3\n");
1377 baseval = SCIPgetValueExprValue(base);
1378
1379 /* the assert below was failing on st_e35 for baseval=-1e-15 and fractional exponent
1380 * in the subNLP heuristic; I assume that this was because baseval was evaluated after
1381 * variable fixings and that there were just floating-point inaccuracies and 0 was meant,
1382 * so I treat -1e-15 as 0 here
1383 */
1384 if( baseval < 0.0 && fmod(exponent, 1.0) != 0.0 && baseval > -SCIPepsilon(scip) )
1385 baseval = 0.0;
1386
1387 /* TODO check if those are all important asserts */
1388 assert(baseval >= 0.0 || fmod(exponent, 1.0) == 0.0);
1389 assert(baseval != 0.0 || exponent != 0.0);
1390
1391 if( baseval != 0.0 || exponent > 0.0 )
1392 {
1393 SCIP_CALL( SCIPcreateExprValue(scip, simplifiedexpr, pow(baseval, exponent), ownercreate, ownercreatedata) );
1394 return SCIP_OKAY;
1395 }
1396 }
1397
1398 /* enforces POW11 (exp(x)^n = exp(n*x)) */
1399 if( SCIPisExprExp(scip, base) )
1400 {
1401 SCIP_EXPR* child;
1402 SCIP_EXPR* prod;
1403 SCIP_EXPR* exponential;
1404 SCIP_EXPR* simplifiedprod;
1405
1406 SCIPdebugPrintf("[simplifyPow] POW11\n");
1407 child = SCIPexprGetChildren(base)[0];
1408
1409 /* multiply child of exponential with exponent */
1410 SCIP_CALL( SCIPcreateExprProduct(scip, &prod, 1, &child, exponent, ownercreate, ownercreatedata) );
1411
1412 /* simplify product */
1413 SCIP_CALL( SCIPcallExprSimplify(scip, prod, &simplifiedprod, ownercreate, ownercreatedata) );
1414 SCIP_CALL( SCIPreleaseExpr(scip, &prod) );
1415
1416 /* create exponential with new child */
1417 SCIP_CALL( SCIPcreateExprExp(scip, &exponential, simplifiedprod, ownercreate, ownercreatedata) );
1418 SCIP_CALL( SCIPreleaseExpr(scip, &simplifiedprod) );
1419
1420 /* the final simplified expression is the simplification of the just created exponential */
1421 SCIP_CALL( SCIPcallExprSimplify(scip, exponential, simplifiedexpr, ownercreate, ownercreatedata) );
1422 SCIP_CALL( SCIPreleaseExpr(scip, &exponential) );
1423
1424 return SCIP_OKAY;
1425 }
1426
1427 /* enforces POW10 */
1428 if( SCIPisExprVar(scip, base) )
1429 {
1430 SCIP_VAR* basevar;
1431
1432 SCIPdebugPrintf("[simplifyPow] POW10\n");
1433 basevar = SCIPgetVarExprVar(base);
1434
1435 assert(basevar != NULL);
1436
1437 /* TODO: if exponent is negative, we could fix the binary variable to 1. However, this is a bit tricky because
1438 * variables can not be tighten in EXITPRE, where the simplify is also called
1439 */
1440 if( SCIPvarIsBinary(basevar) && exponent > 0.0 )
1441 {
1442 *simplifiedexpr = base;
1443 SCIPcaptureExpr(*simplifiedexpr);
1444 return SCIP_OKAY;
1445 }
1446 }
1447
1448 if( EPSISINT(exponent, 0.0) )
1449 {
1450 SCIP_EXPR* aux;
1451 SCIP_EXPR* simplifiedaux;
1452
1453 /* enforces POW12 (abs(x)^n = x^n if n is even) */
1454 if( SCIPisExprAbs(scip, base) && (int)exponent % 2 == 0 )
1455 {
1456 SCIP_EXPR* newpow;
1457
1458 SCIPdebugPrintf("[simplifyPow] POWXX\n");
1459
1460 SCIP_CALL( SCIPcreateExprPow(scip, &newpow, SCIPexprGetChildren(base)[0], exponent, ownercreate, ownercreatedata) );
1461 SCIP_CALL( simplifyPow(scip, newpow, simplifiedexpr, ownercreate, ownercreatedata) );
1462 SCIP_CALL( SCIPreleaseExpr(scip, &newpow) );
1463
1464 return SCIP_OKAY;
1465 }
1466
1467 /* enforces POW5
1468 * given (pow n (prod 1.0 expr_1 ... expr_k)) we distribute the exponent:
1469 * -> (prod 1.0 (pow n expr_1) ... (pow n expr_k))
1470 * notes: - since base is simplified and its coefficient is 1.0 (SP8)
1471 * - n is an integer (excluding 1 and 0; see POW1-2 above)
1472 */
1473 if( SCIPisExprProduct(scip, base) )
1474 {
1475 SCIP_EXPR* auxproduct;
1476 int i;
1477
1478 /* create empty product */
1479 SCIP_CALL( SCIPcreateExprProduct(scip, &auxproduct, 0, NULL, 1.0, ownercreate, ownercreatedata) );
1480
1481 for( i = 0; i < SCIPexprGetNChildren(base); ++i )
1482 {
1483 /* create (pow n expr_i) and simplify */
1484 SCIP_CALL( SCIPcreateExprPow(scip, &aux, SCIPexprGetChildren(base)[i], exponent, ownercreate, ownercreatedata) );
1485 SCIP_CALL( simplifyPow(scip, aux, &simplifiedaux, ownercreate, ownercreatedata) );
1486 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
1487
1488 /* append (pow n expr_i) to product */
1489 SCIP_CALL( SCIPappendExprChild(scip, auxproduct, simplifiedaux) );
1490 SCIP_CALL( SCIPreleaseExpr(scip, &simplifiedaux) );
1491 }
1492
1493 /* simplify (prod 1.0 (pow n expr_1) ... (pow n expr_k))
1494 * this calls simplifyProduct directly, since we know its children are simplified */
1495 SCIP_CALL( SCIPcallExprSimplify(scip, auxproduct, simplifiedexpr, ownercreate, ownercreatedata) );
1496 SCIP_CALL( SCIPreleaseExpr(scip, &auxproduct) );
1497 return SCIP_OKAY;
1498 }
1499
1500 /* enforces POW6
1501 * given (pow n (sum 0.0 coef expr)) we can move `pow` inside `sum`:
1502 * (pow n (sum 0.0 coef expr) ) -> (sum 0.0 coef^n (pow n expr))
1503 * notes: - since base is simplified and its constant is 0, then coef != 1.0 (SS7)
1504 * - n is an integer (excluding 1 and 0; see POW1-2 above)
1505 */
1506 if( SCIPisExprSum(scip, base) && SCIPexprGetNChildren(base) == 1 && SCIPgetConstantExprSum(base) == 0.0 )
1507 {
1508 SCIP_Real newcoef;
1509
1510 SCIPdebugPrintf("[simplifyPow] seeing a sum with one term, exponent %g\n", exponent);
1511
1512 /* assert SS7 holds */
1513 assert(SCIPgetCoefsExprSum(base)[0] != 1.0);
1514
1515 /* create (pow n expr) and simplify it
1516 * note: we call simplifyPow directly, since we know that `expr` is simplified */
1517 newcoef = pow(SCIPgetCoefsExprSum(base)[0], exponent);
1518 SCIP_CALL( SCIPcreateExprPow(scip, &aux, SCIPexprGetChildren(base)[0], exponent, ownercreate, ownercreatedata) );
1519 SCIP_CALL( simplifyPow(scip, aux, &simplifiedaux, ownercreate, ownercreatedata) );
1520 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
1521
1522 /* create (sum (pow n expr)) and simplify it
1523 * this calls simplifySum directly, since we know its children are simplified */
1524 SCIP_CALL( SCIPcreateExprSum(scip, &aux, 1, &simplifiedaux, &newcoef, 0.0, ownercreate, ownercreatedata) );
1525 SCIP_CALL( SCIPcallExprSimplify(scip, aux, simplifiedexpr, ownercreate, ownercreatedata) );
1526 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
1527 SCIP_CALL( SCIPreleaseExpr(scip, &simplifiedaux) );
1528 return SCIP_OKAY;
1529 }
1530
1531 /* enforces POW7 for exponent 2
1532 * (const + sum alpha_i expr_i)^2 = sum alpha_i^2 expr_i^2
1533 * + sum_{j < i} 2*alpha_i alpha_j expr_i expr_j
1534 * + sum const alpha_i expr_i
1535 * TODO: put some limits on the number of children of the sum being expanded
1536 */
1537 if( SCIPisExprSum(scip, base) && exponent == 2.0 && exprhdlrdata->expandmaxexponent >= 2 )
1538 {
1539 int i;
1540 int nchildren;
1541 int nexpandedchildren;
1542 SCIP_EXPR* expansion;
1543 SCIP_EXPR** expandedchildren;
1544 SCIP_Real* coefs;
1545 SCIP_Real constant;
1546
1547 SCIPdebugPrintf("[simplifyPow] expanding sum^%g\n", exponent);
1548
1549 nchildren = SCIPexprGetNChildren(base);
1550 nexpandedchildren = nchildren * (nchildren + 1) / 2 + nchildren;
1551 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nexpandedchildren) );
1552 SCIP_CALL( SCIPallocBufferArray(scip, &expandedchildren, nexpandedchildren) );
1553
1554 for( i = 0; i < nchildren; ++i )
1555 {
1556 int j;
1557 SCIP_EXPR* expansionchild;
1558 SCIP_EXPR* prodchildren[2];
1559 prodchildren[0] = SCIPexprGetChildren(base)[i];
1560
1561 /* create and simplify expr_i * expr_j */
1562 for( j = 0; j < i; ++j )
1563 {
1564 prodchildren[1] = SCIPexprGetChildren(base)[j];
1565 coefs[i*(i+1)/2 + j] = 2 * SCIPgetCoefsExprSum(base)[i] * SCIPgetCoefsExprSum(base)[j];
1566
1567 SCIP_CALL( SCIPcreateExprProduct(scip, &expansionchild, 2, prodchildren, 1.0, ownercreate,
1568 ownercreatedata) );
1569 SCIP_CALL( SCIPcallExprSimplify(scip, expansionchild, &expandedchildren[i*(i+1)/2 + j],
1570 ownercreate, ownercreatedata) ); /* this calls simplifyProduct */
1571 SCIP_CALL( SCIPreleaseExpr(scip, &expansionchild) );
1572 }
1573 /* create and simplify expr_i * expr_i */
1574 prodchildren[1] = SCIPexprGetChildren(base)[i];
1575 coefs[i*(i+1)/2 + i] = SCIPgetCoefsExprSum(base)[i] * SCIPgetCoefsExprSum(base)[i];
1576
1577 SCIP_CALL( SCIPcreateExprProduct(scip, &expansionchild, 2, prodchildren, 1.0, ownercreate,
1578 ownercreatedata) );
1579 SCIP_CALL( SCIPcallExprSimplify(scip, expansionchild, &expandedchildren[i*(i+1)/2 + i], ownercreate,
1580 ownercreatedata) ); /* this calls simplifyProduct */
1581 SCIP_CALL( SCIPreleaseExpr(scip, &expansionchild) );
1582 }
1583 /* create const * alpha_i expr_i */
1584 for( i = 0; i < nchildren; ++i )
1585 {
1586 coefs[i + nexpandedchildren - nchildren] = 2 * SCIPgetConstantExprSum(base) * SCIPgetCoefsExprSum(base)[i];
1587 expandedchildren[i + nexpandedchildren - nchildren] = SCIPexprGetChildren(base)[i];
1588 }
1589
1590 constant = SCIPgetConstantExprSum(base);
1591 constant *= constant;
1592 /* create sum of all the above and simplify it with simplifySum since all of its children are simplified! */
1593 SCIP_CALL( SCIPcreateExprSum(scip, &expansion, nexpandedchildren, expandedchildren, coefs, constant,
1594 ownercreate, ownercreatedata) );
1595 SCIP_CALL( SCIPcallExprSimplify(scip, expansion, simplifiedexpr, ownercreate,
1596 ownercreatedata) ); /* this calls simplifySum */
1597
1598 /* release everything */
1599 SCIP_CALL( SCIPreleaseExpr(scip, &expansion) );
1600 /* release the *created* expanded children */
1601 for( i = 0; i < nexpandedchildren - nchildren; ++i )
1602 {
1603 SCIP_CALL( SCIPreleaseExpr(scip, &expandedchildren[i]) );
1604 }
1605 SCIPfreeBufferArray(scip, &expandedchildren);
1606 SCIPfreeBufferArray(scip, &coefs);
1607
1608 return SCIP_OKAY;
1609 }
1610
1611 /* enforces POW7 for exponent > 2 */
1612 if( SCIPisExprSum(scip, base) && exponent > 2.0 && exponent <= exprhdlrdata->expandmaxexponent )
1613 {
1614 SCIPdebugPrintf("[simplifyPow] expanding sum^%g\n", exponent);
1615
1616 SCIP_CALL( SCIPpowerExprSum(scip, simplifiedexpr, base, (int)exponent, TRUE, ownercreate, ownercreatedata) );
1617
1618 return SCIP_OKAY;
1619 }
1620 }
1621 else
1622 {
1623 /* enforces POW9
1624 *
1625 * FIXME code of POW6 is very similar
1626 */
1627 if( SCIPexprGetNChildren(base) == 1
1628 && SCIPisExprSum(scip, base)
1629 && SCIPgetConstantExprSum(base) == 0.0
1630 && SCIPgetCoefsExprSum(base)[0] >= 0.0 )
1631 {
1632 SCIP_EXPR* simplifiedaux;
1633 SCIP_EXPR* aux;
1634 SCIP_Real newcoef;
1635
1636 SCIPdebugPrintf("[simplifyPow] seeing a sum with one term, exponent %g\n", exponent);
1637 /* assert SS7 holds */
1638 assert(SCIPgetCoefsExprSum(base)[0] != 1.0);
1639
1640 /* create (pow n expr) and simplify it
1641 * note: we call simplifyPow directly, since we know that `expr` is simplified */
1642 SCIP_CALL( SCIPcreateExprPow(scip, &aux, SCIPexprGetChildren(base)[0], exponent, ownercreate,
1643 ownercreatedata) );
1644 SCIP_CALL( simplifyPow(scip, aux, &simplifiedaux, ownercreate, ownercreatedata) );
1645 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
1646
1647 /* create (sum (pow n expr)) and simplify it
1648 * this calls simplifySum directly, since we know its child is simplified! */
1649 newcoef = pow(SCIPgetCoefsExprSum(base)[0], exponent);
1650 SCIP_CALL( SCIPcreateExprSum(scip, &aux, 1, &simplifiedaux, &newcoef, 0.0, ownercreate,
1651 ownercreatedata) );
1652 SCIP_CALL( SCIPcallExprSimplify(scip, aux, simplifiedexpr, ownercreate, ownercreatedata) );
1653 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
1654 SCIP_CALL( SCIPreleaseExpr(scip, &simplifiedaux) );
1655
1656 return SCIP_OKAY;
1657 }
1658
1659 /* enforces POW5a
1660 * given (pow n (prod 1.0 expr_1 ... expr_k)) we distribute the exponent:
1661 * -> (prod 1.0 (pow n expr_1) ... (pow n expr_k))
1662 * notes: - since base is simplified and its coefficient is 1.0 (SP8)
1663 * TODO we can enable this more often by default when simplify makes use of bounds on factors
1664 */
1665 if( exprhdlrdata->distribfracexponent && SCIPisExprProduct(scip, base) )
1666 {
1667 SCIP_EXPR* aux;
1668 SCIP_EXPR* simplifiedaux;
1669 SCIP_EXPR* auxproduct;
1670 int i;
1671
1672 /* create empty product */
1673 SCIP_CALL( SCIPcreateExprProduct(scip, &auxproduct, 0, NULL, 1.0, ownercreate, ownercreatedata) );
1674
1675 for( i = 0; i < SCIPexprGetNChildren(base); ++i )
1676 {
1677 /* create (pow n expr_i) and simplify */
1678 SCIP_CALL( SCIPcreateExprPow(scip, &aux, SCIPexprGetChildren(base)[i], exponent, ownercreate, ownercreatedata) );
1679 SCIP_CALL( simplifyPow(scip, aux, &simplifiedaux, ownercreate, ownercreatedata) );
1680 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
1681
1682 /* append (pow n expr_i) to product */
1683 SCIP_CALL( SCIPappendExprChild(scip, auxproduct, simplifiedaux) );
1684 SCIP_CALL( SCIPreleaseExpr(scip, &simplifiedaux) );
1685 }
1686
1687 /* simplify (prod 1.0 (pow n expr_1) ... (pow n expr_k))
1688 * this calls simplifyProduct directly, since we know its children are simplified */
1689 SCIP_CALL( SCIPcallExprSimplify(scip, auxproduct, simplifiedexpr, ownercreate, ownercreatedata) );
1690 SCIP_CALL( SCIPreleaseExpr(scip, &auxproduct) );
1691 return SCIP_OKAY;
1692 }
1693 }
1694
1695 /* enforces POW8
1696 * given (pow n (pow expo expr)) we distribute the exponent:
1697 * -> (pow n*expo expr)
1698 * notes: n is not 1 or 0, see POW1-2 above
1699 */
1700 if( SCIPisExprPower(scip, base) )
1701 {
1702 SCIP_Real newexponent;
1703 SCIP_Real baseexponent;
1704
1705 baseexponent = SCIPgetExponentExprPow(base);
1706 newexponent = baseexponent * exponent;
1707
1708 /* some checks (see POW8 definition in scip_expr.h) to make sure we don't loose an
1709 * implicit SCIPexprGetChildren(base)[0] >= 0 constraint
1710 *
1711 * if newexponent is fractional, then we will still need expr >= 0
1712 * if both exponents were integer, then we never required and will not require expr >= 0
1713 * if base exponent was an even integer, then we did not require expr >= 0
1714 * (but may need to use |expr|^newexponent)
1715 */
1716 if( !EPSISINT(newexponent, 0.0) ||
1717 (EPSISINT(baseexponent, 0.0) && EPSISINT(exponent, 0.0)) ||
1718 (EPSISINT(baseexponent, 0.0) && ((int)baseexponent) % 2 == 0) )
1719 {
1720 SCIP_EXPR* aux;
1721
1722 if( EPSISINT(baseexponent, 0.0) && ((int)baseexponent) % 2 == 0 &&
1723 (!EPSISINT(newexponent, 0.0) || ((int)newexponent) % 2 == 1) )
1724 {
1725 /* If base exponent was even integer and new exponent will be fractional,
1726 * then simplify to |expr|^newexponent to allow eval for expr < 0.
1727 * If base exponent was even integer and new exponent will be odd integer,
1728 * then simplify to |expr|^newexponent to preserve value for expr < 0.
1729 */
1730 SCIP_EXPR* simplifiedaux;
1731
1732 SCIP_CALL( SCIPcreateExprAbs(scip, &aux, SCIPexprGetChildren(base)[0], ownercreate, ownercreatedata) );
1733 SCIP_CALL( SCIPcallExprSimplify(scip, aux, &simplifiedaux, ownercreate, ownercreatedata) );
1734 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
1735 SCIP_CALL( SCIPcreateExprPow(scip, &aux, simplifiedaux, newexponent, ownercreate, ownercreatedata) );
1736 SCIP_CALL( SCIPreleaseExpr(scip, &simplifiedaux) );
1737 }
1738 else
1739 {
1740 SCIP_CALL( SCIPcreateExprPow(scip, &aux, SCIPexprGetChildren(base)[0], newexponent, ownercreate,
1741 ownercreatedata) );
1742 }
1743
1744 SCIP_CALL( simplifyPow(scip, aux, simplifiedexpr, ownercreate, ownercreatedata) );
1745 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
1746
1747 return SCIP_OKAY;
1748 }
1749 }
1750
1751 SCIPdebugPrintf("[simplifyPow] power is simplified\n");
1752 *simplifiedexpr = expr;
1753
1754 /* we have to capture it, since it must simulate a "normal" simplified call in which a new expression is created */
1755 SCIPcaptureExpr(*simplifiedexpr);
1756
1757 return SCIP_OKAY;
1758}
1759
1760/** expression callback to get information for symmetry detection */
1761static
1763{ /*lint --e{715}*/
1764 SCIP_EXPRDATA* exprdata;
1765
1766 assert(scip != NULL);
1767 assert(expr != NULL);
1768
1769 exprdata = SCIPexprGetData(expr);
1770 assert(exprdata != NULL);
1771
1772 SCIP_CALL( SCIPallocBlockMemory(scip, symdata) );
1773
1774 (*symdata)->nconstants = 1;
1775 (*symdata)->ncoefficients = 0;
1776
1777 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*symdata)->constants, 1) );
1778 (*symdata)->constants[0] = exprdata->exponent;
1779
1780 return SCIP_OKAY;
1781}
1782
1783/** expression handler copy callback */
1784static
1786{ /*lint --e{715}*/
1788
1789 return SCIP_OKAY;
1790}
1791
1792/** expression handler free callback */
1793static
1795{ /*lint --e{715}*/
1796 assert(exprhdlrdata != NULL);
1797 assert(*exprhdlrdata != NULL);
1798
1799 SCIPfreeBlockMemory(scip, exprhdlrdata);
1800
1801 return SCIP_OKAY;
1802}
1803
1804/** expression data copy callback */
1805static
1807{ /*lint --e{715}*/
1808 SCIP_EXPRDATA* sourceexprdata;
1809
1810 assert(targetexprdata != NULL);
1811 assert(sourceexpr != NULL);
1812
1813 sourceexprdata = SCIPexprGetData(sourceexpr);
1814 assert(sourceexprdata != NULL);
1815
1816 *targetexprdata = NULL;
1817
1818 SCIP_CALL( createData(targetscip, targetexprdata, sourceexprdata->exponent) );
1819
1820 return SCIP_OKAY;
1821}
1822
1823/** expression data free callback */
1824static
1826{ /*lint --e{715}*/
1827 SCIP_EXPRDATA* exprdata;
1828
1829 assert(expr != NULL);
1830
1831 exprdata = SCIPexprGetData(expr);
1832 assert(exprdata != NULL);
1833
1834 SCIPfreeBlockMemory(scip, &exprdata);
1835 SCIPexprSetData(expr, NULL);
1836
1837 return SCIP_OKAY;
1838}
1839
1840/** expression print callback */
1841/** @todo: use precedence for better printing */
1842static
1844{ /*lint --e{715}*/
1845 assert(expr != NULL);
1846
1847 /**! [SnippetExprPrintPow] */
1848 switch( stage )
1849 {
1851 {
1852 /* print function with opening parenthesis */
1853 SCIPinfoMessage(scip, file, "(");
1854 break;
1855 }
1856
1858 {
1859 assert(currentchild == 0);
1860 break;
1861 }
1862
1864 {
1865 SCIP_Real exponent = SCIPgetExponentExprPow(expr);
1866
1867 /* print closing parenthesis */
1868 if( exponent >= 0.0 )
1869 SCIPinfoMessage(scip, file, ")^%.15g", exponent);
1870 else
1871 SCIPinfoMessage(scip, file, ")^(%.15g)", exponent);
1872
1873 break;
1874 }
1875
1877 default:
1878 break;
1879 }
1880 /**! [SnippetExprPrintPow] */
1881
1882 return SCIP_OKAY;
1883}
1884
1885/** expression point evaluation callback */
1886static
1888{ /*lint --e{715}*/
1889 SCIP_Real exponent;
1890 SCIP_Real base;
1891
1892 assert(expr != NULL);
1893 assert(SCIPexprGetNChildren(expr) == 1);
1895
1896 exponent = SCIPgetExponentExprPow(expr);
1898
1899 *val = pow(base, exponent);
1900
1901 /* if there is a domain, pole, or range error, pow() should return some kind of NaN, infinity, or HUGE_VAL
1902 * we could also work with floating point exceptions or errno, but I am not sure this would be thread-safe
1903 */
1904 if( !SCIPisFinite(*val) || *val == HUGE_VAL || *val == -HUGE_VAL )
1905 *val = SCIP_INVALID;
1906
1907 return SCIP_OKAY;
1908}
1909
1910/** derivative evaluation callback
1911 *
1912 * computes <gradient, children.dot>
1913 * if expr is child^p, then computes
1914 * p child^(p-1) dot(child)
1915 */
1916static
1918{ /*lint --e{715}*/
1919 SCIP_EXPR* child;
1920 SCIP_Real exponent;
1921
1922 assert(expr != NULL);
1923 assert(SCIPexprGetData(expr) != NULL);
1924 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
1925
1926 child = SCIPexprGetChildren(expr)[0];
1927 assert(child != NULL);
1928 assert(!SCIPisExprValue(scip, child));
1929 assert(SCIPexprGetDot(child) != SCIP_INVALID);
1930
1931 exponent = SCIPgetExponentExprPow(expr);
1932 assert(exponent != 0.0);
1933
1934 /* x^exponent is not differentiable for x = 0 and exponent in ]0,1[ */
1935 if( exponent > 0.0 && exponent < 1.0 && SCIPexprGetEvalValue(child) == 0.0 )
1936 *dot = SCIP_INVALID;
1937 else
1938 *dot = exponent * pow(SCIPexprGetEvalValue(child), exponent - 1.0) * SCIPexprGetDot(child);
1939
1940 return SCIP_OKAY;
1941}
1942
1943/** expression backward forward derivative evaluation callback
1944 *
1945 * computes partial/partial child ( <gradient, children.dot> )
1946 * if expr is child^n, then computes
1947 * n * (n - 1) child^(n-2) dot(child)
1948 */
1949static
1951{ /*lint --e{715}*/
1952 SCIP_EXPR* child;
1953 SCIP_Real exponent;
1954
1955 assert(expr != NULL);
1956 assert(SCIPexprGetData(expr) != NULL);
1957 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
1958 assert(childidx == 0);
1959
1960 child = SCIPexprGetChildren(expr)[0];
1961 assert(child != NULL);
1962 assert(!SCIPisExprValue(scip, child));
1963 assert(SCIPexprGetDot(child) != SCIP_INVALID);
1964
1965 exponent = SCIPgetExponentExprPow(expr);
1966 assert(exponent != 0.0);
1967
1968 /* x^exponent is not twice differentiable for x = 0 and exponent in ]0,1[ u ]1,2[ */
1969 if( exponent > 0.0 && exponent < 2.0 && SCIPexprGetEvalValue(child) == 0.0 && exponent != 1.0 )
1970 *bardot = SCIP_INVALID;
1971 else
1972 *bardot = exponent * (exponent - 1.0) * pow(SCIPexprGetEvalValue(child), exponent - 2.0) * SCIPexprGetDot(child);
1973
1974 return SCIP_OKAY;
1975}
1976
1977/** expression derivative evaluation callback */
1978static
1980{ /*lint --e{715}*/
1981 SCIP_EXPR* child;
1982 SCIP_Real childval;
1983 SCIP_Real exponent;
1984
1985 assert(expr != NULL);
1986 assert(SCIPexprGetData(expr) != NULL);
1987 assert(childidx == 0);
1988
1989 child = SCIPexprGetChildren(expr)[0];
1990 assert(child != NULL);
1991 assert(!SCIPisExprValue(scip, child));
1992
1993 childval = SCIPexprGetEvalValue(child);
1994 assert(childval != SCIP_INVALID);
1995
1996 exponent = SCIPgetExponentExprPow(expr);
1997 assert(exponent != 0.0);
1998
1999 /* x^exponent is not differentiable for x = 0 and exponent in ]0,1[ */
2000 if( exponent > 0.0 && exponent < 1.0 && childval == 0.0 )
2001 *val = SCIP_INVALID;
2002 else
2003 *val = exponent * pow(childval, exponent - 1.0);
2004
2005 return SCIP_OKAY;
2006}
2007
2008/** expression interval evaluation callback */
2009static
2011{ /*lint --e{715}*/
2012 SCIP_INTERVAL childinterval;
2013 SCIP_Real exponent;
2014
2015 assert(expr != NULL);
2016 assert(SCIPexprGetNChildren(expr) == 1);
2017
2018 childinterval = SCIPexprGetActivity(SCIPexprGetChildren(expr)[0]);
2019
2020 exponent = SCIPgetExponentExprPow(expr);
2021
2022 if( exponent < 0.0 )
2023 {
2024 SCIP_EXPRHDLRDATA* exprhdlrdata;
2025 exprhdlrdata = SCIPexprhdlrGetData(SCIPexprGetHdlr(expr));
2026 assert(exprhdlrdata != NULL);
2027
2028 if( exprhdlrdata->minzerodistance > 0.0 )
2029 {
2030 /* avoid small interval around 0 if possible, see also reversepropPow */
2031 if( childinterval.inf > -exprhdlrdata->minzerodistance && childinterval.inf < exprhdlrdata->minzerodistance )
2032 {
2033 if( !exprhdlrdata->warnedonpole && SCIPgetVerbLevel(scip) > SCIP_VERBLEVEL_NONE )
2034 {
2035 SCIPinfoMessage(scip, NULL, "Changing lower bound for child of pow(.,%g) from %g to %g.\n"
2036 "Check your model formulation or use option expr/" POWEXPRHDLR_NAME "/minzerodistance to avoid this warning.\n",
2037 exponent, childinterval.inf, exprhdlrdata->minzerodistance);
2038 SCIPinfoMessage(scip, NULL, "Expression: ");
2039 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2040 SCIPinfoMessage(scip, NULL, "\n");
2041 exprhdlrdata->warnedonpole = TRUE;
2042 }
2043 childinterval.inf = exprhdlrdata->minzerodistance;
2044 }
2045 else if( childinterval.sup < exprhdlrdata->minzerodistance
2046 && childinterval.sup > -exprhdlrdata->minzerodistance )
2047 {
2048 if( !exprhdlrdata->warnedonpole && SCIPgetVerbLevel(scip) > SCIP_VERBLEVEL_NONE )
2049 {
2050 SCIPinfoMessage(scip, NULL, "Changing upper bound for child of pow(.,%g) from %g to %g.\n"
2051 "Check your model formulation or use option expr/" POWEXPRHDLR_NAME "/minzerodistance to avoid this warning.\n",
2052 exponent, childinterval.sup, -exprhdlrdata->minzerodistance);
2053 SCIPinfoMessage(scip, NULL, "Expression: ");
2054 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2055 SCIPinfoMessage(scip, NULL, "\n");
2056 exprhdlrdata->warnedonpole = TRUE;
2057 }
2058 childinterval.sup = -exprhdlrdata->minzerodistance;
2059 }
2060 }
2061 }
2062
2063 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, childinterval) )
2064 {
2065 SCIPintervalSetEmpty(interval);
2066 return SCIP_OKAY;
2067 }
2068
2069 SCIPintervalPowerScalar(SCIP_INTERVAL_INFINITY, interval, childinterval, exponent);
2070
2071 /* make sure 0^negative is an empty interval, as some other codes do not handle intervals like [inf,inf] well
2072 * TODO maybe change SCIPintervalPowerScalar?
2073 */
2074 if( exponent < 0.0 && childinterval.inf == 0.0 && childinterval.sup == 0.0 )
2075 SCIPintervalSetEmpty(interval);
2076
2077 return SCIP_OKAY;
2078}
2079
2080/** expression estimator callback */
2081static
2083{ /*lint --e{715}*/
2084 SCIP_EXPRDATA* exprdata;
2085 SCIP_EXPR* child;
2086 SCIP_Real childlb;
2087 SCIP_Real childub;
2088 SCIP_Real exponent;
2089 SCIP_Bool isinteger;
2090
2091 assert(scip != NULL);
2092 assert(expr != NULL);
2093 assert(SCIPexprGetNChildren(expr) == 1);
2094 assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), POWEXPRHDLR_NAME) == 0);
2095 assert(refpoint != NULL);
2096 assert(coefs != NULL);
2097 assert(constant != NULL);
2098 assert(islocal != NULL);
2099 assert(branchcand != NULL);
2100 assert(*branchcand == TRUE); /* the default */
2101 assert(success != NULL);
2102
2103 *success = FALSE;
2104
2105 /* get aux variables: we over- or underestimate childvar^exponent */
2106 child = SCIPexprGetChildren(expr)[0];
2107 assert(child != NULL);
2108
2109 SCIPdebugMsg(scip, "%sestimation of x^%g at x=%.15g\n",
2110 overestimate ? "over" : "under", SCIPgetExponentExprPow(expr), *refpoint);
2111
2112 /* we can not generate a cut at +/- infinity */
2113 if( SCIPisInfinity(scip, REALABS(*refpoint)) )
2114 return SCIP_OKAY;
2115
2116 childlb = localbounds[0].inf;
2117 childub = localbounds[0].sup;
2118
2119 exprdata = SCIPexprGetData(expr);
2120 exponent = exprdata->exponent;
2121 assert(exponent != 1.0 && exponent != 0.0); /* this should have been simplified */
2122
2123 /* if child is constant, then return a constant estimator
2124 * this can help with small infeasibilities if boundtightening is relaxing bounds too much
2125 */
2126 if( childlb == childub )
2127 {
2128 *coefs = 0.0;
2129 *constant = pow(childlb, exponent);
2130 *success = TRUE;
2131 *islocal = globalbounds[0].inf != globalbounds[0].sup;
2132 *branchcand = FALSE;
2133 return SCIP_OKAY;
2134 }
2135
2136 isinteger = EPSISINT(exponent, 0.0);
2137
2138 /* if exponent is not integral, then child must be non-negative */
2139 if( !isinteger && childlb < 0.0 )
2140 {
2141 /* somewhere we should have tightened the bound on x, but small tightening are not always applied by SCIP
2142 * it is ok to do this tightening here, but let's assert that we were close to 0.0 already
2143 */
2144 assert(SCIPisFeasZero(scip, childlb));
2145 childlb = 0.0;
2146 }
2147 assert(isinteger || childlb >= 0.0);
2148
2149 SCIP_CALL( buildPowEstimator(scip, exprdata, overestimate, childlb, childub, globalbounds[0].inf,
2150 globalbounds[0].sup, SCIPexprIsIntegral(child), MAX(childlb, *refpoint), exponent, coefs,
2151 constant, success, islocal, branchcand) );
2152
2153 return SCIP_OKAY;
2154}
2155
2156/** expression reverse propagaton callback */
2157static
2159{ /*lint --e{715}*/
2160 SCIP_INTERVAL child;
2161 SCIP_INTERVAL interval;
2162 SCIP_Real exponent;
2163
2164 assert(scip != NULL);
2165 assert(expr != NULL);
2166 assert(SCIPexprGetNChildren(expr) == 1);
2167
2168 exponent = SCIPgetExponentExprPow(expr);
2169 child = childrenbounds[0];
2170
2171 SCIPdebugMsg(scip, "reverseprop x^%g in [%.15g,%.15g], x = [%.15g,%.15g]", exponent, bounds.inf, bounds.sup,
2172 child.inf, child.sup);
2173
2175 {
2176 *infeasible = TRUE;
2177 return SCIP_OKAY;
2178 }
2179
2181 {
2182 /* if exponent is not integral, then make sure that child is non-negative */
2183 if( !EPSISINT(exponent, 0.0) && child.inf < 0.0 )
2184 {
2185 SCIPintervalSetBounds(&interval, 0.0, child.sup);
2186 }
2187 else
2188 {
2189 SCIPdebugMsgPrint(scip, "-> no improvement\n");
2190 return SCIP_OKAY;
2191 }
2192 }
2193 else
2194 {
2195 /* f = pow(c0, alpha) -> c0 = pow(f, 1/alpha) */
2196 SCIPintervalPowerScalarInverse(SCIP_INTERVAL_INFINITY, &interval, child, exponent, bounds);
2197 }
2198
2199 if( exponent < 0.0 )
2200 {
2201 SCIP_EXPRHDLRDATA* exprhdlrdata;
2202
2203 exprhdlrdata = SCIPexprhdlrGetData(SCIPexprGetHdlr(expr));
2204 assert(exprhdlrdata != NULL);
2205
2206 if( exprhdlrdata->minzerodistance > 0.0 )
2207 {
2208 /* push lower bound from >= -epsilon to >= epsilon to avoid pole at 0 (domain error)
2209 * push upper bound from <= epsilon to <= -epsilon to avoid pole at 0 (domain error)
2210 * this can lead to a cutoff if domain would otherwise be very close around 0
2211 */
2212 if( interval.inf > -exprhdlrdata->minzerodistance && interval.inf < exprhdlrdata->minzerodistance )
2213 {
2214 if( !exprhdlrdata->warnedonpole && SCIPgetVerbLevel(scip) > SCIP_VERBLEVEL_NONE )
2215 {
2216 SCIPinfoMessage(scip, NULL, "Changing lower bound for child of pow(.,%g) from %g to %g.\n"
2217 "Check your model formulation or use option expr/" POWEXPRHDLR_NAME "/minzerodistance to avoid this warning.\n",
2218 exponent, interval.inf, exprhdlrdata->minzerodistance);
2219 SCIPinfoMessage(scip, NULL, "Expression: ");
2220 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2221 SCIPinfoMessage(scip, NULL, "\n");
2222 exprhdlrdata->warnedonpole = TRUE;
2223 }
2224 interval.inf = exprhdlrdata->minzerodistance;
2225 }
2226 else if( interval.sup < exprhdlrdata->minzerodistance && interval.sup > -exprhdlrdata->minzerodistance )
2227 {
2228 if( !exprhdlrdata->warnedonpole && SCIPgetVerbLevel(scip) > SCIP_VERBLEVEL_NONE )
2229 {
2230 SCIPinfoMessage(scip, NULL, "Changing lower bound for child of pow(.,%g) from %g to %g.\n"
2231 "Check your model formulation or use option expr/" POWEXPRHDLR_NAME "/minzerodistance to avoid this warning.\n",
2232 exponent, interval.sup, -exprhdlrdata->minzerodistance);
2233 SCIPinfoMessage(scip, NULL, "Expression: ");
2234 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2235 SCIPinfoMessage(scip, NULL, "\n");
2236 exprhdlrdata->warnedonpole = TRUE;
2237 }
2238 interval.sup = -exprhdlrdata->minzerodistance;
2239 }
2240 }
2241 }
2242
2243 SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", interval.inf, interval.sup);
2244
2245 childrenbounds[0] = interval;
2246
2247 return SCIP_OKAY;
2248}
2249
2250/** initial estimates callback for a power expression */
2251static
2253{
2254 SCIP_EXPRDATA* exprdata;
2255 SCIP_EXPR* child;
2256 SCIP_Real childlb;
2257 SCIP_Real childub;
2258 SCIP_Real exponent;
2259 SCIP_Bool isinteger;
2260 SCIP_Bool branchcand;
2261 SCIP_Bool success;
2262 SCIP_Bool islocal;
2263 SCIP_Real refpointsunder[3] = {SCIP_INVALID, SCIP_INVALID, SCIP_INVALID};
2264 SCIP_Real refpointsover[3] = {SCIP_INVALID, SCIP_INVALID, SCIP_INVALID};
2265 SCIP_Bool overest[6] = {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE};
2266 int i;
2267
2268 assert(scip != NULL);
2269 assert(expr != NULL);
2270
2271 child = SCIPexprGetChildren(expr)[0];
2272 assert(child != NULL);
2273
2274 childlb = bounds[0].inf;
2275 childub = bounds[0].sup;
2276
2277 /* if child is essentially constant, then there should be no point in separation */
2278 if( SCIPisEQ(scip, childlb, childub) )
2279 {
2280 SCIPdebugMsg(scip, "skip initestimates as child seems essentially fixed [%.15g,%.15g]\n", childlb, childub);
2281 return SCIP_OKAY;
2282 }
2283
2284 exprdata = SCIPexprGetData(expr);
2285 exponent = exprdata->exponent;
2286 assert(exponent != 1.0 && exponent != 0.0); /* this should have been simplified */
2287
2288 isinteger = EPSISINT(exponent, 0.0);
2289
2290 /* if exponent is not integral, then child must be non-negative */
2291 if( !isinteger && childlb < 0.0 )
2292 {
2293 /* somewhere we should have tightened the bound on x, but small tightening are not always applied by SCIP
2294 * it is ok to do this tightening here, but let's assert that we were close to 0.0 already
2295 */
2296 assert(SCIPisFeasZero(scip, childlb));
2297 childlb = 0.0;
2298 }
2299 assert(isinteger || childlb >= 0.0);
2300
2301 /* TODO simplify to get 3 refpoints for either under- or overestimate */
2302 SCIP_CALL( chooseRefpointsPow(scip, exprdata, childlb, childub, refpointsunder, refpointsover, !overestimate,
2303 overestimate) );
2304
2305 for( i = 0; i < 6 && *nreturned < SCIP_EXPR_MAXINITESTIMATES; ++i )
2306 {
2307 SCIP_Real refpoint;
2308
2309 if( (overest[i] && !overestimate) || (!overest[i] && overestimate) )
2310 continue;
2311
2312 assert(overest[i] || i < 3); /* make sure that no out-of-bounds array access will be attempted */
2313 refpoint = overest[i] ? refpointsover[i % 3] : refpointsunder[i % 3];
2314
2315 if( refpoint == SCIP_INVALID )
2316 continue;
2317
2318 assert(SCIPisLE(scip, refpoint, childub) && SCIPisGE(scip, refpoint, childlb));
2319
2320 branchcand = TRUE;
2321 SCIP_CALL( buildPowEstimator(scip, exprdata, overest[i], childlb, childub, childlb, childub,
2322 SCIPexprIsIntegral(child), refpoint, exponent, coefs[*nreturned], &constant[*nreturned],
2323 &success, &islocal, &branchcand) );
2324
2325 if( success )
2326 {
2327 SCIPdebugMsg(scip, "initestimate x^%g for base in [%g,%g] at ref=%g, over:%u -> %g*x+%g\n", exponent,
2328 childlb, childub, refpoint, overest[i], coefs[*nreturned][0], constant[*nreturned]);
2329 ++*nreturned;
2330 }
2331 }
2332
2333 return SCIP_OKAY;
2334}
2335
2336/** expression hash callback */
2337static
2339{ /*lint --e{715}*/
2340 assert(scip != NULL);
2341 assert(expr != NULL);
2342 assert(SCIPexprGetNChildren(expr) == 1);
2343 assert(hashkey != NULL);
2344 assert(childrenhashes != NULL);
2345
2346 /* TODO include exponent into hashkey */
2347 *hashkey = POWEXPRHDLR_HASHKEY;
2348 *hashkey ^= childrenhashes[0];
2349
2350 return SCIP_OKAY;
2351}
2352
2353/** expression curvature detection callback */
2354static
2356{ /*lint --e{715}*/
2357 SCIP_EXPR* child;
2358 SCIP_INTERVAL childinterval;
2359 SCIP_Real exponent;
2360
2361 assert(scip != NULL);
2362 assert(expr != NULL);
2363 assert(exprcurvature != SCIP_EXPRCURV_UNKNOWN);
2364 assert(childcurv != NULL);
2365 assert(success != NULL);
2366 assert(SCIPexprGetNChildren(expr) == 1);
2367
2368 exponent = SCIPgetExponentExprPow(expr);
2369 child = SCIPexprGetChildren(expr)[0];
2370 assert(child != NULL);
2371
2373 childinterval = SCIPexprGetActivity(child);
2374
2375 *childcurv = SCIPexprcurvPowerInv(childinterval, exponent, exprcurvature);
2376 /* SCIPexprcurvPowerInv return unknown actually means that curv cannot be obtained */
2377 *success = *childcurv != SCIP_EXPRCURV_UNKNOWN;
2378
2379 return SCIP_OKAY;
2380}
2381
2382/** expression monotonicity detection callback */
2383static
2385{ /*lint --e{715}*/
2386 SCIP_INTERVAL interval;
2387 SCIP_Real exponent;
2388 SCIP_Real inf;
2389 SCIP_Real sup;
2390 SCIP_Bool expisint;
2391
2392 assert(scip != NULL);
2393 assert(expr != NULL);
2394 assert(result != NULL);
2395 assert(SCIPexprGetNChildren(expr) == 1);
2396 assert(childidx == 0);
2397
2398 assert(SCIPexprGetChildren(expr)[0] != NULL);
2400 interval = SCIPexprGetActivity(SCIPexprGetChildren(expr)[0]);
2401
2402 *result = SCIP_MONOTONE_UNKNOWN;
2403 inf = SCIPintervalGetInf(interval);
2404 sup = SCIPintervalGetSup(interval);
2405 exponent = SCIPgetExponentExprPow(expr);
2406 expisint = EPSISINT(exponent, 0.0); /*lint !e835*/
2407
2408 if( expisint )
2409 {
2410 SCIP_Bool expisodd = ceil(exponent/2) != exponent/2;
2411
2412 if( expisodd )
2413 {
2414 /* x^1, x^3, ... */
2415 if( exponent >= 0.0 )
2416 *result = SCIP_MONOTONE_INC;
2417
2418 /* ..., x^-3, x^-1 are decreasing if 0 is not in ]inf,sup[ */
2419 else if( inf >= 0.0 || sup <= 0.0 )
2420 *result = SCIP_MONOTONE_DEC;
2421 }
2422 /* ..., x^-4, x^-2, x^2, x^4, ... */
2423 else
2424 {
2425 /* function is not monotone if 0 is in ]inf,sup[ */
2426 if( inf >= 0.0 )
2427 *result = exponent >= 0.0 ? SCIP_MONOTONE_INC : SCIP_MONOTONE_DEC;
2428 else if( sup <= 0.0 )
2429 *result = exponent >= 0.0 ? SCIP_MONOTONE_DEC : SCIP_MONOTONE_INC;
2430 }
2431 }
2432 else
2433 {
2434 /* note that the expression is not defined for negative input values
2435 *
2436 * - increasing iff exponent >= 0
2437 * - decreasing iff exponent <= 0
2438 */
2439 *result = exponent >= 0.0 ? SCIP_MONOTONE_INC : SCIP_MONOTONE_DEC;
2440 }
2441
2442 return SCIP_OKAY;
2443}
2444
2445/** expression integrality detection callback */
2446static
2448{ /*lint --e{715}*/
2449 SCIP_EXPR* child;
2450 SCIP_Real exponent;
2451 SCIP_Bool expisint;
2452
2453 assert(scip != NULL);
2454 assert(expr != NULL);
2455 assert(integrality != NULL);
2456 assert(SCIPexprGetNChildren(expr) == 1);
2457
2458 child = SCIPexprGetChildren(expr)[0];
2459 assert(child != NULL);
2460
2461 exponent = SCIPgetExponentExprPow(expr);
2462 assert(exponent != 0.0);
2463 expisint = EPSISINT(exponent, 0.0); /*lint !e835*/
2464
2465 /* maintain child integrality if exponent is non-negative and integral */
2466 *integrality = (expisint && exponent >= 0.0) ? SCIPexprGetIntegrality(child) : SCIP_IMPLINTTYPE_NONE;
2467
2468 return SCIP_OKAY;
2469}
2470
2471/** simplifies a signpower expression
2472 */
2473static
2474SCIP_DECL_EXPRSIMPLIFY(simplifySignpower)
2475{ /*lint --e{715}*/
2476 SCIP_EXPR* base;
2477 SCIP_Real exponent;
2478
2479 assert(scip != NULL);
2480 assert(expr != NULL);
2481 assert(simplifiedexpr != NULL);
2482 assert(SCIPexprGetNChildren(expr) == 1);
2483
2484 base = SCIPexprGetChildren(expr)[0];
2485 assert(base != NULL);
2486
2487 exponent = SCIPgetExponentExprPow(expr);
2488 SCIPdebugPrintf("[simplifySignpower] simplifying power with expo %g\n", exponent);
2489 assert(exponent >= 1.0);
2490
2491 /* enforces SPOW2 */
2492 if( exponent == 1.0 )
2493 {
2494 SCIPdebugPrintf("[simplifySignpower] POW2\n");
2495 *simplifiedexpr = base;
2496 SCIPcaptureExpr(*simplifiedexpr);
2497 return SCIP_OKAY;
2498 }
2499
2500 /* enforces SPOW3 */
2501 if( SCIPisExprValue(scip, base) )
2502 {
2503 SCIP_Real baseval;
2504
2505 SCIPdebugPrintf("[simplifySignpower] POW3\n");
2506 baseval = SCIPgetValueExprValue(base);
2507
2508 SCIP_CALL( SCIPcreateExprValue(scip, simplifiedexpr, SIGN(baseval) * pow(REALABS(baseval), exponent),
2509 ownercreate, ownercreatedata) );
2510
2511 return SCIP_OKAY;
2512 }
2513
2514 /* enforces SPOW11 (exp(x)^n = exp(n*x))
2515 * since exp() is always nonnegative, we can treat signpower as normal power here
2516 */
2517 if( SCIPisExprExp(scip, base) )
2518 {
2519 SCIP_EXPR* child;
2520 SCIP_EXPR* prod;
2521 SCIP_EXPR* exponential;
2522 SCIP_EXPR* simplifiedprod;
2523
2524 SCIPdebugPrintf("[simplifySignpower] POW11\n");
2525 child = SCIPexprGetChildren(base)[0];
2526
2527 /* multiply child of exponential with exponent */
2528 SCIP_CALL( SCIPcreateExprProduct(scip, &prod, 1, &child, exponent, ownercreate, ownercreatedata) );
2529
2530 /* simplify product */
2531 SCIP_CALL( SCIPcallExprSimplify(scip, prod, &simplifiedprod, ownercreate, ownercreatedata) );
2532 SCIP_CALL( SCIPreleaseExpr(scip, &prod) );
2533
2534 /* create exponential with new child */
2535 SCIP_CALL( SCIPcreateExprExp(scip, &exponential, simplifiedprod, ownercreate, ownercreatedata) );
2536 SCIP_CALL( SCIPreleaseExpr(scip, &simplifiedprod) );
2537
2538 /* the final simplified expression is the simplification of the just created exponential */
2539 SCIP_CALL( SCIPcallExprSimplify(scip, exponential, simplifiedexpr, ownercreate, ownercreatedata) );
2540 SCIP_CALL( SCIPreleaseExpr(scip, &exponential) );
2541
2542 return SCIP_OKAY;
2543 }
2544
2545 /* enforces SPOW6 */
2546 if( EPSISINT(exponent, 0.0) && ((int)exponent) % 2 == 1 )
2547 {
2548 SCIP_EXPR* aux;
2549
2550 /* we do not just change the expression data of expression to say it is a normal power, since, at the moment,
2551 * simplify identifies that expressions changed by checking that the pointer of the input expression is
2552 * different from the returned (simplified) expression
2553 */
2554 SCIP_CALL( SCIPcreateExprPow(scip, &aux, base, exponent, ownercreate, ownercreatedata) );
2555
2556 SCIP_CALL( simplifyPow(scip, aux, simplifiedexpr, ownercreate, ownercreatedata) );
2557 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
2558
2559 return SCIP_OKAY;
2560 }
2561
2562 /* enforces SPOW10 */
2563 if( SCIPisExprVar(scip, base) )
2564 {
2565 SCIP_VAR* basevar;
2566
2567 SCIPdebugPrintf("[simplifySignpower] POW10\n");
2568 basevar = SCIPgetVarExprVar(base);
2569
2570 assert(basevar != NULL);
2571
2572 if( SCIPvarIsBinary(basevar) )
2573 {
2574 *simplifiedexpr = base;
2575 SCIPcaptureExpr(*simplifiedexpr);
2576 return SCIP_OKAY;
2577 }
2578 }
2579
2580 /* TODO if( SCIPisExprSignpower(scip, base) ... */
2581
2582 /* enforces SPOW8
2583 * given (signpow n (pow expo expr)) we distribute the exponent:
2584 * -> (signpow n*expo expr) for even n (i.e., sign(x^n) * |x|^n = 1 * x^n)
2585 * notes: n is an even integer (see SPOW6 above)
2586 * FIXME: doesn't this extend to any exponent?
2587 * If (pow expo expr) can be negative, it should mean that (-1)^expo = -1
2588 * then (signpow n (pow expo expr)) = sign(expr^expo) * |expr^expo|^n
2589 * then sign(expr^expo) = sign(expr) and |expr^expo| = |expr|^expo and so
2590 * (signpow n (pow expo expr)) = sign(expr^expo) * |expr^expo|^n = sign(expr) * |expr|^(expo*n) = signpow n*expo expr
2591 */
2592 if( EPSISINT(exponent, 0.0) && SCIPisExprPower(scip, base) )
2593 {
2594 SCIP_EXPR* aux;
2595 SCIP_Real newexponent;
2596
2597 assert(((int)exponent) % 2 == 0 ); /* odd case should have been handled by SPOW6 */
2598
2599 newexponent = SCIPgetExponentExprPow(base) * exponent;
2600 SCIP_CALL( SCIPcreateExprSignpower(scip, &aux, SCIPexprGetChildren(base)[0], newexponent,
2601 ownercreate, ownercreatedata) );
2602 SCIP_CALL( simplifySignpower(scip, aux, simplifiedexpr, ownercreate, ownercreatedata) );
2603
2604 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
2605
2606 return SCIP_OKAY;
2607 }
2608
2609 /* enforces SPOW9 */
2610 if( SCIPisExprSum(scip, base)
2611 && SCIPexprGetNChildren(base) == 1
2612 && SCIPgetConstantExprSum(base) == 0.0 )
2613 {
2614 SCIP_EXPR* simplifiedaux;
2615 SCIP_EXPR* aux;
2616 SCIP_Real newcoef;
2617
2618 SCIPdebugPrintf("[simplifySignpower] seeing a sum with one term, exponent %g\n", exponent);
2619 /* assert SS7 holds */
2620 assert(SCIPgetCoefsExprSum(base)[0] != 1.0);
2621
2622 /* create (signpow n expr) and simplify it
2623 * note: we call simplifySignpower directly, since we know that `expr` is simplified */
2624 SCIP_CALL( SCIPcreateExprSignpower(scip, &aux, SCIPexprGetChildren(base)[0], exponent,
2625 ownercreate, ownercreatedata) );
2626 newcoef = SIGN(SCIPgetCoefsExprSum(base)[0]) * pow(REALABS(SCIPgetCoefsExprSum(base)[0]), exponent);
2627 SCIP_CALL( simplifySignpower(scip, aux, &simplifiedaux, ownercreate, ownercreatedata) );
2628 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
2629
2630 /* create (sum (signpow n expr)) and simplify it
2631 * this calls simplifySum directly, since we know its child is simplified */
2632 SCIP_CALL( SCIPcreateExprSum(scip, &aux, 1, &simplifiedaux, &newcoef, 0.0, ownercreate, ownercreatedata) );
2633 SCIP_CALL( SCIPcallExprSimplify(scip, aux, simplifiedexpr, ownercreate, ownercreatedata) );
2634 SCIP_CALL( SCIPreleaseExpr(scip, &aux) );
2635 SCIP_CALL( SCIPreleaseExpr(scip, &simplifiedaux) );
2636 return SCIP_OKAY;
2637 }
2638
2639 SCIPdebugPrintf("[simplifySignpower] signpower is simplified\n");
2640 *simplifiedexpr = expr;
2641
2642 /* we have to capture it, since it must simulate a "normal" simplified call in which a new expression is created */
2643 SCIPcaptureExpr(*simplifiedexpr);
2644
2645 return SCIP_OKAY;
2646}
2647
2648/** expression handler copy callback */
2649static
2650SCIP_DECL_EXPRCOPYHDLR(copyhdlrSignpower)
2651{ /*lint --e{715}*/
2653
2654 return SCIP_OKAY;
2655}
2656
2657/** expression print callback */
2658static
2659SCIP_DECL_EXPRPRINT(printSignpower)
2660{ /*lint --e{715}*/
2661 assert(expr != NULL);
2662
2663 switch( stage )
2664 {
2666 {
2667 SCIPinfoMessage(scip, file, "signpower(");
2668 break;
2669 }
2670
2672 {
2673 assert(currentchild == 0);
2674 break;
2675 }
2676
2678 {
2679 SCIPinfoMessage(scip, file, ",%.15g)", SCIPgetExponentExprPow(expr));
2680 break;
2681 }
2682
2684 default:
2685 break;
2686 }
2687
2688 return SCIP_OKAY;
2689}
2690
2691/** expression parse callback */
2692static
2693SCIP_DECL_EXPRPARSE(parseSignpower)
2694{ /*lint --e{715}*/
2695 SCIP_EXPR* childexpr;
2696 SCIP_Real exponent;
2697
2698 assert(expr != NULL);
2699
2700 /**! [SnippetExprParseSignpower] */
2701 /* parse child expression string */
2702 SCIP_CALL( SCIPparseExpr(scip, &childexpr, string, endstring, ownercreate, ownercreatedata) );
2703 assert(childexpr != NULL);
2704
2705 string = *endstring;
2706 while( *string == ' ' )
2707 ++string;
2708
2709 if( *string != ',' )
2710 {
2711 SCIPerrorMessage("Expected comma after first argument of signpower().\n");
2712 return SCIP_READERROR;
2713 }
2714 ++string;
2715
2716 if( !SCIPparseReal(scip, string, &exponent, (char**)endstring) )
2717 {
2718 SCIPerrorMessage("Expected numeric exponent for second argument of signpower().\n");
2719 return SCIP_READERROR;
2720 }
2721
2722 if( exponent <= 1.0 || !SCIPisFinite(exponent) || SCIPisInfinity(scip, exponent) )
2723 {
2724 SCIPerrorMessage("Expected finite exponent >= 1.0 for signpower().\n");
2725 return SCIP_READERROR;
2726 }
2727
2728 /* create signpower expression */
2729 SCIP_CALL( SCIPcreateExprSignpower(scip, expr, childexpr, exponent, ownercreate, ownercreatedata) );
2730 assert(*expr != NULL);
2731
2732 /* release child expression since it has been captured by the signpower expression */
2733 SCIP_CALL( SCIPreleaseExpr(scip, &childexpr) );
2734
2735 *success = TRUE;
2736 /**! [SnippetExprParseSignpower] */
2737
2738 return SCIP_OKAY;
2739}
2740
2741/** expression point evaluation callback */
2742static
2744{ /*lint --e{715}*/
2745 SCIP_Real exponent;
2746 SCIP_Real base;
2747
2748 assert(expr != NULL);
2749 assert(SCIPexprGetNChildren(expr) == 1);
2751
2752 exponent = SCIPgetExponentExprPow(expr);
2754
2755 *val = SIGN(base) * pow(REALABS(base), exponent);
2756
2757 /* if there is a range error, pow() should return some kind of infinity, or HUGE_VAL
2758 * we could also work with floating point exceptions or errno, but I am not sure this would be thread-safe
2759 */
2760 if( !SCIPisFinite(*val) || *val == HUGE_VAL || *val == -HUGE_VAL )
2761 *val = SCIP_INVALID;
2762
2763 return SCIP_OKAY;
2764}
2765
2766/** expression derivative evaluation callback */
2767static
2768SCIP_DECL_EXPRBWDIFF(bwdiffSignpower)
2769{ /*lint --e{715}*/
2770 SCIP_EXPR* child;
2771 SCIP_Real childval;
2772 SCIP_Real exponent;
2773
2774 assert(expr != NULL);
2775 assert(SCIPexprGetData(expr) != NULL);
2776 assert(childidx == 0);
2777
2778 child = SCIPexprGetChildren(expr)[0];
2779 assert(child != NULL);
2780 assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(child)), "val") != 0);
2781
2782 childval = SCIPexprGetEvalValue(child);
2783 assert(childval != SCIP_INVALID);
2784
2785 exponent = SCIPgetExponentExprPow(expr);
2786 assert(exponent >= 1.0);
2787
2788 *val = exponent * pow(REALABS(childval), exponent - 1.0);
2789
2790 return SCIP_OKAY;
2791}
2792
2793/** expression interval evaluation callback */
2794static
2795SCIP_DECL_EXPRINTEVAL(intevalSignpower)
2796{ /*lint --e{715}*/
2797 SCIP_INTERVAL childinterval;
2798
2799 assert(expr != NULL);
2800 assert(SCIPexprGetNChildren(expr) == 1);
2801
2802 childinterval = SCIPexprGetActivity(SCIPexprGetChildren(expr)[0]);
2803 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, childinterval) )
2804 {
2805 SCIPintervalSetEmpty(interval);
2806 return SCIP_OKAY;
2807 }
2808
2810
2811 return SCIP_OKAY;
2812}
2813
2814/** expression estimator callback */
2815static
2816SCIP_DECL_EXPRESTIMATE(estimateSignpower)
2817{ /*lint --e{715}*/
2818 SCIP_EXPRDATA* exprdata;
2819 SCIP_Real childlb;
2820 SCIP_Real childub;
2821 SCIP_Real childglb;
2822 SCIP_Real childgub;
2823 SCIP_Real exponent;
2824
2825 assert(scip != NULL);
2826 assert(expr != NULL);
2827 assert(SCIPexprGetNChildren(expr) == 1);
2828 assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), SIGNPOWEXPRHDLR_NAME) == 0);
2829 assert(refpoint != NULL);
2830 assert(coefs != NULL);
2831 assert(constant != NULL);
2832 assert(islocal != NULL);
2833 assert(branchcand != NULL);
2834 assert(*branchcand == TRUE); /* the default */
2835 assert(success != NULL);
2836
2837 *success = FALSE;
2838
2839 SCIPdebugMsg(scip, "%sestimation of signed x^%g at x=%g\n", overestimate ? "over" : "under",
2840 SCIPgetExponentExprPow(expr), *refpoint);
2841
2842 /* we can not generate a cut at +/- infinity */
2843 if( SCIPisInfinity(scip, REALABS(*refpoint)) )
2844 return SCIP_OKAY;
2845
2846 childlb = localbounds[0].inf;
2847 childub = localbounds[0].sup;
2848
2849 childglb = globalbounds[0].inf;
2850 childgub = globalbounds[0].sup;
2851
2852 exprdata = SCIPexprGetData(expr);
2853 exponent = exprdata->exponent;
2854 assert(exponent > 1.0); /* exponent == 1 should have been simplified */
2855
2856 /* if child is constant, then return a constant estimator
2857 * this can help with small infeasibilities if boundtightening is relaxing bounds too much
2858 */
2859 if( childlb == childub )
2860 {
2861 *coefs = 0.0;
2862 *constant = SIGN(childlb)*pow(REALABS(childlb), exponent);
2863 *success = TRUE;
2864 *islocal = childglb != childgub;
2865 *branchcand = FALSE;
2866 return SCIP_OKAY;
2867 }
2868
2869 if( childlb >= 0.0 )
2870 {
2871 estimateParabola(scip, exponent, overestimate, childlb, childub, MAX(0.0, *refpoint), constant, coefs,
2872 islocal, success);
2873
2874 *branchcand = *islocal;
2875
2876 /* if odd or signed power, then check whether tangent on parabola is also globally valid, that is
2877 * reference point is right of -root*global-lower-bound
2878 */
2879 if( !*islocal && childglb < 0.0 )
2880 {
2881 if( SCIPisInfinity(scip, -childglb) )
2882 *islocal = TRUE;
2883 else
2884 {
2885 if( exprdata->root == SCIP_INVALID )
2886 {
2887 SCIP_CALL( computeSignpowerRoot(scip, &exprdata->root, exponent) );
2888 }
2889 *islocal = *refpoint < exprdata->root * (-childglb);
2890 }
2891 }
2892 }
2893 else /* and childlb < 0.0 due to previous if */
2894 {
2895 /* compute root if not known yet; only needed if mixed sign (global child ub > 0) */
2896 if( exprdata->root == SCIP_INVALID && childgub > 0.0 )
2897 {
2898 SCIP_CALL( computeSignpowerRoot(scip, &exprdata->root, exponent) );
2899 }
2900 estimateSignedpower(scip, exponent, exprdata->root, overestimate, childlb, childub, *refpoint,
2901 childglb, childgub, constant, coefs, islocal, branchcand, success);
2902 }
2903
2904 return SCIP_OKAY;
2905}
2906
2907/** initial estimates callback for a signpower expression */
2908static
2909SCIP_DECL_EXPRINITESTIMATES(initestimatesSignpower)
2910{
2911 SCIP_EXPRDATA* exprdata;
2912 SCIP_Real childlb;
2913 SCIP_Real childub;
2914 SCIP_Real exponent;
2915 SCIP_Bool branchcand;
2916 SCIP_Bool success;
2917 SCIP_Bool islocal;
2918 SCIP_Real refpointsunder[3] = {SCIP_INVALID, SCIP_INVALID, SCIP_INVALID};
2919 SCIP_Real refpointsover[3] = {SCIP_INVALID, SCIP_INVALID, SCIP_INVALID};
2920 SCIP_Bool overest[6] = {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE};
2921 SCIP_Real refpoint;
2922 int i;
2923
2924 assert(scip != NULL);
2925 assert(expr != NULL);
2926 assert(SCIPexprGetNChildren(expr) == 1);
2927 assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), SIGNPOWEXPRHDLR_NAME) == 0);
2928
2929 childlb = bounds[0].inf;
2930 childub = bounds[0].sup;
2931
2932 /* if child is essentially constant, then there should be no point in separation */
2933 if( SCIPisEQ(scip, childlb, childub) )
2934 {
2935 SCIPdebugMsg(scip, "skip initestimates as child seems essentially fixed [%.15g,%.15g]\n", childlb, childub);
2936 return SCIP_OKAY;
2937 }
2938
2939 exprdata = SCIPexprGetData(expr);
2940 exponent = exprdata->exponent;
2941 assert(exponent > 1.0); /* this should have been simplified */
2942
2943 if( childlb >= 0.0 )
2944 {
2945 if( !overestimate )
2946 addTangentRefpoints(scip, exponent, childlb, childub, refpointsunder);
2947 if( overestimate && !SCIPisInfinity(scip, childub) )
2948 refpointsover[0] = (childlb + childub) / 2.0;
2949 }
2950 else if( childub <= 0.0 )
2951 {
2952 if( !overestimate && !SCIPisInfinity(scip, -childlb) )
2953 refpointsunder[0] = (childlb + childub) / 2.0;
2954 if( overestimate )
2955 addTangentRefpoints(scip, exponent, childlb, childub, refpointsunder);
2956 }
2957 else
2958 {
2959 SCIP_CALL( addSignpowerRefpoints(scip, exprdata, childlb, childub, exponent, !overestimate, refpointsunder) );
2960 }
2961
2962 /* add cuts for all refpoints */
2963 for( i = 0; i < 6 && *nreturned < SCIP_EXPR_MAXINITESTIMATES; ++i )
2964 {
2965 if( (overest[i] && !overestimate) || (!overest[i] && overestimate) )
2966 continue;
2967
2968 assert(overest[i] || i < 3); /* make sure that no out-of-bounds array access will be attempted */
2969 refpoint = overest[i] ? refpointsover[i % 3] : refpointsunder[i % 3];
2970 if( refpoint == SCIP_INVALID )
2971 continue;
2972 assert(SCIPisLE(scip, refpoint, childub) && SCIPisGE(scip, refpoint, childlb));
2973
2974 if( childlb >= 0 )
2975 {
2976 estimateParabola(scip, exponent, overest[i], childlb, childub, refpoint, &constant[*nreturned], coefs[*nreturned],
2977 &islocal, &success);
2978 }
2979 else
2980 {
2981 /* compute root if not known yet; only needed if mixed sign (global child ub > 0) */
2982 if( exprdata->root == SCIP_INVALID && childub > 0.0 )
2983 {
2984 SCIP_CALL( computeSignpowerRoot(scip, &exprdata->root, exponent) );
2985 }
2986 branchcand = TRUE;
2987 estimateSignedpower(scip, exponent, exprdata->root, overest[i], childlb, childub, refpoint,
2988 childlb, childub, &constant[*nreturned], coefs[*nreturned], &islocal,
2989 &branchcand, &success);
2990 }
2991
2992 if( success )
2993 ++*nreturned;
2994 }
2995
2996 return SCIP_OKAY;
2997}
2998
2999/** expression reverse propagaton callback */
3000static
3001SCIP_DECL_EXPRREVERSEPROP(reversepropSignpower)
3002{ /*lint --e{715}*/
3003 SCIP_INTERVAL interval;
3004 SCIP_INTERVAL exprecip;
3005 SCIP_Real exponent;
3006
3007 assert(scip != NULL);
3008 assert(expr != NULL);
3009 assert(SCIPexprGetNChildren(expr) == 1);
3010
3011 exponent = SCIPgetExponentExprPow(expr);
3012
3013 SCIPdebugMsg(scip, "reverseprop signpow(x,%g) in [%.15g,%.15g]", exponent, bounds.inf, bounds.sup);
3014
3016 {
3017 SCIPdebugMsgPrint(scip, "-> no improvement\n");
3018 return SCIP_OKAY;
3019 }
3020
3021 /* f = pow(c0, alpha) -> c0 = pow(f, 1/alpha) */
3022 SCIPintervalSet(&exprecip, exponent);
3023 SCIPintervalReciprocal(SCIP_INTERVAL_INFINITY, &exprecip, exprecip);
3024 if( exprecip.inf == exprecip.sup )
3025 {
3026 SCIPintervalSignPowerScalar(SCIP_INTERVAL_INFINITY, &interval, bounds, exprecip.inf);
3027 }
3028 else
3029 {
3030 SCIP_INTERVAL interval1, interval2;
3031 SCIPintervalSignPowerScalar(SCIP_INTERVAL_INFINITY, &interval1, bounds, exprecip.inf);
3032 SCIPintervalSignPowerScalar(SCIP_INTERVAL_INFINITY, &interval2, bounds, exprecip.sup);
3033 SCIPintervalUnify(&interval, interval1, interval2);
3034 }
3035
3036 SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", interval.inf, interval.sup);
3037
3038 childrenbounds[0] = interval;
3039
3040 return SCIP_OKAY;
3041}
3042
3043/** expression hash callback */
3044static
3046{ /*lint --e{715}*/
3047 assert(scip != NULL);
3048 assert(expr != NULL);
3049 assert(SCIPexprGetNChildren(expr) == 1);
3050 assert(hashkey != NULL);
3051 assert(childrenhashes != NULL);
3052
3053 /* TODO include exponent into hashkey */
3054 *hashkey = SIGNPOWEXPRHDLR_HASHKEY;
3055 *hashkey ^= childrenhashes[0];
3056
3057 return SCIP_OKAY;
3058}
3059
3060/** expression curvature detection callback */
3061static
3062SCIP_DECL_EXPRCURVATURE(curvatureSignpower)
3063{ /*lint --e{715}*/
3064 SCIP_EXPR* child;
3065 SCIP_INTERVAL childinterval;
3066
3067 assert(scip != NULL);
3068 assert(expr != NULL);
3069 assert(exprcurvature != SCIP_EXPRCURV_UNKNOWN);
3070 assert(childcurv != NULL);
3071 assert(success != NULL);
3072 assert(SCIPexprGetNChildren(expr) == 1);
3073
3074 child = SCIPexprGetChildren(expr)[0];
3075 assert(child != NULL);
3076
3078 childinterval = SCIPexprGetActivity(child);
3079
3080 if( exprcurvature == SCIP_EXPRCURV_CONVEX )
3081 {
3082 /* signpower is only convex if argument is convex and non-negative */
3083 *childcurv = SCIP_EXPRCURV_CONVEX;
3084 *success = childinterval.inf >= 0.0;
3085 }
3086 else if( exprcurvature == SCIP_EXPRCURV_CONCAVE )
3087 {
3088 /* signpower is only concave if argument is concave and non-positive */
3089 *childcurv = SCIP_EXPRCURV_CONCAVE;
3090 *success = childinterval.sup <= 0.0;
3091 }
3092 else
3093 *success = FALSE;
3094
3095 return SCIP_OKAY;
3096}
3097
3098/** expression monotonicity detection callback */
3099static
3100SCIP_DECL_EXPRMONOTONICITY(monotonicitySignpower)
3101{ /*lint --e{715}*/
3102 assert(scip != NULL);
3103 assert(expr != NULL);
3104 assert(result != NULL);
3105
3106 *result = SCIP_MONOTONE_INC;
3107 return SCIP_OKAY;
3108}
3109
3110/** creates the handler for power expression and includes it into SCIP */
3112 SCIP* scip /**< SCIP data structure */
3113 )
3114{
3115 SCIP_EXPRHDLR* exprhdlr;
3116 SCIP_EXPRHDLRDATA* exprhdlrdata;
3117
3118 SCIP_CALL( SCIPallocClearBlockMemory(scip, &exprhdlrdata) );
3119
3121 evalPow, exprhdlrdata) );
3122 assert(exprhdlr != NULL);
3123
3124 SCIPexprhdlrSetCopyFreeHdlr(exprhdlr, copyhdlrPow, freehdlrPow);
3125 SCIPexprhdlrSetCopyFreeData(exprhdlr, copydataPow, freedataPow);
3126 SCIPexprhdlrSetSimplify(exprhdlr, simplifyPow);
3127 SCIPexprhdlrSetPrint(exprhdlr, printPow);
3128 SCIPexprhdlrSetIntEval(exprhdlr, intevalPow);
3129 SCIPexprhdlrSetEstimate(exprhdlr, initestimatesPow, estimatePow);
3130 SCIPexprhdlrSetReverseProp(exprhdlr, reversepropPow);
3131 SCIPexprhdlrSetHash(exprhdlr, hashPow);
3132 SCIPexprhdlrSetCompare(exprhdlr, comparePow);
3133 SCIPexprhdlrSetDiff(exprhdlr, bwdiffPow, fwdiffPow, bwfwdiffPow);
3134 SCIPexprhdlrSetCurvature(exprhdlr, curvaturePow);
3135 SCIPexprhdlrSetMonotonicity(exprhdlr, monotonicityPow);
3136 SCIPexprhdlrSetIntegrality(exprhdlr, integralityPow);
3137 SCIPexprhdlrSetGetSymdata(exprhdlr, getSymDataPow);
3138
3139 SCIP_CALL( SCIPaddRealParam(scip, "expr/" POWEXPRHDLR_NAME "/minzerodistance",
3140 "minimal distance from zero to enforce for child in bound tightening",
3141 &exprhdlrdata->minzerodistance, FALSE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
3142
3143 SCIP_CALL( SCIPaddIntParam(scip, "expr/" POWEXPRHDLR_NAME "/expandmaxexponent",
3144 "maximal exponent when to expand power of sum in simplify",
3145 &exprhdlrdata->expandmaxexponent, FALSE, 2, 1, INT_MAX, NULL, NULL) );
3146
3147 SCIP_CALL( SCIPaddBoolParam(scip, "expr/" POWEXPRHDLR_NAME "/distribfracexponent",
3148 "whether a fractional exponent is distributed onto factors on power of product",
3149 &exprhdlrdata->distribfracexponent, FALSE, FALSE, NULL, NULL) );
3150
3151 return SCIP_OKAY;
3152}
3153
3154/** creates the handler for signed power expression and includes it into SCIP */
3156 SCIP* scip /**< SCIP data structure */
3157 )
3158{
3159 SCIP_EXPRHDLR* exprhdlr;
3160
3162 SIGNPOWEXPRHDLR_PRECEDENCE, evalSignpower, NULL) );
3163 assert(exprhdlr != NULL);
3164
3165 SCIPexprhdlrSetCopyFreeHdlr(exprhdlr, copyhdlrSignpower, NULL);
3166 SCIPexprhdlrSetCopyFreeData(exprhdlr, copydataPow, freedataPow);
3167 SCIPexprhdlrSetSimplify(exprhdlr, simplifySignpower);
3168 SCIPexprhdlrSetPrint(exprhdlr, printSignpower);
3169 SCIPexprhdlrSetParse(exprhdlr, parseSignpower);
3170 SCIPexprhdlrSetIntEval(exprhdlr, intevalSignpower);
3171 SCIPexprhdlrSetEstimate(exprhdlr, initestimatesSignpower, estimateSignpower);
3172 SCIPexprhdlrSetReverseProp(exprhdlr, reversepropSignpower);
3173 SCIPexprhdlrSetHash(exprhdlr, hashSignpower);
3174 SCIPexprhdlrSetCompare(exprhdlr, comparePow);
3175 SCIPexprhdlrSetDiff(exprhdlr, bwdiffSignpower, NULL, NULL);
3176 SCIPexprhdlrSetCurvature(exprhdlr, curvatureSignpower);
3177 SCIPexprhdlrSetMonotonicity(exprhdlr, monotonicitySignpower);
3178 SCIPexprhdlrSetIntegrality(exprhdlr, integralityPow);
3179 SCIPexprhdlrSetGetSymdata(exprhdlr, getSymDataPow);
3180
3181 return SCIP_OKAY;
3182}
3183
3184/** creates a power expression */
3186 SCIP* scip, /**< SCIP data structure */
3187 SCIP_EXPR** expr, /**< pointer where to store expression */
3188 SCIP_EXPR* child, /**< single child */
3189 SCIP_Real exponent, /**< exponent of the power expression */
3190 SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call to create ownerdata */
3191 void* ownercreatedata /**< data to pass to ownercreate */
3192 )
3193{
3194 SCIP_EXPRDATA* exprdata;
3195
3196 assert(expr != NULL);
3197 assert(child != NULL);
3198
3199 SCIP_CALL( createData(scip, &exprdata, exponent) );
3200 assert(exprdata != NULL);
3201
3202 SCIP_CALL( SCIPcreateExpr(scip, expr, SCIPgetExprhdlrPower(scip), exprdata, 1, &child, ownercreate,
3203 ownercreatedata) );
3204
3205 return SCIP_OKAY;
3206}
3207
3208/** creates a signpower expression */
3210 SCIP* scip, /**< SCIP data structure */
3211 SCIP_EXPR** expr, /**< pointer where to store expression */
3212 SCIP_EXPR* child, /**< single child */
3213 SCIP_Real exponent, /**< exponent of the power expression */
3214 SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call to create ownerdata */
3215 void* ownercreatedata /**< data to pass to ownercreate */
3216 )
3217{
3218 SCIP_EXPRDATA* exprdata;
3219
3220 assert(expr != NULL);
3221 assert(child != NULL);
3223
3224 SCIP_CALL( createData(scip, &exprdata, exponent) );
3225 assert(exprdata != NULL);
3226
3228 ownercreate, ownercreatedata) );
3229
3230 return SCIP_OKAY;
3231}
3232
3233/** indicates whether expression is of signpower-type */ /*lint -e{715}*/
3235 SCIP* scip, /**< SCIP data structure */
3236 SCIP_EXPR* expr /**< expression */
3237 )
3238{ /*lint --e{715}*/
3239 assert(expr != NULL);
3240
3241 return strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), SIGNPOWEXPRHDLR_NAME) == 0;
3242}
3243
3244/** computes coefficients of linearization of a square term in a reference point */
3246 SCIP* scip, /**< SCIP data structure */
3247 SCIP_Real sqrcoef, /**< coefficient of square term */
3248 SCIP_Real refpoint, /**< point where to linearize */
3249 SCIP_Bool isint, /**< whether corresponding variable is a discrete variable, and thus linearization could be moved */
3250 SCIP_Real* lincoef, /**< buffer to add coefficient of linearization */
3251 SCIP_Real* linconstant, /**< buffer to add constant of linearization */
3252 SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
3253 )
3254{
3255 assert(scip != NULL);
3256 assert(lincoef != NULL);
3257 assert(linconstant != NULL);
3258 assert(success != NULL);
3259
3260 if( sqrcoef == 0.0 )
3261 return;
3262
3263 if( SCIPisInfinity(scip, REALABS(refpoint)) )
3264 {
3265 *success = FALSE;
3266 return;
3267 }
3268
3269 if( !isint || SCIPisIntegral(scip, refpoint) )
3270 {
3271 SCIP_Real tmp;
3272
3273 /* sqrcoef * x^2 -> tangent in refpoint = sqrcoef * 2 * refpoint * (x - refpoint) */
3274
3275 tmp = sqrcoef * refpoint;
3276
3277 if( SCIPisInfinity(scip, 2.0 * REALABS(tmp)) )
3278 {
3279 *success = FALSE;
3280 return;
3281 }
3282
3283 *lincoef += 2.0 * tmp;
3284 tmp *= refpoint;
3285 *linconstant -= tmp;
3286 }
3287 else
3288 {
3289 /* sqrcoef * x^2 -> secant between f=floor(refpoint) and f+1 = sqrcoef * (f^2 + ((f+1)^2 - f^2) * (x-f))
3290 * = sqrcoef * (-f*(f+1) + (2*f+1)*x)
3291 */
3292 SCIP_Real f;
3293 SCIP_Real coef;
3294 SCIP_Real constant;
3295
3296 f = SCIPfloor(scip, refpoint);
3297
3298 coef = sqrcoef * (2.0 * f + 1.0);
3299 constant = -sqrcoef * f * (f + 1.0);
3300
3301 if( SCIPisInfinity(scip, REALABS(coef)) || SCIPisInfinity(scip, REALABS(constant)) )
3302 {
3303 *success = FALSE;
3304 return;
3305 }
3306
3307 *lincoef += coef;
3308 *linconstant += constant;
3309 }
3310}
3311
3312/** computes coefficients of secant of a square term */
3314 SCIP* scip, /**< SCIP data structure */
3315 SCIP_Real sqrcoef, /**< coefficient of square term */
3316 SCIP_Real lb, /**< lower bound on variable */
3317 SCIP_Real ub, /**< upper bound on variable */
3318 SCIP_Real* lincoef, /**< buffer to add coefficient of secant */
3319 SCIP_Real* linconstant, /**< buffer to add constant of secant */
3320 SCIP_Bool* success /**< buffer to set to FALSE if secant has failed due to large numbers or unboundedness */
3321 )
3322{
3323 SCIP_Real coef;
3324 SCIP_Real constant;
3325
3326 assert(scip != NULL);
3327 assert(!SCIPisInfinity(scip, lb));
3328 assert(!SCIPisInfinity(scip, -ub));
3329 assert(SCIPisLE(scip, lb, ub));
3330 assert(lincoef != NULL);
3331 assert(linconstant != NULL);
3332 assert(success != NULL);
3333
3334 if( sqrcoef == 0.0 )
3335 return;
3336
3337 if( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
3338 {
3339 /* unboundedness */
3340 *success = FALSE;
3341 return;
3342 }
3343
3344 /* sqrcoef * x^2 -> sqrcoef * (lb * lb + (ub*ub - lb*lb)/(ub-lb) * (x-lb)) = sqrcoef * (lb*lb + (ub+lb)*(x-lb))
3345 * = sqrcoef * ((lb+ub)*x - lb*ub)
3346 */
3347 coef = sqrcoef * (lb + ub);
3348 constant = -sqrcoef * lb * ub;
3349 if( SCIPisInfinity(scip, REALABS(coef)) || SCIPisInfinity(scip, REALABS(constant)) )
3350 {
3351 *success = FALSE;
3352 return;
3353 }
3354
3355 *lincoef += coef;
3356 *linconstant += constant;
3357}
3358
3359/** Separation for roots with exponent in [0,1]
3360 *
3361 * - x^0.5 with x >= 0
3362 <pre>
3363 8 +----------------------------------------------------------------------+
3364 | + + + + |
3365 7 |-+ x**0.5 ********|
3366 | *********|
3367 | ******** |
3368 6 |-+ ******** +-|
3369 | ****** |
3370 5 |-+ ****** +-|
3371 | ****** |
3372 | ***** |
3373 4 |-+ **** +-|
3374 | ***** |
3375 3 |-+ **** +-|
3376 | *** |
3377 | *** |
3378 2 |-+ ** +-|
3379 | ** |
3380 1 |** +-|
3381 |* |
3382 |* + + + + |
3383 0 +----------------------------------------------------------------------+
3384 0 10 20 30 40 50
3385 </pre>
3386 */
3388 SCIP* scip, /**< SCIP data structure */
3389 SCIP_Real exponent, /**< exponent */
3390 SCIP_Bool overestimate, /**< should the power be overestimated? */
3391 SCIP_Real xlb, /**< lower bound on x */
3392 SCIP_Real xub, /**< upper bound on x */
3393 SCIP_Real xref, /**< reference point (where to linearize) */
3394 SCIP_Real* constant, /**< buffer to store constant term of estimator */
3395 SCIP_Real* slope, /**< buffer to store slope of estimator */
3396 SCIP_Bool* islocal, /**< buffer to store whether estimator only locally valid, that is,
3397 it depends on given bounds */
3398 SCIP_Bool* success /**< buffer to store whether estimator could be computed */
3399 )
3400{
3401 assert(scip != NULL);
3402 assert(constant != NULL);
3403 assert(slope != NULL);
3404 assert(islocal != NULL);
3405 assert(success != NULL);
3406 assert(exponent > 0.0);
3407 assert(exponent < 1.0);
3408 assert(xlb >= 0.0);
3409
3410 if( !overestimate )
3411 {
3412 /* underestimate -> secant */
3413 computeSecant(scip, FALSE, exponent, xlb, xub, constant, slope, success);
3414 *islocal = TRUE;
3415 }
3416 else
3417 {
3418 /* overestimate -> tangent */
3419
3420 /* need to linearize right of 0 */
3421 if( xref < 0.0 )
3422 xref = 0.0;
3423
3424 if( SCIPisZero(scip, xref) )
3425 {
3426 if( SCIPisZero(scip, xub) )
3427 {
3428 *success = FALSE;
3429 *islocal = FALSE;
3430 return;
3431 }
3432
3433 /* if xref is 0 (then xlb=0 probably), then slope is infinite, then try to move away from 0 */
3434 if( xub < 0.2 )
3435 xref = 0.5 * xlb + 0.5 * xub;
3436 else
3437 xref = 0.1;
3438 }
3439
3440 computeTangent(scip, FALSE, exponent, xref, constant, slope, success);
3441 *islocal = FALSE;
3442 }
3443}
3444
3445/* from pub_expr.h */
3446
3447/** gets the exponent of a power or signed power expression */ /*lint -e{715}*/
3449 SCIP_EXPR* expr /**< expression */
3450 )
3451{
3452 SCIP_EXPRDATA* exprdata;
3453
3454 assert(expr != NULL);
3455
3456 exprdata = SCIPexprGetData(expr);
3457 assert(exprdata != NULL);
3458
3459 return exprdata->exponent;
3460}
#define NULL
Definition: def.h:248
#define EPSISINT(x, eps)
Definition: def.h:195
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_INTERVAL_INFINITY
Definition: def.h:180
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define REALABS(x)
Definition: def.h:182
#define SCIP_CALL(x)
Definition: def.h:355
absolute expression handler
exponential expression handler
#define SIGNPOWEXPRHDLR_PRECEDENCE
Definition: expr_pow.c:57
static SCIP_DECL_EXPRPRINT(printPow)
Definition: expr_pow.c:1843
static SCIP_DECL_EXPRESTIMATE(estimatePow)
Definition: expr_pow.c:2082
static SCIP_DECL_EXPRREVERSEPROP(reversepropPow)
Definition: expr_pow.c:2158
#define POWEXPRHDLR_PRECEDENCE
Definition: expr_pow.c:52
void SCIPaddSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: expr_pow.c:3245
static SCIP_DECL_EXPRBWDIFF(bwdiffPow)
Definition: expr_pow.c:1979
static SCIP_RETCODE chooseRefpointsPow(SCIP *scip, SCIP_EXPRDATA *exprdata, SCIP_Real lb, SCIP_Real ub, SCIP_Real *refpointsunder, SCIP_Real *refpointsover, SCIP_Bool underestimate, SCIP_Bool overestimate)
Definition: expr_pow.c:1216
static SCIP_DECL_EXPRPARSE(parseSignpower)
Definition: expr_pow.c:2693
static SCIP_DECL_EXPRINITESTIMATES(initestimatesPow)
Definition: expr_pow.c:2252
static SCIP_DECL_EXPRFWDIFF(fwdiffPow)
Definition: expr_pow.c:1917
static void estimateSignedpower(SCIP *scip, SCIP_Real exponent, SCIP_Real root, SCIP_Bool overestimate, SCIP_Real xlb, SCIP_Real xub, SCIP_Real xref, SCIP_Real xlbglobal, SCIP_Real xubglobal, SCIP_Real *constant, SCIP_Real *slope, SCIP_Bool *islocal, SCIP_Bool *branchcand, SCIP_Bool *success)
Definition: expr_pow.c:552
static SCIP_DECL_EXPRFREEHDLR(freehdlrPow)
Definition: expr_pow.c:1794
static void computeTangent(SCIP *scip, SCIP_Bool signpower, SCIP_Real exponent, SCIP_Real xref, SCIP_Real *constant, SCIP_Real *slope, SCIP_Bool *success)
Definition: expr_pow.c:257
#define SIGNPOWEXPRHDLR_NAME
Definition: expr_pow.c:55
static SCIP_DECL_EXPRINTEVAL(intevalPow)
Definition: expr_pow.c:2010
void SCIPestimateRoot(SCIP *scip, SCIP_Real exponent, SCIP_Bool overestimate, SCIP_Real xlb, SCIP_Real xub, SCIP_Real xref, SCIP_Real *constant, SCIP_Real *slope, SCIP_Bool *islocal, SCIP_Bool *success)
Definition: expr_pow.c:3387
#define SIGNPOWEXPRHDLR_HASHKEY
Definition: expr_pow.c:58
#define POWEXPRHDLR_NAME
Definition: expr_pow.c:50
static SCIP_DECL_EXPRCOPYHDLR(copyhdlrPow)
Definition: expr_pow.c:1785
static SCIP_RETCODE buildPowEstimator(SCIP *scip, SCIP_EXPRDATA *exprdata, SCIP_Bool overestimate, SCIP_Real childlb, SCIP_Real childub, SCIP_Real childglb, SCIP_Real childgub, SCIP_Bool childintegral, SCIP_Real refpoint, SCIP_Real exponent, SCIP_Real *coef, SCIP_Real *constant, SCIP_Bool *success, SCIP_Bool *islocal, SCIP_Bool *branchcand)
Definition: expr_pow.c:990
static void estimateParabola(SCIP *scip, SCIP_Real exponent, SCIP_Bool overestimate, SCIP_Real xlb, SCIP_Real xub, SCIP_Real xref, SCIP_Real *constant, SCIP_Real *slope, SCIP_Bool *islocal, SCIP_Bool *success)
Definition: expr_pow.c:486
static SCIP_DECL_EXPRGETSYMDATA(getSymDataPow)
Definition: expr_pow.c:1762
static SCIP_DECL_EXPREVAL(evalPow)
Definition: expr_pow.c:1887
#define SIGN(x)
Definition: expr_pow.c:71
static SCIP_RETCODE createData(SCIP *scip, SCIP_EXPRDATA **exprdata, SCIP_Real exponent)
Definition: expr_pow.c:231
static SCIP_DECL_EXPRMONOTONICITY(monotonicityPow)
Definition: expr_pow.c:2384
static SCIP_DECL_EXPRINTEGRALITY(integralityPow)
Definition: expr_pow.c:2447
static SCIP_DECL_EXPRCURVATURE(curvaturePow)
Definition: expr_pow.c:2355
static SCIP_DECL_EXPRCOMPARE(comparePow)
Definition: expr_pow.c:1304
static SCIP_DECL_EXPRFREEDATA(freedataPow)
Definition: expr_pow.c:1825
void SCIPaddSquareSecant(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real lb, SCIP_Real ub, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: expr_pow.c:3313
static SCIP_RETCODE addSignpowerRefpoints(SCIP *scip, SCIP_EXPRDATA *exprdata, SCIP_Real lb, SCIP_Real ub, SCIP_Real exponent, SCIP_Bool underestimate, SCIP_Real *refpoints)
Definition: expr_pow.c:1161
#define SIGNPOW_ROOTS_KNOWN
Definition: expr_pow.c:73
static void estimateHyperbolaPositive(SCIP *scip, SCIP_Real exponent, SCIP_Real root, SCIP_Bool overestimate, SCIP_Real xlb, SCIP_Real xub, SCIP_Real xref, SCIP_Real xlbglobal, SCIP_Real xubglobal, SCIP_Real *constant, SCIP_Real *slope, SCIP_Bool *islocal, SCIP_Bool *branchcand, SCIP_Bool *success)
Definition: expr_pow.c:700
static SCIP_DECL_EXPRBWFWDIFF(bwfwdiffPow)
Definition: expr_pow.c:1950
#define POWEXPRHDLR_HASHKEY
Definition: expr_pow.c:53
static SCIP_DECL_EXPRCOPYDATA(copydataPow)
Definition: expr_pow.c:1806
static SCIP_RETCODE computeSignpowerRoot(SCIP *scip, SCIP_Real *root, SCIP_Real exponent)
Definition: expr_pow.c:117
static SCIP_DECL_EXPRSIMPLIFY(simplifyPow)
Definition: expr_pow.c:1327
static void estimateHyperbolaMixed(SCIP *scip, SCIP_Real exponent, SCIP_Bool overestimate, SCIP_Real xlb, SCIP_Real xub, SCIP_Real xref, SCIP_Real xlbglobal, SCIP_Real xubglobal, SCIP_Real *constant, SCIP_Real *slope, SCIP_Bool *islocal, SCIP_Bool *branchcand, SCIP_Bool *success)
Definition: expr_pow.c:912
#define SIGNPOWEXPRHDLR_DESC
Definition: expr_pow.c:56
#define INITLPMAXPOWVAL
Definition: expr_pow.c:60
#define POWEXPRHDLR_DESC
Definition: expr_pow.c:51
static SCIP_DECL_EXPRHASH(hashPow)
Definition: expr_pow.c:2338
static void addTangentRefpoints(SCIP *scip, SCIP_Real exponent, SCIP_Real lb, SCIP_Real ub, SCIP_Real *refpoints)
Definition: expr_pow.c:1123
static SCIP_RETCODE computeHyperbolaRoot(SCIP *scip, SCIP_Real *root, SCIP_Real exponent)
Definition: expr_pow.c:185
static SCIP_Real signpow_roots[SIGNPOW_ROOTS_KNOWN+1]
Definition: expr_pow.c:79
static void computeSecant(SCIP *scip, SCIP_Bool signpower, SCIP_Real exponent, SCIP_Real xlb, SCIP_Real xub, SCIP_Real *constant, SCIP_Real *slope, SCIP_Bool *success)
Definition: expr_pow.c:306
power and signed power expression handlers
product expression handler
sum expression handler
constant value expression handler
SCIP_RETCODE SCIPcreateExprProduct(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real coefficient, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
SCIP_RETCODE SCIPpowerExprSum(SCIP *scip, SCIP_EXPR **result, SCIP_EXPR *base, int exponent, SCIP_Bool simplify, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_sum.c:1315
SCIP_Bool SCIPisExprAbs(SCIP *scip, SCIP_EXPR *expr)
Definition: expr_abs.c:546
SCIP_RETCODE SCIPcreateExprAbs(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_abs.c:528
SCIP_RETCODE SCIPcreateExprSignpower(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_pow.c:3209
SCIP_Bool SCIPisExprExp(SCIP *scip, SCIP_EXPR *expr)
Definition: expr_exp.c:528
SCIP_RETCODE SCIPcreateExprExp(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_exp.c:510
SCIP_Bool SCIPisExprSignpower(SCIP *scip, SCIP_EXPR *expr)
Definition: expr_pow.c:3234
SCIP_RETCODE SCIPcreateExprSum(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefficients, SCIP_Real constant, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_sum.c:1117
SCIP_RETCODE SCIPcreateExprValue(SCIP *scip, SCIP_EXPR **expr, SCIP_Real value, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_value.c:274
SCIP_RETCODE SCIPcreateExprPow(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_pow.c:3185
SCIP_RETCODE SCIPincludeExprhdlrSignpower(SCIP *scip)
Definition: expr_pow.c:3155
SCIP_RETCODE SCIPincludeExprhdlrPow(SCIP *scip)
Definition: expr_pow.c:3111
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
SCIP_VERBLEVEL SCIPgetVerbLevel(SCIP *scip)
Definition: scip_message.c:249
#define SCIPdebugMsgPrint
Definition: scip_message.h:79
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
const char * SCIPexprhdlrGetName(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:545
void SCIPexprhdlrSetIntegrality(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRINTEGRALITY((*integrality)))
Definition: expr.c:440
void SCIPexprhdlrSetCopyFreeData(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRCOPYDATA((*copydata)), SCIP_DECL_EXPRFREEDATA((*freedata)))
Definition: expr.c:383
void SCIPexprhdlrSetPrint(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRPRINT((*print)))
Definition: expr.c:396
void SCIPexprhdlrSetGetSymdata(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRGETSYMDATA((*getsymdata)))
Definition: expr.c:521
void SCIPexprhdlrSetHash(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRHASH((*hash)))
Definition: expr.c:451
SCIP_EXPRHDLRDATA * SCIPexprhdlrGetData(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:575
void SCIPexprhdlrSetCopyFreeHdlr(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRCOPYHDLR((*copyhdlr)), SCIP_DECL_EXPRFREEHDLR((*freehdlr)))
Definition: expr.c:370
void SCIPexprhdlrSetDiff(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRBWDIFF((*bwdiff)), SCIP_DECL_EXPRFWDIFF((*fwdiff)), SCIP_DECL_EXPRBWFWDIFF((*bwfwdiff)))
Definition: expr.c:473
void SCIPexprhdlrSetReverseProp(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRREVERSEPROP((*reverseprop)))
Definition: expr.c:510
void SCIPexprhdlrSetParse(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRPARSE((*parse)))
Definition: expr.c:407
void SCIPexprhdlrSetEstimate(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRINITESTIMATES((*initestimates)), SCIP_DECL_EXPRESTIMATE((*estimate)))
Definition: expr.c:532
void SCIPexprhdlrSetMonotonicity(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRMONOTONICITY((*monotonicity)))
Definition: expr.c:429
void SCIPexprhdlrSetIntEval(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRINTEVAL((*inteval)))
Definition: expr.c:488
void SCIPexprhdlrSetCurvature(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRCURVATURE((*curvature)))
Definition: expr.c:418
SCIP_RETCODE SCIPincludeExprhdlr(SCIP *scip, SCIP_EXPRHDLR **exprhdlr, const char *name, const char *desc, unsigned int precedence, SCIP_DECL_EXPREVAL((*eval)), SCIP_EXPRHDLRDATA *data)
Definition: scip_expr.c:847
void SCIPexprhdlrSetCompare(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRCOMPARE((*compare)))
Definition: expr.c:462
SCIP_EXPRHDLR * SCIPgetExprhdlrPower(SCIP *scip)
Definition: scip_expr.c:950
SCIP_EXPRHDLR * SCIPfindExprhdlr(SCIP *scip, const char *name)
Definition: scip_expr.c:894
void SCIPexprhdlrSetSimplify(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRSIMPLIFY((*simplify)))
Definition: expr.c:499
SCIP_IMPLINTTYPE SCIPexprGetIntegrality(SCIP_EXPR *expr)
Definition: expr.c:4091
SCIP_RETCODE SCIPcreateExpr(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPRHDLR *exprhdlr, SCIP_EXPRDATA *exprdata, int nchildren, SCIP_EXPR **children, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1000
SCIP_RETCODE SCIPappendExprChild(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *child)
Definition: scip_expr.c:1256
void SCIPexprSetData(SCIP_EXPR *expr, SCIP_EXPRDATA *exprdata)
Definition: expr.c:3920
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3872
SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
Definition: expr_pow.c:3448
SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1490
SCIP_EXPRCURV SCIPexprcurvPowerInv(SCIP_INTERVAL basebounds, SCIP_Real exponent, SCIP_EXPRCURV powercurv)
Definition: exprcurv.c:209
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1479
SCIP_Bool SCIPexprIsIntegral(SCIP_EXPR *expr)
Definition: expr.c:4101
SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
Definition: expr_sum.c:1554
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1468
int SCIPcompareExpr(SCIP *scip, SCIP_EXPR *expr1, SCIP_EXPR *expr2)
Definition: scip_expr.c:1759
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition: scip_expr.c:1443
SCIP_Real SCIPexprGetDot(SCIP_EXPR *expr)
Definition: expr.c:3986
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1457
SCIP_EXPRDATA * SCIPexprGetData(SCIP_EXPR *expr)
Definition: expr.c:3905
SCIP_RETCODE SCIPparseExpr(SCIP *scip, SCIP_EXPR **expr, const char *exprstr, const char **finalpos, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1406
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition: scip_expr.c:1512
SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
Definition: expr_value.c:298
SCIP_Bool SCIPisExprPower(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1501
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition: expr.c:3946
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:3882
SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
Definition: expr_sum.c:1569
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition: expr_var.c:424
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition: expr.c:4028
void SCIPcaptureExpr(SCIP_EXPR *expr)
Definition: scip_expr.c:1435
SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1742
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition: expr.c:3895
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalSignPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
void SCIPintervalUnify(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalPowerScalarInverse(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL basedomain, SCIP_Real exponent, SCIP_INTERVAL image)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
void SCIPintervalReciprocal(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
#define SCIPallocClearBlockMemory(scip, ptr)
Definition: scip_mem.h:91
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPparseReal(SCIP *scip, const char *str, SCIP_Real *value, char **endptr)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
public functions to work with algebraic expressions
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPdebugPrintf
Definition: pub_message.h:99
#define SCIPisFinite(x)
Definition: pub_misc.h:82
SCIP_Real sup
Definition: intervalarith.h:57
SCIP_Real inf
Definition: intervalarith.h:56
structs for symmetry computations
#define SCIP_DECL_EXPR_OWNERCREATE(x)
Definition: type_expr.h:143
struct SCIP_ExprhdlrData SCIP_EXPRHDLRDATA
Definition: type_expr.h:195
struct SCIP_ExprData SCIP_EXPRDATA
Definition: type_expr.h:54
@ SCIP_EXPRCURV_CONVEX
Definition: type_expr.h:63
@ SCIP_EXPRCURV_UNKNOWN
Definition: type_expr.h:62
@ SCIP_EXPRCURV_CONCAVE
Definition: type_expr.h:64
#define SCIP_EXPR_MAXINITESTIMATES
Definition: type_expr.h:198
#define SCIP_EXPRITER_VISITINGCHILD
Definition: type_expr.h:695
@ SCIP_MONOTONE_UNKNOWN
Definition: type_expr.h:71
@ SCIP_MONOTONE_INC
Definition: type_expr.h:72
@ SCIP_MONOTONE_DEC
Definition: type_expr.h:73
#define SCIP_EXPRITER_VISITEDCHILD
Definition: type_expr.h:696
#define SCIP_EXPRITER_LEAVEEXPR
Definition: type_expr.h:697
#define SCIP_EXPRITER_ENTEREXPR
Definition: type_expr.h:694
@ SCIP_VERBLEVEL_NONE
Definition: type_message.h:57
@ SCIP_READERROR
Definition: type_retcode.h:45
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_IMPLINTTYPE_NONE
Definition: type_var.h:90