Scippy

SCIP

Solving Constraint Integer Programs

intervalarith.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 intervalarith.c
26 * @ingroup OTHER_CFILES
27 * @brief interval arithmetics for provable bounds
28 * @author Tobias Achterberg
29 * @author Stefan Vigerske
30 * @author Kati Wolter
31 */
32
33/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34
35#define _USE_MATH_DEFINES /* to get M_PI on Windows */ /*lint !750 */
36
37#include <stdlib.h>
38#include <assert.h>
39#include <math.h>
40
41#include "scip/def.h"
42#include "scip/intervalarith.h"
43#include "scip/pub_message.h"
44#include "scip/misc.h"
45#include "scip/rational.h"
46
47/* Inform compiler that this code accesses the floating-point environment, so that
48 * certain optimizations should be omitted (http://www.cplusplus.com/reference/cfenv/FENV_ACCESS/).
49 * Not supported by Clang (gives warning) and GCC (silently), at the moment.
50 */
51#if defined(__INTEL_COMPILER) || defined(_MSC_VER)
52#pragma fenv_access (on)
53#elif defined(__GNUC__) && !defined(__clang__)
54#pragma STDC FENV_ACCESS ON
55#endif
56
57/* Unfortunately, the FENV_ACCESS pragma is essentially ignored by GCC at the moment (2019),
58 * see #2650 and https://gcc.gnu.org/bugzilla/show_bug.cgi?id=34678.
59 * There are ways to work around this by declaring variables volatile or inserting more assembler code,
60 * but there is always the danger that something would be overlooked.
61 * A more drastic but safer way seems to be to just disable all compiler optimizations for this file.
62 * The Intel compiler seems to implement FENV_ACCESS correctly, but also defines __GNUC__.
63 */
64#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
65#if defined(__clang__)
66#pragma clang optimize off
67#else
68#pragma GCC optimize ("O0")
69#endif
70#endif
71
72/*lint -e644*/
73/*lint -e777*/
74
75#ifdef SCIP_ROUNDING_FE
76#define ROUNDING
77/*
78 * Linux rounding operations
79 */
80
81#include <fenv.h>
82
83/** Linux rounding mode settings */
84#define SCIP_ROUND_DOWNWARDS FE_DOWNWARD /**< round always down */
85#define SCIP_ROUND_UPWARDS FE_UPWARD /**< round always up */
86#define SCIP_ROUND_NEAREST FE_TONEAREST /**< round always to nearest */
87#define SCIP_ROUND_ZERO FE_TOWARDZERO /**< round always towards 0.0 */
88
89/** returns whether rounding mode control is available */
91 void
92 )
93{
94 return TRUE;
95}
96
97/** sets rounding mode of floating point operations */
98static
100 SCIP_ROUNDMODE roundmode /**< rounding mode to activate */
101 )
102{
103#ifndef NDEBUG
104 if( fesetround(roundmode) != 0 )
105 {
106 SCIPerrorMessage("error setting rounding mode to %d\n", roundmode);
107 abort();
108 }
109#else
110 (void) fesetround(roundmode);
111#endif
112}
113
114/** gets current rounding mode of floating point operations */
115static
117 void
118 )
119{
120 return (SCIP_ROUNDMODE)fegetround();
121}
122
123#endif
124
125
126
127#ifdef SCIP_ROUNDING_FP
128#define ROUNDING
129/*
130 * OSF rounding operations
131 */
132
133#include <float.h>
134
135/** OSF rounding mode settings */
136#define SCIP_ROUND_DOWNWARDS FP_RND_RM /**< round always down */
137#define SCIP_ROUND_UPWARDS FP_RND_RP /**< round always up */
138#define SCIP_ROUND_NEAREST FP_RND_RN /**< round always to nearest */
139#define SCIP_ROUND_ZERO FP_RND_RZ /**< round always towards 0.0 */
140
141/** returns whether rounding mode control is available */
143 void
144 )
145{
146 return TRUE;
147}
148
149/** sets rounding mode of floating point operations */
150static
152 SCIP_ROUNDMODE roundmode /**< rounding mode to activate */
153 )
154{
155#ifndef NDEBUG
156 if( write_rnd(roundmode) != 0 )
157 {
158 SCIPerrorMessage("error setting rounding mode to %d\n", roundmode);
159 abort();
160 }
161#else
162 (void) write_rnd(roundmode);
163#endif
164}
165
166/** gets current rounding mode of floating point operations */
167static
169 void
170 )
171{
172 return read_rnd();
173}
174
175#endif
176
177
178
179#ifdef SCIP_ROUNDING_MS
180#define ROUNDING
181/*
182 * Microsoft compiler rounding operations
183 */
184
185#include <float.h>
186
187/** Microsoft rounding mode settings */
188#define SCIP_ROUND_DOWNWARDS RC_DOWN /**< round always down */
189#define SCIP_ROUND_UPWARDS RC_UP /**< round always up */
190#define SCIP_ROUND_NEAREST RC_NEAR /**< round always to nearest */
191#define SCIP_ROUND_ZERO RC_CHOP /**< round always towards zero */
192
193/** returns whether rounding mode control is available */
195 void
196 )
197{
198 return TRUE;
199}
200
201/** sets rounding mode of floating point operations */
202static
204 SCIP_ROUNDMODE roundmode /**< rounding mode to activate */
205 )
206{
207#ifndef NDEBUG
208 if( (_controlfp(roundmode, _MCW_RC) & _MCW_RC) != roundmode )
209 {
210 SCIPerrorMessage("error setting rounding mode to %x\n", roundmode);
211 abort();
212 }
213#else
214 (void) _controlfp(roundmode, _MCW_RC);
215#endif
216}
217
218/** gets current rounding mode of floating point operations */
219static
221 void
222 )
223{
224 return _controlfp(0, 0) & _MCW_RC;
225}
226#endif
227
228
229
230#ifndef ROUNDING
231/*
232 * rouding operations not available
233 */
234#define SCIP_ROUND_DOWNWARDS 0 /**< round always down */
235#define SCIP_ROUND_UPWARDS 1 /**< round always up */
236#define SCIP_ROUND_NEAREST 2 /**< round always to nearest */
237#define SCIP_ROUND_ZERO 3 /**< round always towards zero */
238
239/** returns whether rounding mode control is available */
241 void
242 )
243{
244 return FALSE;
245}
246
247/** sets rounding mode of floating point operations */ /*lint -e715*/
248static
250 SCIP_ROUNDMODE roundmode /**< rounding mode to activate */
251 )
252{ /*lint --e{715}*/
253 SCIPerrorMessage("setting rounding mode not available - interval arithmetic is invalid!\n");
254}
255
256/** gets current rounding mode of floating point operations */
257static
259 void
260 )
261{
262 return SCIP_ROUND_NEAREST;
263}
264#else
265#undef ROUNDING
266#endif
267
268/** sets rounding mode of floating point operations */
270 SCIP_ROUNDMODE roundmode /**< rounding mode to activate */
271 )
272{
273 intervalSetRoundingMode(roundmode);
274}
275
276/** gets current rounding mode of floating point operations */
278 void
279 )
280{
282}
283
284#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) /* gcc or icc compiler on x86 32bit or 64bit */
285
286/** gets the negation of a double
287 * Do this in a way that the compiler does not "optimize" it away, which usually does not considers rounding modes.
288 * However, compiling with -frounding-math would allow to return -x here.
289 * @todo We now set the FENV_ACCESS pragma to on, which is the same as -frounding-math, so we might be able to eliminate this.
290 */
291static
292double negate(
293 /* we explicitly use double here, since I'm not sure the assembler code would work as it for other float's */
294 double x /**< number that should be negated */
295 )
296{
297 /* The following line of code is taken from GAOL, http://sourceforge.net/projects/gaol. */
298 __asm volatile ("fldl %1; fchs; fstpl %0" : "=m" (x) : "m" (x));
299 return x;
300}
301
302/* cl or icl compiler on 32bit windows or icl compiler on 64bit windows
303 * cl on 64bit windows does not seem to support inline assembler
304 */
305#elif defined(_MSC_VER) && (defined(__INTEL_COMPILER) || !defined(_M_X64))
306
307/** gets the negation of a double
308 * Do this in a way that the compiler does not "optimize" it away, which usually does not considers rounding modes.
309 */
310static
311double negate(
312 /* we explicitly use double here, since I'm not sure the assembler code would work as it for other float's */
313 double x /**< number that should be negated */
314 )
315{
316 /* The following lines of code are taken from GAOL, http://sourceforge.net/projects/gaol. */
317 __asm {
318 fld x
319 fchs
320 fstp x
321 }
322 return x;
323}
324
325#else /* unknown compiler or MSVS 64bit */
326
327/** gets the negation of a double
328 *
329 * Fallback implementation that calls the negation method from misc.o.
330 * Having the implementation in a different object file will hopefully prevent
331 * it from being "optimized away".
332 */
333static
335 SCIP_Real x /**< number that should be negated */
336 )
337{
338 return SCIPnegateReal(x);
339}
340
341#endif
342
343
344/** sets rounding mode of floating point operations to downwards rounding */
346 void
347 )
348{
350}
351
352/** sets rounding mode of floating point operations to upwards rounding */
354 void
355 )
356{
358}
359
360/** sets rounding mode of floating point operations to nearest rounding */
362 void
363 )
364{
366}
367
368/** sets rounding mode of floating point operations to towards zero rounding */
370 void
371 )
372{
374}
375
376/** negates a number in a way that the compiler does not optimize it away */
378 SCIP_Real x /**< number to negate */
379 )
380{
381 return negate((double)x);
382}
383
384/*
385 * Interval arithmetic operations
386 */
387
388/* In debug mode, the following methods are implemented as function calls to ensure
389 * type validity.
390 * In optimized mode, the methods are implemented as defines to improve performance.
391 * However, we want to have them in the library anyways, so we have to undef the defines.
392 */
393
394#undef SCIPintervalGetInf
395#undef SCIPintervalGetSup
396#undef SCIPintervalSet
397#undef SCIPintervalSetBounds
398#undef SCIPintervalSetEmpty
399#undef SCIPintervalIsEmpty
400#undef SCIPintervalSetEntire
401#undef SCIPintervalIsEntire
402#undef SCIPintervalIsPositiveInfinity
403#undef SCIPintervalIsNegativeInfinity
404
405/** returns infimum of interval */
407 SCIP_INTERVAL interval /**< interval */
408 )
409{
410 return interval.inf;
411}
412
413/** returns supremum of interval */
415 SCIP_INTERVAL interval /**< interval */
416 )
417{
418 return interval.sup;
419}
420
421/** stores given value as interval */
423 SCIP_INTERVAL* resultant, /**< interval to store value into */
424 SCIP_Real value /**< value to store */
425 )
426{
427 assert(resultant != NULL);
428
429 resultant->inf = value;
430 resultant->sup = value;
431}
432
433/** stores given value as interval */
435 SCIP_INTERVAL* resultant, /**< interval to store value into */
436 SCIP_RATIONAL* value /**< value to store */
437 )
438{
439 assert(resultant != NULL);
440
443}
444
445/** stores given infimum and supremum as interval */
447 SCIP_INTERVAL* resultant, /**< interval to store value into */
448 SCIP_Real inf, /**< value to store as infimum */
449 SCIP_Real sup /**< value to store as supremum */
450 )
451{
452 assert(resultant != NULL);
453 assert(inf <= sup);
454
455 resultant->inf = inf;
456 resultant->sup = sup;
457}
458
459/** sets interval to empty interval, which will be [1.0, -1.0] */
461 SCIP_INTERVAL* resultant /**< resultant interval of operation */
462 )
463{
464 assert(resultant != NULL);
465
466 resultant->inf = 1.0;
467 resultant->sup = -1.0;
468}
469
470/** indicates whether interval is empty, i.e., whether inf > sup */
472 SCIP_Real infinity, /**< value for infinity */
473 SCIP_INTERVAL operand /**< operand of operation */
474 )
475{
476 if( operand.sup >= infinity || operand.inf <= -infinity )
477 return FALSE;
478
479 return operand.sup < operand.inf;
480}
481
482/** sets interval to entire [-infinity, +infinity] */
484 SCIP_Real infinity, /**< value for infinity */
485 SCIP_INTERVAL* resultant /**< resultant interval of operation */
486 )
487{
488 assert(resultant != NULL);
489
490 resultant->inf = -infinity;
491 resultant->sup = infinity;
492}
493
494/** indicates whether interval is entire, i.e., whether inf &le; -infinity and sup &ge; infinity */
496 SCIP_Real infinity, /**< value for infinity */
497 SCIP_INTERVAL operand /**< operand of operation */
498 )
499{
500 return operand.inf <= -infinity && operand.sup >= infinity;
501}
502
503/** indicates whether interval is positive infinity, i.e., [infinity, infinity] */
505 SCIP_Real infinity, /**< value for infinity */
506 SCIP_INTERVAL operand /**< operand of operation */
507 )
508{
509 return operand.inf >= infinity && operand.sup >= operand.inf;
510}
511
512/** indicates whether interval is negative infinity, i.e., [-infinity, -infinity] */
514 SCIP_Real infinity, /**< value for infinity */
515 SCIP_INTERVAL operand /**< operand of operation */
516 )
517{
518 return operand.sup <= -infinity && operand.inf <= operand.sup;
519}
520
521/** indicates whether operand1 is contained in operand2 */
523 SCIP_Real infinity, /**< value for infinity */
524 SCIP_INTERVAL operand1, /**< first operand of operation */
525 SCIP_INTERVAL operand2 /**< second operand of operation */
526 )
527{
528 /* the empty interval is contained everywhere */
529 if( operand1.inf > operand1.sup )
530 return TRUE;
531
532 /* something not-empty is not contained in the empty interval */
533 if( operand2.inf > operand2.sup )
534 return FALSE;
535
536 return (MAX(-infinity, operand1.inf) >= operand2.inf) &&
537 ( MIN( infinity, operand1.sup) <= operand2.sup);
538}
539
540/** indicates whether operand1 and operand2 are disjoint */
542 SCIP_INTERVAL operand1, /**< first operand of operation */
543 SCIP_INTERVAL operand2 /**< second operand of operation */
544 )
545{
546 return (operand1.sup < operand2.inf) || (operand2.sup < operand1.inf);
547}
548
549/** indicates whether operand1 and operand2 are disjoint with epsilon tolerance
550 *
551 * Returns whether minimal (relative) distance of intervals is larger than epsilon.
552 * Same as `SCIPintervalIsEmpty(SCIPintervalIntersectEps(operand1, operand2))`.
553 */
555 SCIP_Real eps, /**< epsilon */
556 SCIP_INTERVAL operand1, /**< first operand of operation */
557 SCIP_INTERVAL operand2 /**< second operand of operation */
558 )
559{
560 if( operand1.sup < operand2.inf )
561 return SCIPrelDiff(operand2.inf, operand1.sup) > eps;
562
563 if( operand1.inf > operand2.sup )
564 return SCIPrelDiff(operand1.inf, operand2.sup) > eps;
565
566 return FALSE;
567}
568
569/** intersection of two intervals */
571 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
572 SCIP_INTERVAL operand1, /**< first operand of operation */
573 SCIP_INTERVAL operand2 /**< second operand of operation */
574 )
575{
576 assert(resultant != NULL);
577
578 resultant->inf = MAX(operand1.inf, operand2.inf);
579 resultant->sup = MIN(operand1.sup, operand2.sup);
580}
581
582/** intersection of two intervals with epsilon tolerance
583 *
584 * If intersection of operand1 and operand2 is empty, but minimal (relative) distance of intervals
585 * is at most epsilon, then set resultant to singleton containing the point in operand1
586 * that is closest to operand2, i.e.,
587 * - `resultant = { operand1.sup }`, if `operand1.sup` < `operand2.inf` and `reldiff(operand2.inf,operand1.sup)` &le; eps
588 * - `resultant = { operand1.inf }`, if `operand1.inf` > `operand2.sup` and `reldiff(operand1.inf,operand2.sup)` &le; eps
589 * - `resultant` = intersection of `operand1` and `operand2`, otherwise
590 */
592 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
593 SCIP_Real eps, /**< epsilon */
594 SCIP_INTERVAL operand1, /**< first operand of operation */
595 SCIP_INTERVAL operand2 /**< second operand of operation */
596 )
597{
598 assert(resultant != NULL);
599 assert(eps >= 0.0);
600
601 if( operand1.sup < operand2.inf )
602 {
603 if( SCIPrelDiff(operand2.inf, operand1.sup) <= eps )
604 {
605 SCIPintervalSet(resultant, operand1.sup);
606 return;
607 }
608 }
609 else if( operand1.inf > operand2.sup )
610 {
611 if( SCIPrelDiff(operand1.inf, operand2.sup) <= eps )
612 {
613 SCIPintervalSet(resultant, operand1.inf);
614 return;
615 }
616 }
617
618 SCIPintervalIntersect(resultant, operand1, operand2);
619}
620
621/** interval enclosure of the union of two intervals */
623 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
624 SCIP_INTERVAL operand1, /**< first operand of operation */
625 SCIP_INTERVAL operand2 /**< second operand of operation */
626 )
627{
628 assert(resultant != NULL);
629
630 if( operand1.inf > operand1.sup )
631 {
632 /* operand1 is empty */
633 *resultant = operand2;
634 return;
635 }
636
637 if( operand2.inf > operand2.sup )
638 {
639 /* operand2 is empty */
640 *resultant = operand1;
641 return;
642 }
643
644 resultant->inf = MIN(operand1.inf, operand2.inf);
645 resultant->sup = MAX(operand1.sup, operand2.sup);
646}
647
648/** adds operand1 and operand2 and stores infimum of result in infimum of resultant */
650 SCIP_Real infinity, /**< value for infinity */
651 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
652 SCIP_INTERVAL operand1, /**< first operand of operation */
653 SCIP_INTERVAL operand2 /**< second operand of operation */
654 )
655{
657 assert(resultant != NULL);
658
659 /* [a,...] + [-inf,...] = [-inf,...] for all a, in particular, [+inf,...] + [-inf,...] = [-inf,...] */
660 if( operand1.inf <= -infinity || operand2.inf <= -infinity )
661 {
662 resultant->inf = -infinity;
663 }
664 /* [a,...] + [+inf,...] = [+inf,...] for all a > -inf */
665 else if( operand1.inf >= infinity || operand2.inf >= infinity )
666 {
667 resultant->inf = infinity;
668 }
669 else
670 {
671 resultant->inf = operand1.inf + operand2.inf;
672 }
673}
674
675/** adds operand1 and operand2 and stores supremum of result in supremum of resultant */
677 SCIP_Real infinity, /**< value for infinity */
678 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
679 SCIP_INTERVAL operand1, /**< first operand of operation */
680 SCIP_INTERVAL operand2 /**< second operand of operation */
681 )
682{
684 assert(resultant != NULL);
685
686 /* [...,b] + [...,+inf] = [...,+inf] for all b, in particular, [...,-inf] + [...,+inf] = [...,+inf] */
687 if( operand1.sup >= infinity || operand2.sup >= infinity )
688 {
689 resultant->sup = infinity;
690 }
691 /* [...,b] + [...,-inf] = [...,-inf] for all b < +inf */
692 else if( operand1.sup <= -infinity || operand2.sup <= -infinity )
693 {
694 resultant->sup = -infinity;
695 }
696 else
697 {
698 resultant->sup = operand1.sup + operand2.sup;
699 }
700}
701
702/** adds operand1 and operand2 and stores result in resultant */
704 SCIP_Real infinity, /**< value for infinity */
705 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
706 SCIP_INTERVAL operand1, /**< first operand of operation */
707 SCIP_INTERVAL operand2 /**< second operand of operation */
708 )
709{
710 SCIP_ROUNDMODE roundmode;
711
712 assert(resultant != NULL);
713 assert(!SCIPintervalIsEmpty(infinity, operand1));
714 assert(!SCIPintervalIsEmpty(infinity, operand2));
715
716 roundmode = intervalGetRoundingMode();
717
718 /* compute infimum of result */
720 SCIPintervalAddInf(infinity, resultant, operand1, operand2);
721
722 /* compute supremum of result */
724 SCIPintervalAddSup(infinity, resultant, operand1, operand2);
725
726 intervalSetRoundingMode(roundmode);
727}
728
729/** adds operand1 and scalar operand2 and stores result in resultant */
731 SCIP_Real infinity, /**< value for infinity */
732 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
733 SCIP_INTERVAL operand1, /**< first operand of operation */
734 SCIP_Real operand2 /**< second operand of operation */
735 )
736{
737 SCIP_ROUNDMODE roundmode;
738
739 assert(resultant != NULL);
740 assert(!SCIPintervalIsEmpty(infinity, operand1));
741
742 roundmode = intervalGetRoundingMode();
743
744 /* -inf + something >= -inf */
745 if( operand1.inf <= -infinity || operand2 <= -infinity )
746 {
747 resultant->inf = -infinity;
748 }
749 else if( operand1.inf >= infinity || operand2 >= infinity )
750 {
751 /* inf + finite = inf, inf + inf = inf */
752 resultant->inf = infinity;
753 }
754 else
755 {
757 resultant->inf = operand1.inf + operand2;
758 }
759
760 /* inf + something <= inf */
761 if( operand1.sup >= infinity || operand2 >= infinity )
762 {
763 resultant->sup = infinity;
764 }
765 else if( operand1.sup <= -infinity || operand2 <= -infinity )
766 {
767 /* -inf + finite = -inf, -inf + (-inf) = -inf */
768 resultant->sup = -infinity;
769 }
770 else
771 {
773 resultant->sup = operand1.sup + operand2;
774 }
775
776 intervalSetRoundingMode(roundmode);
777}
778
779/** adds vector operand1 and vector operand2 and stores result in vector resultant */
781 SCIP_Real infinity, /**< value for infinity */
782 SCIP_INTERVAL* resultant, /**< array of resultant intervals of operation */
783 int length, /**< length of arrays */
784 SCIP_INTERVAL* operand1, /**< array of first operands of operation */
785 SCIP_INTERVAL* operand2 /**< array of second operands of operation */
786 )
787{
788 SCIP_ROUNDMODE roundmode;
789 int i;
790
791 roundmode = intervalGetRoundingMode();
792
793 /* compute infimums of resultant array */
795 for( i = 0; i < length; ++i )
796 {
797 SCIPintervalAddInf(infinity, &resultant[i], operand1[i], operand2[i]);
798 }
799 /* compute supremums of result array */
801 for( i = 0; i < length; ++i )
802 {
803 SCIPintervalAddSup(infinity, &resultant[i], operand1[i], operand2[i]);
804 }
805
806 intervalSetRoundingMode(roundmode);
807}
808
809/** subtracts operand2 from operand1 and stores result in resultant */
811 SCIP_Real infinity, /**< value for infinity */
812 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
813 SCIP_INTERVAL operand1, /**< first operand of operation */
814 SCIP_INTERVAL operand2 /**< second operand of operation */
815 )
816{
817 SCIP_ROUNDMODE roundmode;
818
819 assert(resultant != NULL);
820 assert(!SCIPintervalIsEmpty(infinity, operand1));
821 assert(!SCIPintervalIsEmpty(infinity, operand2));
822
823 roundmode = intervalGetRoundingMode();
824
825 if( operand1.inf <= -infinity || operand2.sup >= infinity )
826 resultant->inf = -infinity;
827 /* [a,b] - [-inf,-inf] = [+inf,+inf] */
828 else if( operand1.inf >= infinity || operand2.sup <= -infinity )
829 {
830 resultant->inf = infinity;
831 resultant->sup = infinity;
832 return;
833 }
834 else
835 {
837 resultant->inf = operand1.inf - operand2.sup;
838 }
839
840 if( operand1.sup >= infinity || operand2.inf <= -infinity )
841 resultant->sup = infinity;
842 /* [a,b] - [+inf,+inf] = [-inf,-inf] */
843 else if( operand1.sup <= -infinity || operand2.inf >= infinity )
844 {
845 assert(resultant->inf == -infinity); /* should be set above, since operand1.inf <= operand1.sup <= -infinity */
846 resultant->sup = -infinity;
847 }
848 else
849 {
851 resultant->sup = operand1.sup - operand2.inf;
852 }
853
854 intervalSetRoundingMode(roundmode);
855}
856
857/** subtracts scalar operand2 from operand1 and stores result in resultant */
859 SCIP_Real infinity, /**< value for infinity */
860 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
861 SCIP_INTERVAL operand1, /**< first operand of operation */
862 SCIP_Real operand2 /**< second operand of operation */
863 )
864{
865 SCIPintervalAddScalar(infinity, resultant, operand1, -operand2);
866}
867
868/** multiplies operand1 with operand2 and stores infimum of result in infimum of resultant */
870 SCIP_Real infinity, /**< value for infinity */
871 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
872 SCIP_INTERVAL operand1, /**< first operand of operation; can be +/-inf */
873 SCIP_INTERVAL operand2 /**< second operand of operation; can be +/-inf */
874 )
875{
876 assert(resultant != NULL);
877 assert(!SCIPintervalIsEmpty(infinity, operand1));
878 assert(!SCIPintervalIsEmpty(infinity, operand2));
879
881
882 if( operand1.inf >= infinity )
883 {
884 /* operand1 is infinity scalar */
885 assert(operand1.sup >= infinity);
886 SCIPintervalMulScalarInf(infinity, resultant, operand2, infinity);
887 }
888 else if( operand2.inf >= infinity )
889 {
890 /* operand2 is infinity scalar */
891 assert(operand2.sup >= infinity);
892 SCIPintervalMulScalarInf(infinity, resultant, operand1, infinity);
893 }
894 else if( operand1.sup <= -infinity )
895 {
896 /* operand1 is -infinity scalar */
897 assert(operand1.inf <= -infinity);
898 SCIPintervalMulScalarInf(infinity, resultant, operand2, -infinity);
899 }
900 else if( operand2.sup <= -infinity )
901 {
902 /* operand2 is -infinity scalar */
903 assert(operand2.inf <= -infinity);
904 SCIPintervalMulScalarInf(infinity, resultant, operand1, -infinity);
905 }
906 else if( ( operand1.inf <= -infinity && operand2.sup > 0.0 )
907 || ( operand1.sup > 0.0 && operand2.inf <= -infinity )
908 || ( operand1.inf < 0.0 && operand2.sup >= infinity )
909 || ( operand1.sup >= infinity && operand2.inf < 0.0 ) )
910 {
911 resultant->inf = -infinity;
912 }
913 else
914 {
915 SCIP_Real cand1;
916 SCIP_Real cand2;
917 SCIP_Real cand3;
918 SCIP_Real cand4;
919
920 cand1 = operand1.inf * operand2.inf;
921 cand2 = operand1.inf * operand2.sup;
922 cand3 = operand1.sup * operand2.inf;
923 cand4 = operand1.sup * operand2.sup;
924 resultant->inf = MIN(MIN(cand1, cand2), MIN(cand3, cand4));
925 }
926}
927
928/** multiplies operand1 with operand2 and stores supremum of result in supremum of resultant */
930 SCIP_Real infinity, /**< value for infinity */
931 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
932 SCIP_INTERVAL operand1, /**< first operand of operation; can be +/-inf */
933 SCIP_INTERVAL operand2 /**< second operand of operation; can be +/-inf */
934 )
935{
936 assert(resultant != NULL);
937 assert(!SCIPintervalIsEmpty(infinity, operand1));
938 assert(!SCIPintervalIsEmpty(infinity, operand2));
939
941
942 if( operand1.inf >= infinity )
943 {
944 /* operand1 is infinity scalar */
945 assert(operand1.sup >= infinity);
946 SCIPintervalMulScalarSup(infinity, resultant, operand2, infinity);
947 }
948 else if( operand2.inf >= infinity )
949 {
950 /* operand2 is infinity scalar */
951 assert(operand2.sup >= infinity);
952 SCIPintervalMulScalarSup(infinity, resultant, operand1, infinity);
953 }
954 else if( operand1.sup <= -infinity )
955 {
956 /* operand1 is -infinity scalar */
957 assert(operand1.inf <= -infinity);
958 SCIPintervalMulScalarSup(infinity, resultant, operand2, -infinity);
959 }
960 else if( operand2.sup <= -infinity )
961 {
962 /* operand2 is -infinity scalar */
963 assert(operand2.inf <= -infinity);
964 SCIPintervalMulScalarSup(infinity, resultant, operand1, -infinity);
965 }
966 else if( ( operand1.inf <= -infinity && operand2.inf < 0.0 )
967 || ( operand1.inf < 0.0 && operand2.inf <= -infinity )
968 || ( operand1.sup > 0.0 && operand2.sup >= infinity )
969 || ( operand1.sup >= infinity && operand2.sup > 0.0 ) )
970 {
971 resultant->sup = infinity;
972 }
973 else
974 {
975 SCIP_Real cand1;
976 SCIP_Real cand2;
977 SCIP_Real cand3;
978 SCIP_Real cand4;
979
980 cand1 = operand1.inf * operand2.inf;
981 cand2 = operand1.inf * operand2.sup;
982 cand3 = operand1.sup * operand2.inf;
983 cand4 = operand1.sup * operand2.sup;
984 resultant->sup = MAX(MAX(cand1, cand2), MAX(cand3, cand4));
985 }
986}
987
988/** multiplies operand1 with operand2 and stores result in resultant */
990 SCIP_Real infinity, /**< value for infinity */
991 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
992 SCIP_INTERVAL operand1, /**< first operand of operation; can be +/-inf */
993 SCIP_INTERVAL operand2 /**< second operand of operation; can be +/-inf */
994 )
995{
996 SCIP_ROUNDMODE roundmode;
997
998 assert(resultant != NULL);
999 assert(!SCIPintervalIsEmpty(infinity, operand1));
1000 assert(!SCIPintervalIsEmpty(infinity, operand2));
1001
1002 roundmode = intervalGetRoundingMode();
1003
1004 /* compute infimum result */
1006 SCIPintervalMulInf(infinity, resultant, operand1, operand2);
1007
1008 /* compute supremum of result */
1010 SCIPintervalMulSup(infinity, resultant, operand1, operand2);
1011
1012 intervalSetRoundingMode(roundmode);
1013}
1014
1015/** multiplies operand1 with scalar operand2 and stores infimum of result in infimum of resultant */
1017 SCIP_Real infinity, /**< value for infinity */
1018 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1019 SCIP_INTERVAL operand1, /**< first operand of operation */
1020 SCIP_Real operand2 /**< second operand of operation; can be +/- inf */
1021 )
1022{
1024 assert(resultant != NULL);
1025 assert(!SCIPintervalIsEmpty(infinity, operand1));
1026
1027 if( operand2 >= infinity )
1028 {
1029 /* result.inf defined by sign of operand1.inf */
1030 if( operand1.inf > 0 )
1031 resultant->inf = infinity;
1032 else if( operand1.inf < 0 )
1033 resultant->inf = -infinity;
1034 else
1035 resultant->inf = 0.0;
1036 }
1037 else if( operand2 <= -infinity )
1038 {
1039 /* result.inf defined by sign of operand1.sup */
1040 if( operand1.sup > 0 )
1041 resultant->inf = -infinity;
1042 else if( operand1.sup < 0 )
1043 resultant->inf = infinity;
1044 else
1045 resultant->inf = 0.0;
1046 }
1047 else if( operand2 == 0.0 )
1048 {
1049 resultant->inf = 0.0;
1050 }
1051 else if( operand2 > 0.0 )
1052 {
1053 if( operand1.inf <= -infinity )
1054 resultant->inf = -infinity;
1055 else if( operand1.inf >= infinity )
1056 resultant->inf = infinity;
1057 else
1058 resultant->inf = operand1.inf * operand2;
1059 }
1060 else
1061 {
1062 if( operand1.sup >= infinity )
1063 resultant->inf = -infinity;
1064 else if( operand1.sup <= -infinity )
1065 resultant->inf = infinity;
1066 else
1067 resultant->inf = operand1.sup * operand2;
1068 }
1069}
1070
1071/** multiplies operand1 with scalar operand2 and stores supremum of result in supremum of resultant */
1073 SCIP_Real infinity, /**< value for infinity */
1074 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1075 SCIP_INTERVAL operand1, /**< first operand of operation */
1076 SCIP_Real operand2 /**< second operand of operation; can be +/- inf */
1077 )
1078{
1080 assert(resultant != NULL);
1081 assert(!SCIPintervalIsEmpty(infinity, operand1));
1082
1083 if( operand2 >= infinity )
1084 {
1085 /* result.sup defined by sign of operand1.sup */
1086 if( operand1.sup > 0 )
1087 resultant->sup = infinity;
1088 else if( operand1.sup < 0 )
1089 resultant->sup = -infinity;
1090 else
1091 resultant->sup = 0.0;
1092 }
1093 else if( operand2 <= -infinity )
1094 {
1095 /* result.sup defined by sign of operand1.inf */
1096 if( operand1.inf > 0 )
1097 resultant->sup = -infinity;
1098 else if( operand1.inf < 0 )
1099 resultant->sup = infinity;
1100 else
1101 resultant->sup = 0.0;
1102 }
1103 else if( operand2 == 0.0 )
1104 {
1105 resultant->sup = 0.0;
1106 }
1107 else if( operand2 > 0.0 )
1108 {
1109 if( operand1.sup >= infinity )
1110 resultant->sup = infinity;
1111 else if( operand1.sup <= -infinity )
1112 resultant->sup = -infinity;
1113 else
1114 resultant->sup = operand1.sup * operand2;
1115 }
1116 else
1117 {
1118 if( operand1.inf <= -infinity )
1119 resultant->sup = infinity;
1120 else if( operand1.inf >= infinity )
1121 resultant->sup = -infinity;
1122 else
1123 resultant->sup = operand1.inf * operand2;
1124 }
1125}
1126
1127/** multiplies operand1 with scalar operand2 and stores result in resultant */
1129 SCIP_Real infinity, /**< value for infinity */
1130 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1131 SCIP_INTERVAL operand1, /**< first operand of operation */
1132 SCIP_Real operand2 /**< second operand of operation */
1133 )
1134{
1135 SCIP_ROUNDMODE roundmode;
1136
1137 assert(resultant != NULL);
1138 assert(!SCIPintervalIsEmpty(infinity, operand1));
1139
1140 if( operand2 == 1.0 )
1141 {
1142 *resultant = operand1;
1143 return;
1144 }
1145
1146 if( operand2 == -1.0 )
1147 {
1148 resultant->inf = -operand1.sup;
1149 resultant->sup = -operand1.inf;
1150 return;
1151 }
1152
1153 roundmode = intervalGetRoundingMode();
1154
1155 /* compute infimum result */
1157 SCIPintervalMulScalarInf(infinity, resultant, operand1, operand2);
1158
1159 /* compute supremum of result */
1161 SCIPintervalMulScalarSup(infinity, resultant, operand1, operand2);
1162
1163 intervalSetRoundingMode(roundmode);
1164}
1165
1166/** divides operand1 by operand2 and stores result in resultant */
1168 SCIP_Real infinity, /**< value for infinity */
1169 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1170 SCIP_INTERVAL operand1, /**< first operand of operation */
1171 SCIP_INTERVAL operand2 /**< second operand of operation */
1172 )
1173{
1174 SCIP_ROUNDMODE roundmode;
1175 SCIP_INTERVAL intmed;
1176
1177 assert(resultant != NULL);
1178 assert(!SCIPintervalIsEmpty(infinity, operand1));
1179 assert(!SCIPintervalIsEmpty(infinity, operand2));
1180
1181 if( operand2.inf <= 0.0 && operand2.sup >= 0.0 )
1182 { /* division by [0,0] or interval containing 0 gives [-inf, +inf] */
1183 resultant->inf = -infinity;
1184 resultant->sup = infinity;
1185 return;
1186 }
1187
1188 if( operand1.inf == 0.0 && operand1.sup == 0.0 )
1189 { /* division of [0,0] by something nonzero */
1190 SCIPintervalSet(resultant, 0.0);
1191 return;
1192 }
1193
1194 roundmode = intervalGetRoundingMode();
1195
1196 /* division by nonzero: resultant = x * (1/y) */
1197 if( operand2.sup >= infinity || operand2.sup <= -infinity )
1198 {
1199 intmed.inf = 0.0;
1200 }
1201 else
1202 {
1204 intmed.inf = 1.0 / operand2.sup;
1205 }
1206 if( operand2.inf <= -infinity || operand2.inf >= infinity )
1207 {
1208 intmed.sup = 0.0;
1209 }
1210 else
1211 {
1213 intmed.sup = 1.0 / operand2.inf;
1214 }
1215 SCIPintervalMul(infinity, resultant, operand1, intmed);
1216
1217 intervalSetRoundingMode(roundmode);
1218}
1219
1220/** divides operand1 by scalar operand2 and stores result in resultant */
1222 SCIP_Real infinity, /**< value for infinity */
1223 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1224 SCIP_INTERVAL operand1, /**< first operand of operation */
1225 SCIP_Real operand2 /**< second operand of operation */
1226 )
1227{
1228 SCIP_ROUNDMODE roundmode;
1229
1230 assert(resultant != NULL);
1231 assert(!SCIPintervalIsEmpty(infinity, operand1));
1232
1233 roundmode = intervalGetRoundingMode();
1234
1235 if( operand2 >= infinity || operand2 <= -infinity )
1236 {
1237 /* division by +/-infinity is 0.0 */
1238 resultant->inf = 0.0;
1239 resultant->sup = 0.0;
1240 }
1241 else if( operand2 > 0.0 )
1242 {
1243 if( operand1.inf <= -infinity )
1244 resultant->inf = -infinity;
1245 else if( operand1.inf >= infinity )
1246 {
1247 /* infinity / + = infinity */
1248 resultant->inf = infinity;
1249 }
1250 else
1251 {
1253 resultant->inf = operand1.inf / operand2;
1254 }
1255
1256 if( operand1.sup >= infinity )
1257 resultant->sup = infinity;
1258 else if( operand1.sup <= -infinity )
1259 {
1260 /* -infinity / + = -infinity */
1261 resultant->sup = -infinity;
1262 }
1263 else
1264 {
1266 resultant->sup = operand1.sup / operand2;
1267 }
1268 }
1269 else if( operand2 < 0.0 )
1270 {
1271 if( operand1.sup >= infinity )
1272 resultant->inf = -infinity;
1273 else if( operand1.sup <= -infinity )
1274 {
1275 /* -infinity / - = infinity */
1276 resultant->inf = infinity;
1277 }
1278 else
1279 {
1281 resultant->inf = operand1.sup / operand2;
1282 }
1283
1284 if( operand1.inf <= -infinity )
1285 resultant->sup = infinity;
1286 else if( operand1.inf >= infinity )
1287 {
1288 /* infinity / - = -infinity */
1289 resultant->sup = -infinity;
1290 }
1291 else
1292 {
1294 resultant->sup = operand1.inf / operand2;
1295 }
1296 }
1297 else
1298 { /* division by 0.0 */
1299 if( operand1.inf >= 0 )
1300 {
1301 /* [+,+] / [0,0] = [+inf, +inf] */
1302 resultant->inf = infinity;
1303 resultant->sup = infinity;
1304 }
1305 else if( operand1.sup <= 0 )
1306 {
1307 /* [-,-] / [0,0] = [-inf, -inf] */
1308 resultant->inf = -infinity;
1309 resultant->sup = -infinity;
1310 }
1311 else
1312 {
1313 /* [-,+] / [0,0] = [-inf, +inf] */
1314 resultant->inf = -infinity;
1315 resultant->sup = infinity;
1316 }
1317 return;
1318 }
1319
1320 intervalSetRoundingMode(roundmode);
1321}
1322
1323/** computes the scalar product of two vectors of intervals and stores result in resultant */
1325 SCIP_Real infinity, /**< value for infinity */
1326 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1327 int length, /**< length of vectors */
1328 SCIP_INTERVAL* operand1, /**< first vector as array of intervals; can have +/-inf entries */
1329 SCIP_INTERVAL* operand2 /**< second vector as array of intervals; can have +/-inf entries */
1330 )
1331{
1332 SCIP_ROUNDMODE roundmode;
1333 SCIP_INTERVAL prod;
1334 int i;
1335
1336 roundmode = intervalGetRoundingMode();
1337
1338 resultant->inf = 0.0;
1339 resultant->sup = 0.0;
1340
1341 /* compute infimum of resultant */
1343 for( i = 0; i < length && resultant->inf > -infinity; ++i )
1344 {
1346 SCIPintervalMulInf(infinity, &prod, operand1[i], operand2[i]);
1347 SCIPintervalAddInf(infinity, resultant, *resultant, prod);
1348 }
1349 assert(resultant->sup == 0.0);
1350
1351 /* compute supremum of resultant */
1353 for( i = 0; i < length && resultant->sup < infinity ; ++i )
1354 {
1356 SCIPintervalMulSup(infinity, &prod, operand1[i], operand2[i]);
1357 SCIPintervalAddSup(infinity, resultant, *resultant, prod);
1358 }
1359
1360 intervalSetRoundingMode(roundmode);
1361}
1362
1363/** computes the scalar product of a vector of intervals and a vector of scalars and stores infimum of result in infimum of resultant */
1365 SCIP_Real infinity, /**< value for infinity */
1366 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1367 int length, /**< length of vectors */
1368 SCIP_INTERVAL* operand1, /**< first vector as array of intervals */
1369 SCIP_Real* operand2 /**< second vector as array of scalars; can have +/-inf entries */
1370 )
1371{
1372 SCIP_INTERVAL prod;
1373 int i;
1374
1376
1377 resultant->inf = 0.0;
1378
1379 /* compute infimum of resultant */
1381 for( i = 0; i < length && resultant->inf > -infinity; ++i )
1382 {
1383 SCIPintervalMulScalarInf(infinity, &prod, operand1[i], operand2[i]);
1384 assert(prod.sup >= infinity);
1385 SCIPintervalAddInf(infinity, resultant, *resultant, prod);
1386 }
1387}
1388
1389/** computes the scalar product of a vector of intervals and a vector of scalars and stores supremum of result in supremum of resultant */
1391 SCIP_Real infinity, /**< value for infinity */
1392 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1393 int length, /**< length of vectors */
1394 SCIP_INTERVAL* operand1, /**< first vector as array of intervals */
1395 SCIP_Real* operand2 /**< second vector as array of scalars; can have +/-inf entries */
1396 )
1397{
1398 SCIP_INTERVAL prod;
1399 int i;
1400
1402
1403 resultant->sup = 0.0;
1404
1405 /* compute supremum of resultant */
1407 for( i = 0; i < length && resultant->sup < infinity; ++i )
1408 {
1409 SCIPintervalMulScalarSup(infinity, &prod, operand1[i], operand2[i]);
1410 assert(prod.inf <= -infinity);
1411 SCIPintervalAddSup(infinity, resultant, *resultant, prod);
1412 }
1413}
1414
1415/** computes the scalar product of a vector of intervals and a vector of scalars and stores result in resultant */
1417 SCIP_Real infinity, /**< value for infinity */
1418 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1419 int length, /**< length of vectors */
1420 SCIP_INTERVAL* operand1, /**< first vector as array of intervals */
1421 SCIP_Real* operand2 /**< second vector as array of scalars; can have +/-inf entries */
1422 )
1423{
1424 SCIP_ROUNDMODE roundmode;
1425
1426 roundmode = intervalGetRoundingMode();
1427
1428 resultant->inf = 0.0;
1429 resultant->sup = 0.0;
1430
1431 /* compute infimum of resultant */
1433 SCIPintervalScalprodScalarsInf(infinity, resultant, length, operand1, operand2);
1434 assert(resultant->sup == 0.0);
1435
1436 /* compute supremum of resultant */
1438 SCIPintervalScalprodScalarsSup(infinity, resultant, length, operand1, operand2);
1439
1440 intervalSetRoundingMode(roundmode);
1441}
1442
1443/** squares operand and stores result in resultant */
1445 SCIP_Real infinity, /**< value for infinity */
1446 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1447 SCIP_INTERVAL operand /**< operand of operation */
1448 )
1449{
1450 SCIP_ROUNDMODE roundmode;
1451
1452 assert(resultant != NULL);
1453 assert(!SCIPintervalIsEmpty(infinity, operand));
1454
1455 roundmode = intervalGetRoundingMode();
1456
1457 if( operand.sup <= 0.0 )
1458 { /* operand is left of 0.0 */
1459 if( operand.sup <= -infinity )
1460 resultant->inf = infinity;
1461 else
1462 {
1464 resultant->inf = operand.sup * operand.sup;
1465 }
1466
1467 if( operand.inf <= -infinity )
1468 resultant->sup = infinity;
1469 else
1470 {
1472 resultant->sup = operand.inf * operand.inf;
1473 }
1474 }
1475 else if( operand.inf >= 0.0 )
1476 { /* operand is right of 0.0 */
1477 if( operand.inf >= infinity )
1478 resultant->inf = infinity;
1479 else
1480 {
1482 resultant->inf = operand.inf * operand.inf;
1483 }
1484
1485 if( operand.sup >= infinity )
1486 resultant->sup = infinity;
1487 else
1488 {
1490 resultant->sup = operand.sup * operand.sup;
1491 }
1492 }
1493 else
1494 { /* [-,+]^2 */
1495 resultant->inf = 0.0;
1496 if( operand.inf <= -infinity || operand.sup >= infinity )
1497 resultant->sup = infinity;
1498 else
1499 {
1500 SCIP_Real x;
1501 SCIP_Real y;
1502
1504 x = operand.inf * operand.inf;
1505 y = operand.sup * operand.sup;
1506 resultant->sup = MAX(x, y);
1507 }
1508 }
1509
1510 intervalSetRoundingMode(roundmode);
1511}
1512
1513/** stores (positive part of) square root of operand in resultant
1514 * @attention we assume a correctly rounded sqrt(double) function when rounding is to nearest
1515 */
1517 SCIP_Real infinity, /**< value for infinity */
1518 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1519 SCIP_INTERVAL operand /**< operand of operation */
1520 )
1521{
1522 assert(resultant != NULL);
1523 assert(!SCIPintervalIsEmpty(infinity, operand));
1524
1525 if( operand.sup < 0.0 )
1526 {
1527 SCIPintervalSetEmpty(resultant);
1528 return;
1529 }
1530
1531 if( operand.inf == operand.sup )
1532 {
1533 if( operand.inf >= infinity )
1534 {
1535 resultant->inf = infinity;
1536 resultant->sup = infinity;
1537 }
1538 else
1539 {
1540 SCIP_Real tmp;
1541
1542 assert(intervalGetRoundingMode() == SCIP_ROUND_NEAREST); /* usually, no-one should have changed rounding mode */
1543 tmp = sqrt(operand.inf);
1544 resultant->inf = SCIPnextafter(tmp, SCIP_REAL_MIN);
1545 resultant->sup = SCIPnextafter(tmp, SCIP_REAL_MAX);
1546 }
1547
1548 return;
1549 }
1550
1551 if( operand.inf <= 0.0 )
1552 resultant->inf = 0.0;
1553 else if( operand.inf >= infinity )
1554 {
1555 resultant->inf = infinity;
1556 resultant->sup = infinity;
1557 }
1558 else
1559 {
1560 assert(intervalGetRoundingMode() == SCIP_ROUND_NEAREST); /* usually, no-one should have changed rounding mode */
1561 resultant->inf = SCIPnextafter(sqrt(operand.inf), SCIP_REAL_MIN);
1562 }
1563
1564 if( operand.sup >= infinity )
1565 resultant->sup = infinity;
1566 else
1567 {
1568 assert(intervalGetRoundingMode() == SCIP_ROUND_NEAREST); /* usually, no-one should have changed rounding mode */
1569 resultant->sup = SCIPnextafter(sqrt(operand.sup), SCIP_REAL_MAX);
1570 }
1571}
1572
1573/** stores operand1 to the power of operand2 in resultant
1574 *
1575 * uses SCIPintervalPowerScalar if operand2 is a scalar, otherwise computes exp(op2*log(op1))
1576 */
1578 SCIP_Real infinity, /**< value for infinity */
1579 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1580 SCIP_INTERVAL operand1, /**< first operand of operation */
1581 SCIP_INTERVAL operand2 /**< second operand of operation */
1582 )
1583{
1584 assert(resultant != NULL);
1585 assert(!SCIPintervalIsEmpty(infinity, operand1));
1586 assert(!SCIPintervalIsEmpty(infinity, operand2));
1587
1588 if( operand2.inf == operand2.sup )
1589 { /* operand is number */
1590 SCIPintervalPowerScalar(infinity, resultant, operand1, operand2.inf);
1591 return;
1592 }
1593
1594 /* log([..,0]) will give an empty interval below, but we want [0,0]^exponent to be 0
1595 * if 0 is in exponent, then resultant should also contain 1 (the case exponent == [0,0] is handled above)
1596 */
1597 if( operand1.sup == 0.0 )
1598 {
1599 if( operand2.inf <= 0.0 && operand2.sup >= 0.0 )
1600 SCIPintervalSetBounds(resultant, 0.0, 1.0);
1601 else
1602 SCIPintervalSet(resultant, 0.0);
1603 return;
1604 }
1605
1606 /* resultant := log(op1) */
1607 SCIPintervalLog(infinity, resultant, operand1);
1608 if( SCIPintervalIsEmpty(infinity, *resultant) )
1609 return;
1610
1611 /* resultant := op2 * resultant */
1612 SCIPintervalMul(infinity, resultant, operand2, *resultant);
1613
1614 /* resultant := exp(resultant) */
1615 SCIPintervalExp(infinity, resultant, *resultant);
1616}
1617
1618/** computes lower bound on power of a scalar operand1 to an integer operand2
1619 *
1620 * Both operands need to be finite numbers.
1621 * Needs to have operand1 &ge; 0 and need to have operand2 &ge; 0 if operand1 = 0.
1622 */
1624 SCIP_Real operand1, /**< first operand of operation */
1625 int operand2 /**< second operand of operation */
1626 )
1627{
1628 SCIP_ROUNDMODE roundmode;
1629 SCIP_Real result;
1630
1631 assert(operand1 >= 0.0);
1632
1633 if( operand1 == 0.0 )
1634 {
1635 assert(operand2 >= 0);
1636 if( operand2 == 0 )
1637 return 1.0; /* 0^0 = 1 */
1638 else
1639 return 0.0; /* 0^positive = 0 */
1640 }
1641
1642 /* 1^n = 1, x^0 = 1 */
1643 if( operand1 == 1.0 || operand2 == 0 )
1644 return 1.0;
1645
1646 if( operand2 < 0 )
1647 {
1648 /* x^n = 1 / x^(-n) */
1649 result = SCIPintervalPowerScalarIntegerSup(operand1, -operand2);
1650 assert(result != 0.0);
1651
1652 roundmode = intervalGetRoundingMode();
1654 result = 1.0 / result;
1655 intervalSetRoundingMode(roundmode);
1656 }
1657 else
1658 {
1659 unsigned int n;
1660 SCIP_Real z;
1661
1662 roundmode = intervalGetRoundingMode();
1663
1664 result = 1.0;
1665 n = (unsigned int)operand2;
1666 z = operand1;
1667
1669
1670 /* use a binary exponentiation algorithm:
1671 * consider the binary representation of n: n = sum_i 2^i d_i with d_i \in {0,1}
1672 * then x^n = prod_{i:d_i=1} x^(2^i)
1673 * in the following, we loop over i=1,..., thereby storing x^(2^i) in z
1674 * whenever d_i is 1, we multiply result with x^(2^i) (the current z)
1675 * at the last (highest) i with d_i = 1 we stop, thus having x^n stored in result
1676 *
1677 * the binary representation of n and bit shifting is used for the loop
1678 */
1679 assert(n >= 1);
1680 do
1681 {
1682 if( n & 1 ) /* n is odd (d_i=1), so multiply result with current z (=x^{2^i}) */
1683 {
1684 result = result * z;
1685 n >>= 1;
1686 if( n == 0 )
1687 break;
1688 }
1689 else
1690 n >>= 1;
1691 z = z * z;
1692 }
1693 while( TRUE ); /*lint !e506 */
1694
1695 intervalSetRoundingMode(roundmode);
1696 }
1697
1698 return result;
1699}
1700
1701/** computes upper bound on power of a scalar operand1 to an integer operand2
1702 *
1703 * Both operands need to be finite numbers.
1704 * Needs to have operand1 &ge; 0 and needs to have operand2 &ge; 0 if operand1 = 0.
1705 */
1707 SCIP_Real operand1, /**< first operand of operation */
1708 int operand2 /**< second operand of operation */
1709 )
1710{
1711 SCIP_ROUNDMODE roundmode;
1712 SCIP_Real result;
1713
1714 assert(operand1 >= 0.0);
1715
1716 if( operand1 == 0.0 )
1717 {
1718 assert(operand2 >= 0);
1719 if( operand2 == 0 )
1720 return 1.0; /* 0^0 = 1 */
1721 else
1722 return 0.0; /* 0^positive = 0 */
1723 }
1724
1725 /* 1^n = 1, x^0 = 1 */
1726 if( operand1 == 1.0 || operand2 == 0 )
1727 return 1.0;
1728
1729 if( operand2 < 0 )
1730 {
1731 /* x^n = 1 / x^(-n) */
1732 result = SCIPintervalPowerScalarIntegerInf(operand1, -operand2);
1733 assert(result != 0.0);
1734
1735 roundmode = intervalGetRoundingMode();
1737 result = 1.0 / result;
1738 intervalSetRoundingMode(roundmode);
1739 }
1740 else
1741 {
1742 unsigned int n;
1743 SCIP_Real z;
1744
1745 roundmode = intervalGetRoundingMode();
1746
1747 result = 1.0;
1748 n = (unsigned int)operand2;
1749 z = operand1;
1750
1752
1753 /* use a binary exponentiation algorithm... see comments in SCIPintervalPowerScalarIntegerInf */
1754 assert(n >= 1);
1755 do
1756 {
1757 if( n&1 )
1758 {
1759 result = result * z;
1760 n >>= 1;
1761 if( n == 0 )
1762 break;
1763 }
1764 else
1765 n >>= 1;
1766 z = z * z;
1767 }
1768 while( TRUE ); /*lint !e506 */
1769
1770 intervalSetRoundingMode(roundmode);
1771 }
1772
1773 return result;
1774}
1775
1776/** computes bounds on power of a scalar operand1 to an integer operand2
1777 *
1778 * Both operands need to be finite numbers.
1779 * Needs to have operand1 &ge; 0 and needs to have operand2 &ge; 0 if operand1 = 0.
1780 */
1782 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1783 SCIP_Real operand1, /**< first operand of operation */
1784 int operand2 /**< second operand of operation */
1785 )
1786{
1787 SCIP_ROUNDMODE roundmode;
1788
1789 assert(operand1 >= 0.0);
1790
1791 if( operand1 == 0.0 )
1792 {
1793 assert(operand2 >= 0);
1794 if( operand2 == 0 )
1795 {
1796 SCIPintervalSet(resultant, 1.0); /* 0^0 = 1 */
1797 return;
1798 }
1799 else
1800 {
1801 SCIPintervalSet(resultant, 0.0); /* 0^positive = 0 */
1802 return;
1803 }
1804 }
1805
1806 /* 1^n = 1, x^0 = 1 */
1807 if( operand1 == 1.0 || operand2 == 0 )
1808 {
1809 SCIPintervalSet(resultant, 1.0);
1810 return;
1811 }
1812
1813 if( operand2 < 0 )
1814 {
1815 /* x^n = 1 / x^(-n) */
1816 SCIPintervalPowerScalarInteger(resultant, operand1, -operand2);
1817 assert(resultant->inf > 0.0 || resultant->sup < 0.0);
1818 SCIPintervalReciprocal(SCIP_REAL_MAX, resultant, *resultant); /* value for infinity does not matter, since there should be no 0.0 in the interval, so just use something large enough */
1819 }
1820 else
1821 {
1822 unsigned int n;
1823 SCIP_Real z_inf;
1824 SCIP_Real z_sup;
1825 SCIP_Real result_sup;
1826 SCIP_Real result_inf;
1827
1828 roundmode = intervalGetRoundingMode();
1829
1830 result_inf = 1.0;
1831 result_sup = 1.0;
1832 z_inf = operand1;
1833 z_sup = operand1;
1834 n = (unsigned int)operand2;
1835
1837
1838 /* use a binary exponentiation algorithm... see comments in SCIPintervalPowerScalarIntegerInf
1839 * we compute lower and upper bounds within the same loop
1840 * to get correct lower bounds while rounding mode is upwards, we negate arguments */
1841 assert(n >= 1);
1842 do
1843 {
1844 if( n & 1 )
1845 {
1846 result_inf = negate(negate(result_inf) * z_inf);
1847 result_sup = result_sup * z_sup;
1848 n >>= 1;
1849 if( n == 0 )
1850 break;
1851 }
1852 else
1853 n >>= 1;
1854 z_inf = negate(negate(z_inf) * z_inf);
1855 z_sup = z_sup * z_sup;
1856 }
1857 while( TRUE ); /*lint !e506 */
1858
1859 intervalSetRoundingMode(roundmode);
1860
1861 resultant->inf = result_inf;
1862 resultant->sup = result_sup;
1863 assert(resultant->inf <= resultant->sup);
1864 }
1865}
1866
1867/** stores bounds on the power of a scalar operand1 to a scalar operand2 in resultant
1868 *
1869 * Both operands need to be finite numbers.
1870 * Needs to have operand1 &ge; 0 or operand2 integer and needs to have operand2 &ge; 0 if operand1 = 0.
1871 * @attention we assume a correctly rounded pow(double) function when rounding is to nearest
1872 */
1874 SCIP_INTERVAL* resultant, /**< resultant of operation */
1875 SCIP_Real operand1, /**< first operand of operation */
1876 SCIP_Real operand2 /**< second operand of operation */
1877 )
1878{
1879 SCIP_Real result;
1880
1881 assert(resultant != NULL);
1882
1883 if( operand1 == 0.0 )
1884 {
1885 assert(operand2 >= 0);
1886 if( operand2 == 0 )
1887 {
1888 SCIPintervalSet(resultant, 1.0); /* 0^0 = 1 */
1889 return;
1890 }
1891 else
1892 {
1893 SCIPintervalSet(resultant, 0.0); /* 0^positive = 0 */
1894 return;
1895 }
1896 }
1897
1898 /* 1^n = 1, x^0 = 1 */
1899 if( operand1 == 1.0 || operand2 == 0 )
1900 {
1901 SCIPintervalSet(resultant, 1.0);
1902 return;
1903 }
1904
1905 assert(intervalGetRoundingMode() == SCIP_ROUND_NEAREST); /* usually, no-one should have changed rounding mode */
1906 result = pow(operand1, operand2);
1907
1908 /* to get safe bounds, get the floating point numbers just below and above result */
1909 resultant->inf = SCIPnextafter(result, SCIP_REAL_MIN);
1910 resultant->sup = SCIPnextafter(result, SCIP_REAL_MAX);
1911}
1912
1913/** stores operand1 to the power of the scalar operand2 in resultant
1914 * @attention we assume a correctly rounded pow(double) function when rounding is to nearest
1915 */
1917 SCIP_Real infinity, /**< value for infinity */
1918 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
1919 SCIP_INTERVAL operand1, /**< first operand of operation */
1920 SCIP_Real operand2 /**< second operand of operation */
1921 )
1922{
1923 SCIP_Bool op2isint;
1924
1925 assert(resultant != NULL);
1926 assert(!SCIPintervalIsEmpty(infinity, operand1));
1927
1928 if( operand2 == infinity )
1929 {
1930 /* 0^infinity = 0
1931 * +^infinity = infinity
1932 * -^infinity = -infinity
1933 */
1934 if( operand1.inf < 0.0 )
1935 resultant->inf = -infinity;
1936 else
1937 resultant->inf = 0.0;
1938 if( operand1.sup > 0.0 )
1939 resultant->sup = infinity;
1940 else
1941 resultant->sup = 0.0;
1942 return;
1943 }
1944
1945 if( operand2 == 0.0 )
1946 { /* special case, since x^0 = 1 for x != 0, but 0^0 = 0 */
1947 if( operand1.inf == 0.0 && operand1.sup == 0.0 )
1948 {
1949 resultant->inf = 0.0;
1950 resultant->sup = 0.0;
1951 }
1952 else if( operand1.inf <= 0.0 || operand1.sup >= 0.0 )
1953 { /* 0.0 in x gives [0,1] */
1954 resultant->inf = 0.0;
1955 resultant->sup = 1.0;
1956 }
1957 else
1958 { /* 0.0 outside x gives [1,1] */
1959 resultant->inf = 1.0;
1960 resultant->sup = 1.0;
1961 }
1962 return;
1963 }
1964
1965 if( operand2 == 1.0 )
1966 {
1967 /* x^1 = x */
1968 *resultant = operand1;
1969 return;
1970 }
1971
1972 op2isint = (ceil(operand2) == operand2);
1973
1974 if( !op2isint && operand1.inf < 0.0 )
1975 { /* x^n with x negative not defined for n not integer*/
1976 operand1.inf = 0.0;
1977 if( operand1.sup < operand1.inf )
1978 {
1979 SCIPintervalSetEmpty(resultant);
1980 return;
1981 }
1982 }
1983
1984 if( operand1.inf >= 0.0 )
1985 { /* easy case: x^n with x >= 0 */
1986 if( operand2 >= 0.0 )
1987 {
1988 /* inf^+ = inf */
1989 if( operand1.inf >= infinity )
1990 resultant->inf = infinity;
1991 else if( operand1.inf > 0.0 )
1992 {
1993 assert(intervalGetRoundingMode() == SCIP_ROUND_NEAREST); /* usually, no-one should have changed rounding mode */
1994 resultant->inf = SCIPnextafter(pow(operand1.inf, operand2), SCIP_REAL_MIN);
1995 }
1996 else
1997 resultant->inf = 0.0;
1998
1999 if( operand1.sup >= infinity )
2000 resultant->sup = infinity;
2001 else if( operand1.sup > 0.0 )
2002 {
2003 assert(intervalGetRoundingMode() == SCIP_ROUND_NEAREST); /* usually, no-one should have changed rounding mode */
2004 resultant->sup = SCIPnextafter(pow(operand1.sup, operand2), SCIP_REAL_MAX);
2005 }
2006 else
2007 resultant->sup = 0.0;
2008 }
2009 else
2010 {
2011 if( operand1.sup >= infinity )
2012 resultant->inf = 0.0;
2013 else if( operand1.sup == 0.0 )
2014 {
2015 /* x^(negative even) = infinity for x->0 (from both sides),
2016 * but x^(negative odd) = -infinity for x->0 from left side */
2017 if( ceil(operand2/2) == operand2/2 )
2018 resultant->inf = infinity;
2019 else
2020 resultant->inf = -infinity;
2021 }
2022 else
2023 {
2024 assert(intervalGetRoundingMode() == SCIP_ROUND_NEAREST); /* usually, no-one should have changed rounding mode */
2025 resultant->inf = SCIPnextafter(pow(operand1.sup, operand2), SCIP_REAL_MIN);
2026 }
2027
2028 /* 0^(negative) = infinity */
2029 if( operand1.inf == 0.0 )
2030 resultant->sup = infinity;
2031 else
2032 {
2033 assert(intervalGetRoundingMode() == SCIP_ROUND_NEAREST); /* usually, no-one should have changed rounding mode */
2034 resultant->sup = SCIPnextafter(pow(operand1.inf, operand2), SCIP_REAL_MAX);
2035 }
2036 }
2037 }
2038 else if( operand1.sup <= 0.0 )
2039 { /* more difficult case: x^n with x < 0; we now know, that n is integer */
2040 assert(op2isint);
2041 if( operand2 >= 0.0 && ceil(operand2/2) == operand2/2 )
2042 {
2043 /* x^n with n>=2 and even -> x^n is monotonically decreasing for x < 0 */
2044 if( operand1.sup == -infinity )
2045 /* (-inf)^n = inf */
2046 resultant->inf = infinity;
2047 else
2048 resultant->inf = SCIPintervalPowerScalarIntegerInf(-operand1.sup, (int)operand2);
2049
2050 if( operand1.inf <= -infinity )
2051 resultant->sup = infinity;
2052 else
2053 resultant->sup = SCIPintervalPowerScalarIntegerSup(-operand1.inf, (int)operand2);
2054 }
2055 else if( operand2 <= 0.0 && ceil(operand2/2) != operand2/2 )
2056 {
2057 /* x^n with n<=-1 and odd -> x^n = 1/x^(-n) is monotonically decreasing for x<0 */
2058 if( operand1.sup == -infinity )
2059 /* (-inf)^n = 1/(-inf)^(-n) = 1/(-inf) = 0 */
2060 resultant->inf = 0.0;
2061 else if( operand1.sup == 0.0 )
2062 /* x^n -> -infinity for x->0 from left */
2063 resultant->inf = -infinity;
2064 else
2065 resultant->inf = -SCIPintervalPowerScalarIntegerSup(-operand1.sup, (int)operand2);
2066
2067 if( operand1.inf <= -infinity )
2068 /* (-inf)^n = 1/(-inf)^(-n) = 1/(-inf) = 0 */
2069 resultant->sup = 0.0;
2070 else if( operand1.inf == 0.0 )
2071 /* x^n -> infinity for x->0 from right */
2072 resultant->sup = infinity;
2073 else
2074 resultant->sup = -SCIPintervalPowerScalarIntegerInf(-operand1.inf, (int)operand2);
2075 }
2076 else if( operand2 >= 0.0 )
2077 {
2078 /* x^n with n>0 and odd -> x^n is monotonically increasing for x<0 */
2079 if( operand1.inf <= -infinity )
2080 resultant->inf = -infinity;
2081 else
2082 resultant->inf = -SCIPintervalPowerScalarIntegerSup(-operand1.inf, (int)operand2);
2083
2084 if( operand1.sup <= -infinity )
2085 resultant->sup = -infinity;
2086 else
2087 resultant->sup = -SCIPintervalPowerScalarIntegerInf(-operand1.sup, (int)operand2);
2088 }
2089 else
2090 {
2091 /* x^n with n<0 and even -> x^n is monotonically increasing for x<0 */
2092 if( operand1.inf <= -infinity )
2093 resultant->inf = 0.0;
2094 else if( operand1.inf == 0.0 )
2095 /* x^n -> infinity for x->0 from both sides */
2096 resultant->inf = infinity;
2097 else
2098 resultant->inf = SCIPintervalPowerScalarIntegerSup(-operand1.inf, (int)operand2);
2099
2100 if( operand1.sup <= -infinity )
2101 resultant->sup = 0.0;
2102 else if( operand1.sup == 0.0 )
2103 /* x^n -> infinity for x->0 from both sides */
2104 resultant->sup = infinity;
2105 else
2106 resultant->sup = SCIPintervalPowerScalarIntegerSup(-operand1.sup, (int)operand2);
2107 }
2108 assert(resultant->inf <= resultant->sup || resultant->inf >= infinity || resultant->sup <= -infinity);
2109 }
2110 else
2111 { /* similar difficult case: x^n with x in [<0, >0], but n is integer */
2112 assert(op2isint); /* otherwise we had set operand1.inf == 0.0, which was handled in first case */
2113 if( operand2 >= 0.0 && operand2/2 == ceil(operand2/2) )
2114 {
2115 /* n even positive integer */
2116 resultant->inf = 0.0;
2117 if( operand1.inf == -infinity || operand1.sup == infinity )
2118 resultant->sup = infinity;
2119 else
2120 resultant->sup = SCIPintervalPowerScalarIntegerSup(MAX(-operand1.inf, operand1.sup), (int)operand2);
2121 }
2122 else if( operand2 <= 0.0 && ceil(operand2/2) == operand2/2 )
2123 {
2124 /* n even negative integer */
2125 resultant->sup = infinity; /* since 0^n = infinity */
2126 if( operand1.inf == -infinity || operand1.sup == infinity )
2127 resultant->inf = 0.0;
2128 else
2129 resultant->inf = SCIPintervalPowerScalarIntegerInf(MAX(-operand1.inf, operand1.sup), (int)operand2);
2130 }
2131 else if( operand2 >= 0.0 )
2132 {
2133 /* n odd positive integer, so monotonically increasing function */
2134 if( operand1.inf == -infinity )
2135 resultant->inf = -infinity;
2136 else
2137 resultant->inf = -SCIPintervalPowerScalarIntegerSup(-operand1.inf, (int)operand2);
2138 if( operand1.sup == infinity )
2139 resultant->sup = infinity;
2140 else
2141 resultant->sup = SCIPintervalPowerScalarIntegerSup(operand1.sup, (int)operand2);
2142 }
2143 else
2144 {
2145 /* n odd negative integer:
2146 * x^n -> -infinity for x->0 from left
2147 * x^n -> infinity for x->0 from right */
2148 resultant->inf = -infinity;
2149 resultant->sup = infinity;
2150 }
2151 }
2152
2153 /* if value for infinity is too small, relax intervals so they do not appear empty */
2154 if( resultant->inf > infinity )
2155 resultant->inf = infinity;
2156 if( resultant->sup < -infinity )
2157 resultant->sup = -infinity;
2158}
2159
2160/** given an interval for the image of a power operation, computes an interval for the origin
2161 *
2162 * That is, for \f$y = x^p\f$ with the exponent \f$p\f$ a given scalar and \f$y\f$ = `image` a given interval,
2163 * computes \f$x \subseteq \text{basedomain}\f$ such that \f$y \in x^p\f$ and such that for all \f$z \in \text{basedomain} \setminus x: z^p \not \in y\f$.
2164 */
2166 SCIP_Real infinity, /**< value for infinity */
2167 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2168 SCIP_INTERVAL basedomain, /**< domain of base */
2169 SCIP_Real exponent, /**< exponent */
2170 SCIP_INTERVAL image /**< interval image of power */
2171 )
2172{
2173 SCIP_INTERVAL tmp;
2174 SCIP_INTERVAL exprecip;
2175
2176 assert(resultant != NULL);
2177 assert(image.inf <= image.sup);
2178 assert(basedomain.inf <= basedomain.sup);
2179
2180 if( exponent == 0.0 )
2181 {
2182 /* exponent is 0.0 */
2183 if( image.inf <= 1.0 && image.sup >= 1.0 )
2184 {
2185 /* 1 in image -> resultant = entire */
2186 *resultant = basedomain;
2187 }
2188 else if( image.inf <= 0.0 && image.sup >= 0.0 )
2189 {
2190 /* 0 in image, 1 not in image -> resultant = 0 (provided 0^0 = 0 ???)
2191 * -> resultant = {0} intersected with basedomain */
2192 SCIPintervalSetBounds(resultant, MAX(0.0, basedomain.inf), MIN(0.0, basedomain.sup));
2193 }
2194 else
2195 {
2196 /* 0 and 1 not in image -> resultant = empty */
2197 SCIPintervalSetEmpty(resultant);
2198 }
2199 return;
2200 }
2201
2202 /* i = b^e
2203 * i >= 0 -> b = i^(1/e) [union -i^(1/e), if e is even]
2204 * i < 0, e odd integer -> b = -(-i)^(1/e)
2205 * i < 0, e even integer or fractional -> empty
2206 */
2207
2208 SCIPintervalSetBounds(&exprecip, exponent, exponent);
2209 SCIPintervalReciprocal(infinity, &exprecip, exprecip);
2210
2211 /* invert positive part of image, if any */
2212 if( image.sup >= 0.0 )
2213 {
2214 SCIPintervalSetBounds(&tmp, MAX(image.inf, 0.0), image.sup);
2215 SCIPintervalPower(infinity, resultant, tmp, exprecip);
2216 if( basedomain.inf <= -resultant->inf && EPSISINT(exponent, 0.0) && (int)exponent % 2 == 0 ) /*lint !e835 */
2217 {
2218 if( basedomain.sup < resultant->inf )
2219 SCIPintervalSetBounds(resultant, -resultant->sup, -resultant->inf);
2220 else
2221 SCIPintervalSetBounds(resultant, -resultant->sup, resultant->sup);
2222 }
2223
2224 SCIPintervalIntersect(resultant, *resultant, basedomain);
2225 }
2226 else
2227 SCIPintervalSetEmpty(resultant);
2228
2229 /* invert negative part of image, if any and if base can take negative value and if exponent is such that negative values are possible */
2230 if( image.inf < 0.0 && basedomain.inf < 0.0 && EPSISINT(exponent, 0.0) && ((int)exponent % 2 != 0) ) /*lint !e835 */
2231 {
2232 SCIPintervalSetBounds(&tmp, MAX(-image.sup, 0.0), -image.inf);
2233 SCIPintervalPower(infinity, &tmp, tmp, exprecip);
2234 SCIPintervalSetBounds(&tmp, -tmp.sup, -tmp.inf);
2235 SCIPintervalIntersect(&tmp, basedomain, tmp);
2236 SCIPintervalUnify(resultant, *resultant, tmp);
2237 }
2238}
2239
2240/** stores operand1 to the signed power of the scalar positive operand2 in resultant
2241 *
2242 * The signed power of x w.r.t. an exponent n &ge; 0 is given as \f$\mathrm{sign}(x) |x|^n\f$.
2243 *
2244 * @attention we assume correctly rounded sqrt(double) and pow(double) functions when rounding is to nearest
2245 */
2247 SCIP_Real infinity, /**< value for infinity */
2248 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2249 SCIP_INTERVAL operand1, /**< first operand of operation */
2250 SCIP_Real operand2 /**< second operand of operation */
2251 )
2252{
2253 SCIP_ROUNDMODE roundmode;
2254 assert(resultant != NULL);
2255
2256 assert(!SCIPintervalIsEmpty(infinity, operand1));
2257 assert(operand2 >= 0.0);
2258
2259 if( operand2 == infinity )
2260 {
2261 /* 0^infinity = 0
2262 * +^infinity = infinity
2263 *-+^infinity = -infinity
2264 */
2265 if( operand1.inf < 0.0 )
2266 resultant->inf = -infinity;
2267 else
2268 resultant->inf = 0.0;
2269 if( operand1.sup > 0.0 )
2270 resultant->sup = infinity;
2271 else
2272 resultant->sup = 0.0;
2273 return;
2274 }
2275
2276 if( operand2 == 0.0 )
2277 {
2278 /* special case, since x^0 = 1 for x != 0, but 0^0 = 0 */
2279 if( operand1.inf < 0.0 )
2280 resultant->inf = -1.0;
2281 else if( operand1.inf == 0.0 )
2282 resultant->inf = 0.0;
2283 else
2284 resultant->inf = 1.0;
2285
2286 if( operand1.sup < 0.0 )
2287 resultant->sup = -1.0;
2288 else if( operand1.sup == 0.0 )
2289 resultant->sup = 0.0;
2290 else
2291 resultant->sup = 1.0;
2292
2293 return;
2294 }
2295
2296 if( operand2 == 1.0 )
2297 { /* easy case that should run fast */
2298 *resultant = operand1;
2299 return;
2300 }
2301
2302 roundmode = intervalGetRoundingMode();
2303
2304 if( operand2 == 2.0 )
2305 { /* common case where pow can easily be avoided */
2306 if( operand1.inf <= -infinity )
2307 {
2308 resultant->inf = -infinity;
2309 }
2310 else if( operand1.inf >= infinity )
2311 {
2312 resultant->inf = infinity;
2313 }
2314 else if( operand1.inf > 0.0 )
2315 {
2317 resultant->inf = operand1.inf * operand1.inf;
2318 }
2319 else
2320 {
2321 /* need upwards since we negate result of multiplication */
2323 resultant->inf = negate(operand1.inf * operand1.inf);
2324 }
2325
2326 if( operand1.sup >= infinity )
2327 {
2328 resultant->sup = infinity;
2329 }
2330 else if( operand1.sup <= -infinity )
2331 {
2332 resultant->sup = -infinity;
2333 }
2334 else if( operand1.sup > 0.0 )
2335 {
2337 resultant->sup = operand1.sup * operand1.sup;
2338 }
2339 else
2340 {
2341 /* need downwards since we negate result of multiplication */
2343 resultant->sup = negate(operand1.sup * operand1.sup);
2344 }
2345 assert(resultant->inf <= resultant->sup);
2346 }
2347 else if( operand2 == 0.5 )
2348 { /* another common case where pow can easily be avoided */
2349 if( operand1.inf <= -infinity )
2350 resultant->inf = -infinity;
2351 else if( operand1.inf >= infinity )
2352 resultant->inf = infinity;
2353 else if( operand1.inf >= 0.0 )
2354 {
2356 resultant->inf = SCIPnextafter(sqrt( operand1.inf), SCIP_REAL_MIN);
2357 }
2358 else
2359 {
2361 resultant->inf = -SCIPnextafter(sqrt(-operand1.inf), SCIP_REAL_MAX);
2362 }
2363
2364 if( operand1.sup >= infinity )
2365 resultant->sup = infinity;
2366 else if( operand1.sup <= -infinity )
2367 resultant->sup = -infinity;
2368 else if( operand1.sup > 0.0 )
2369 {
2371 resultant->sup = SCIPnextafter(sqrt( operand1.sup), SCIP_REAL_MAX);
2372 }
2373 else
2374 {
2376 resultant->sup = -SCIPnextafter(sqrt(-operand1.sup), SCIP_REAL_MAX);
2377 }
2378 assert(resultant->inf <= resultant->sup);
2379 }
2380 else
2381 {
2382 if( operand1.inf <= -infinity )
2383 resultant->inf = -infinity;
2384 else if( operand1.inf >= infinity )
2385 resultant->inf = infinity;
2386 else if( operand1.inf > 0.0 )
2387 {
2389 resultant->inf = SCIPnextafter(pow( operand1.inf, operand2), SCIP_REAL_MIN);
2390 }
2391 else
2392 {
2394 resultant->inf = -SCIPnextafter(pow(-operand1.inf, operand2), SCIP_REAL_MAX);
2395 }
2396
2397 if( operand1.sup >= infinity )
2398 resultant->sup = infinity;
2399 else if( operand1.sup <= -infinity )
2400 resultant->sup = -infinity;
2401 else if( operand1.sup > 0.0 )
2402 {
2404 resultant->sup = SCIPnextafter(pow( operand1.sup, operand2), SCIP_REAL_MAX);
2405 }
2406 else
2407 {
2409 resultant->sup = -SCIPnextafter(pow(-operand1.sup, operand2), SCIP_REAL_MIN);
2410 }
2411 }
2412
2413 intervalSetRoundingMode(roundmode);
2414}
2415
2416/** computes the reciprocal of an interval
2417 */
2419 SCIP_Real infinity, /**< value for infinity */
2420 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2421 SCIP_INTERVAL operand /**< operand of operation */
2422 )
2423{
2424 SCIP_ROUNDMODE roundmode;
2425
2426 assert(resultant != NULL);
2427 assert(!SCIPintervalIsEmpty(infinity, operand));
2428
2429 if( operand.inf == 0.0 && operand.sup == 0.0 )
2430 { /* 1/0 = [-inf,inf] */
2431 resultant->inf = infinity;
2432 resultant->sup = -infinity;
2433 return;
2434 }
2435
2436 roundmode = intervalGetRoundingMode();
2437
2438 if( operand.inf >= 0.0 )
2439 { /* 1/x with x >= 0 */
2440 if( operand.sup >= infinity )
2441 resultant->inf = 0.0;
2442 else
2443 {
2445 resultant->inf = 1.0 / operand.sup;
2446 }
2447
2448 if( operand.inf >= infinity )
2449 resultant->sup = 0.0;
2450 else if( operand.inf == 0.0 )
2451 resultant->sup = infinity;
2452 else
2453 {
2455 resultant->sup = 1.0 / operand.inf;
2456 }
2457
2458 intervalSetRoundingMode(roundmode);
2459 }
2460 else if( operand.sup <= 0.0 )
2461 { /* 1/x with x <= 0 */
2462 if( operand.sup <= -infinity )
2463 resultant->inf = 0.0;
2464 else if( operand.sup == 0.0 )
2465 resultant->inf = -infinity;
2466 else
2467 {
2469 resultant->inf = 1.0 / operand.sup;
2470 }
2471
2472 if( operand.inf <= -infinity )
2473 resultant->sup = infinity;
2474 else
2475 {
2477 resultant->sup = 1.0 / operand.inf;
2478 }
2479 intervalSetRoundingMode(roundmode);
2480 }
2481 else
2482 { /* 1/x with x in [-,+] is division by zero */
2483 resultant->inf = -infinity;
2484 resultant->sup = infinity;
2485 }
2486}
2487
2488/** stores exponential of operand in resultant
2489 * @attention we assume a correctly rounded exp(double) function when rounding is to nearest
2490 */
2492 SCIP_Real infinity, /**< value for infinity */
2493 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2494 SCIP_INTERVAL operand /**< operand of operation */
2495 )
2496{
2497 assert(resultant != NULL);
2498 assert(!SCIPintervalIsEmpty(infinity, operand));
2499
2500 if( operand.sup <= -infinity )
2501 {
2502 resultant->inf = 0.0;
2503 resultant->sup = 0.0;
2504 return;
2505 }
2506
2507 if( operand.inf >= infinity )
2508 {
2509 resultant->inf = infinity;
2510 resultant->sup = infinity;
2511 return;
2512 }
2513
2514 if( operand.inf == operand.sup )
2515 {
2516 if( operand.inf == 0.0 )
2517 {
2518 resultant->inf = 1.0;
2519 resultant->sup = 1.0;
2520 }
2521 else
2522 {
2523 SCIP_Real tmp;
2524
2526 tmp = exp(operand.inf);
2527 resultant->inf = tmp > 0.0 ? SCIPnextafter(tmp, SCIP_REAL_MIN) : 0.0;
2528 assert(resultant->inf >= 0.0);
2529 resultant->sup = SCIPnextafter(tmp, SCIP_REAL_MAX);
2530
2531 return;
2532 }
2533 }
2534
2535 if( operand.inf <= -infinity )
2536 {
2537 resultant->inf = 0.0;
2538 }
2539 else if( operand.inf == 0.0 )
2540 {
2541 resultant->inf = 1.0;
2542 }
2543 else
2544 {
2545 SCIP_Real tmp;
2546
2548 tmp = exp(operand.inf);
2549 resultant->inf = tmp > 0.0 ? SCIPnextafter(tmp, SCIP_REAL_MIN) : 0.0;
2550 /* make sure we do not exceed value for infinity, so interval is not declared as empty if inf and sup are both > infinity */
2551 if( resultant->inf >= infinity )
2552 resultant->inf = infinity;
2553 }
2554
2555 if( operand.sup >= infinity )
2556 {
2557 resultant->sup = infinity;
2558 }
2559 else if( operand.sup == 0.0 )
2560 {
2561 resultant->sup = 1.0;
2562 }
2563 else
2564 {
2566 resultant->sup = SCIPnextafter(exp(operand.sup), SCIP_REAL_MAX);
2567 if( resultant->sup < -infinity )
2568 resultant->sup = -infinity;
2569 }
2570}
2571
2572/** stores natural logarithm of operand in resultant
2573 * @attention we assume a correctly rounded log(double) function when rounding is to nearest
2574 */
2576 SCIP_Real infinity, /**< value for infinity */
2577 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2578 SCIP_INTERVAL operand /**< operand of operation */
2579 )
2580{
2581 assert(resultant != NULL);
2582 assert(!SCIPintervalIsEmpty(infinity, operand));
2583
2584 /* if operand.sup == 0.0, we could return -inf in resultant->sup, but that
2585 * seems of little use and just creates problems somewhere else, e.g., #1230
2586 */
2587 if( operand.sup <= 0.0 )
2588 {
2589 SCIPintervalSetEmpty(resultant);
2590 return;
2591 }
2592
2593 if( operand.inf == operand.sup )
2594 {
2595 if( operand.sup == 1.0 )
2596 {
2597 resultant->inf = 0.0;
2598 resultant->sup = 0.0;
2599 }
2600 else
2601 {
2602 SCIP_Real tmp;
2603
2605 tmp = log(operand.inf);
2606 resultant->inf = SCIPnextafter(tmp, SCIP_REAL_MIN);
2607 resultant->sup = SCIPnextafter(tmp, SCIP_REAL_MAX);
2608 }
2609
2610 return;
2611 }
2612
2613 if( operand.inf <= 0.0 )
2614 {
2615 resultant->inf = -infinity;
2616 }
2617 else if( operand.inf == 1.0 )
2618 {
2619 resultant->inf = 0.0;
2620 }
2621 else
2622 {
2624 resultant->inf = SCIPnextafter(log(operand.inf), SCIP_REAL_MIN);
2625 }
2626
2627 if( operand.sup >= infinity )
2628 {
2629 resultant->sup = infinity;
2630 }
2631 else if( operand.sup == 1.0 )
2632 {
2633 resultant->sup = 0.0;
2634 }
2635 else
2636 {
2638 resultant->sup = SCIPnextafter(log(operand.sup), SCIP_REAL_MAX);
2639 }
2640}
2641
2642/** stores minimum of operands in resultant */
2644 SCIP_Real infinity, /**< value for infinity */
2645 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2646 SCIP_INTERVAL operand1, /**< first operand of operation */
2647 SCIP_INTERVAL operand2 /**< second operand of operation */
2648 )
2649{
2650 assert(resultant != NULL);
2651 assert(!SCIPintervalIsEmpty(infinity, operand1));
2652 assert(!SCIPintervalIsEmpty(infinity, operand2));
2653
2654 resultant->inf = MIN(operand1.inf, operand2.inf);
2655 resultant->sup = MIN(operand1.sup, operand2.sup);
2656}
2657
2658/** stores maximum of operands in resultant */
2660 SCIP_Real infinity, /**< value for infinity */
2661 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2662 SCIP_INTERVAL operand1, /**< first operand of operation */
2663 SCIP_INTERVAL operand2 /**< second operand of operation */
2664 )
2665{
2666 assert(resultant != NULL);
2667 assert(!SCIPintervalIsEmpty(infinity, operand1));
2668 assert(!SCIPintervalIsEmpty(infinity, operand2));
2669
2670 resultant->inf = MAX(operand1.inf, operand2.inf);
2671 resultant->sup = MAX(operand1.sup, operand2.sup);
2672}
2673
2674/** returns the maximum of the absolute values of the infimum and supremum of the interval */
2676 SCIP_INTERVAL interval /**< interval */
2677 )
2678{
2679 return MAX(ABS(interval.sup), ABS(interval.inf));
2680}
2681
2682/** stores absolute value of operand in resultant */
2684 SCIP_Real infinity, /**< value for infinity */
2685 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2686 SCIP_INTERVAL operand /**< operand of operation */
2687 )
2688{
2689 assert(resultant != NULL);
2690 assert(!SCIPintervalIsEmpty(infinity, operand));
2691
2692 if( operand.inf <= 0.0 && operand.sup >= 0.0)
2693 {
2694 resultant->inf = 0.0;
2695 resultant->sup = MAX(-operand.inf, operand.sup);
2696 }
2697 else if( operand.inf > 0.0 )
2698 {
2699 *resultant = operand;
2700 }
2701 else
2702 {
2703 resultant->inf = -operand.sup;
2704 resultant->sup = -operand.inf;
2705 }
2706}
2707
2708/* double precision lower and upper bounds on pi
2709 * taken from boost::numeric::interval_lib::constants
2710 * MSVC refuses to evaluate this at compile time
2711 */
2712#ifndef _MSC_VER
2713static const double pi_d_l = (3373259426.0 + 273688.0 / (1<<21)) / (1<<30); /*lint !e790*/
2714static const double pi_d_u = (3373259426.0 + 273689.0 / (1<<21)) / (1<<30); /*lint !e790*/
2715#else
2716#define pi_d_l ((3373259426.0 + 273688.0 / (1<<21)) / (1<<30))
2717#define pi_d_u ((3373259426.0 + 273689.0 / (1<<21)) / (1<<30))
2718#endif
2719
2720/** stores sine value of operand in resultant */
2722 SCIP_Real infinity, /**< value for infinity */
2723 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2724 SCIP_INTERVAL operand /**< operand of operation */
2725 )
2726{
2727 /* the function evaluates sine transforming it to a cosine via sin(x) = cos(x-pi/2) = -cos(x+pi/2) */
2728 SCIP_INTERVAL pihalf;
2729 SCIP_INTERVAL shiftedop;
2730
2731 /* sin(x) = cos(x-pi/2) = -cos(x+pi/2)*/
2733 SCIPintervalMulScalar(infinity, &pihalf, pihalf, 0.5);
2734
2735 /* intervalCos() will move operand.inf into [0,pi]
2736 * if we can achieve this here by add pi/2 instead of subtracting it, then use the sin(x) = -cos(x+pi/2) identity
2737 */
2738 if( operand.inf < 0.0 && operand.inf > -pi_d_l )
2739 {
2740 SCIP_Real tmp;
2741
2742 SCIPintervalAdd(infinity, &shiftedop, operand, pihalf);
2743 SCIPintervalCos(infinity, resultant, shiftedop);
2744
2745 tmp = -resultant->sup;
2746 resultant->sup = -resultant->inf;
2747 resultant->inf = tmp;
2748 }
2749 else
2750 {
2751 SCIPintervalSub(infinity, &shiftedop, operand, pihalf);
2752 SCIPintervalCos(infinity, resultant, shiftedop);
2753 }
2754
2755 /* some correction if inf or sup is 0, then sin(0) = 0 would be nice */
2756 if( operand.inf == 0.0 && operand.sup < pi_d_l )
2757 resultant->inf = 0.0;
2758 else if( operand.sup == 0.0 && operand.inf > -pi_d_l )
2759 resultant->sup = 0.0;
2760}
2761
2762/** stores cosine value of operand in resultant */
2764 SCIP_Real infinity, /**< value for infinity */
2765 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2766 SCIP_INTERVAL operand /**< operand of operation */
2767 )
2768{
2769 /* this implementation follows boost::numeric::cos
2770 * cos is decreasing in [0, pi] and increasing in [pi, 2pi].
2771 * If operand = [a,b] and a is in [0, pi], then
2772 * cos([a,b]) = [-1, 1] if b >= 2pi
2773 * cos([a,b]) = [-1, max(cos(a), cos(b))] if b is in [pi, 2pi]
2774 * cos([a,b]) = [cos(b), cos(a)] if b is in [0, pi]
2775 *
2776 * To make sure that a is always between [0, pi] we use the identity cos(x) = (-1)^k cos(x + k pi), i.e.,
2777 * we compute k such that a + k pi \in [0,pi], compute cos([a,b] + k pi) and then multiply by (-1)^k.
2778 */
2779 SCIP_ROUNDMODE roundmode;
2780 SCIP_Real negwidth;
2781 SCIP_Real k = 0.0;
2782
2783 assert(resultant != NULL);
2784 assert(!SCIPintervalIsEmpty(infinity, operand));
2785
2786 SCIPdebugMessage("cos([%.16g,%.16g])\n", operand.inf, operand.sup);
2787
2788 if( operand.inf == operand.sup )
2789 {
2790 SCIP_Real tmp;
2791
2793 tmp = cos(operand.inf);
2794 resultant->inf = SCIPnextafter(tmp, SCIP_REAL_MIN);
2795 resultant->sup = SCIPnextafter(tmp, SCIP_REAL_MAX);
2796 return;
2797 }
2798
2799 /* set interval to [-1,1] if we cannot reliably work out the difference between inf and sup
2800 * double precision has almost 16 digits of precision; for now cut off at 12
2801 */
2802 if( operand.sup > 1e12 || operand.inf < -1e12 )
2803 {
2804 SCIPintervalSetBounds(resultant, -1.0, 1.0);
2805 return;
2806 }
2807
2808 roundmode = SCIPintervalGetRoundingMode();
2809
2810 /* set interval to [-1,1] if width is at least 2 pi */
2812 negwidth = operand.inf - operand.sup;
2813 if( -negwidth >= 2.0*pi_d_l )
2814 {
2815 SCIPintervalSetBounds(resultant, -1.0, 1.0);
2816 SCIPintervalSetRoundingMode(roundmode);
2817 return;
2818 }
2819
2820 /* get operand.inf into [0,pi] */
2821 if( operand.inf < 0.0 || operand.inf >= pi_d_l )
2822 {
2823 SCIP_INTERVAL tmp;
2824
2825 k = floor((operand.inf / (operand.inf < 0.0 ? pi_d_l : pi_d_u)));
2826
2827 /* operand <- operand - k * pi */
2829 SCIPintervalMulScalar(infinity, &tmp, tmp, k);
2830 SCIPintervalSub(infinity, &operand, operand, tmp);
2831 }
2832 assert(operand.inf >= 0.0);
2833 assert(operand.inf <= pi_d_u);
2834
2835 SCIPdebugMessage("shifted operand by %g*pi = [%.16g,%.16g])\n", k, operand.inf, operand.sup);
2836
2837 SCIPintervalSetRoundingMode(roundmode);
2838
2839 if( operand.sup <= pi_d_l )
2840 {
2841 /* monotone decreasing */
2842 resultant->inf = SCIPnextafter(cos(operand.sup), SCIP_REAL_MIN);
2843 resultant->inf = MAX(-1.0, resultant->inf);
2844 if( operand.inf == 0.0 )
2845 resultant->sup = 1.0;
2846 else
2847 {
2848 resultant->sup = SCIPnextafter(cos(operand.inf), SCIP_REAL_MAX);
2849 resultant->sup = MIN( 1.0, resultant->sup);
2850 }
2851 SCIPdebugMessage("cos([%.16g,%.16g]) = [%.16g,%.16g]\n", operand.inf, operand.sup, resultant->inf, resultant->sup);
2852 }
2853 else if( operand.sup <= 2*pi_d_l )
2854 {
2855 /* inf <= pi, sup >= pi: minimum at pi (=-1), maximum at inf or sup */
2856 resultant->inf = -1.0;
2857 if( operand.inf == 0.0 )
2858 resultant->sup = 1.0;
2859 else
2860 {
2861 SCIP_Real cinf;
2862 SCIP_Real csup;
2863
2864 cinf = cos(operand.inf);
2865 csup = cos(operand.sup);
2866 resultant->sup = SCIPnextafter(MAX(cinf, csup), SCIP_REAL_MAX);
2867 resultant->sup = MIN(1.0, resultant->sup);
2868 }
2869 SCIPdebugMessage("cos([%.16g,%.16g]) = [%.16g,%.16g]\n", operand.inf, operand.sup, resultant->inf, resultant->sup);
2870 }
2871 else
2872 {
2873 SCIPintervalSetBounds(resultant, -1.0, 1.0);
2874 }
2875
2876 /* back to original operand using cos(x + k pi) = (-1)^k cos(x) */
2877 if( fmod(k, 2.0) != 0.0 )
2878 {
2879 SCIP_Real tmp = -resultant->sup;
2880 resultant->sup = -resultant->inf;
2881 resultant->inf = tmp;
2882 SCIPdebugMessage("shifted back -> [%.16g,%.16g]\n", resultant->inf, resultant->sup);
2883 }
2884
2885 assert(resultant->inf >= -1.0);
2886 assert(resultant->sup <= 1.0);
2887}
2888
2889/** stores sign of operand in resultant */
2891 SCIP_Real infinity, /**< value for infinity */
2892 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2893 SCIP_INTERVAL operand /**< operand of operation */
2894 )
2895{
2896 assert(resultant != NULL);
2897 assert(!SCIPintervalIsEmpty(infinity, operand));
2898
2899 if( operand.sup < 0.0 )
2900 {
2901 resultant->inf = -1.0;
2902 resultant->sup = -1.0;
2903 }
2904 else if( operand.inf >= 0.0 )
2905 {
2906 resultant->inf = 1.0;
2907 resultant->sup = 1.0;
2908 }
2909 else
2910 {
2911 resultant->inf = -1.0;
2912 resultant->sup = 1.0;
2913 }
2914}
2915
2916/** stores entropy of operand in resultant */
2918 SCIP_Real infinity, /**< value for infinity */
2919 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
2920 SCIP_INTERVAL operand /**< operand of operation */
2921 )
2922{
2923 SCIP_Real loginf;
2924 SCIP_Real logsup;
2925 SCIP_Real infcand1 = 0.0;
2926 SCIP_Real infcand2 = 0.0;
2927 SCIP_Real supcand1 = 0.0;
2928 SCIP_Real supcand2 = 0.0;
2929 SCIP_Real extr;
2930 SCIP_Real inf;
2931 SCIP_Real sup;
2932
2933 assert(resultant != NULL);
2934 assert(!SCIPintervalIsEmpty(infinity, operand));
2935
2936 /* check whether the domain is empty */
2937 if( operand.sup < 0.0 )
2938 {
2939 SCIPintervalSetEmpty(resultant);
2940 return;
2941 }
2942
2943 /* handle special case of domain being [0,0] */
2944 if( operand.sup == 0.0 )
2945 {
2946 SCIPintervalSet(resultant, 0.0);
2947 return;
2948 }
2949
2950 /* compute infimum = MIN(entropy(op.inf), entropy(op.sup)) and supremum = MAX(MIN(entropy(op.inf), entropy(op.sup))) */
2951
2952 /* first, compute the logarithms (roundmode nearest, then nextafter) */
2954 if( operand.inf > 0.0 )
2955 {
2956 loginf = log(operand.inf);
2957 infcand1 = SCIPnextafter(loginf, SCIP_REAL_MAX);
2958 supcand1 = SCIPnextafter(loginf, SCIP_REAL_MIN);
2959 }
2960
2961 if( operand.sup < infinity )
2962 {
2963 logsup = log(operand.sup);
2964 infcand2 = SCIPnextafter(logsup, SCIP_REAL_MAX);
2965 supcand2 = SCIPnextafter(logsup, SCIP_REAL_MIN);
2966 }
2967
2968 /* second, multiply with operand.inf/sup using upward rounding
2969 * thus, for infinum, negate after muliplication; for supremum, negate before multiplication
2970 */
2972 if( operand.inf > 0.0 )
2973 {
2974 infcand1 = SCIPnegateReal(operand.inf * infcand1);
2975 supcand1 = SCIPnegateReal(operand.inf) * supcand1;
2976 }
2977 else
2978 {
2979 infcand1 = 0.0;
2980 supcand1 = 0.0;
2981 }
2982
2983 if( operand.sup < infinity )
2984 {
2985 infcand2 = SCIPnegateReal(operand.sup * infcand2);
2986 supcand2 = SCIPnegateReal(operand.sup) * supcand2;
2987 }
2988 else
2989 {
2990 infcand2 = -infinity;
2991 supcand2 = -infinity;
2992 }
2993
2994 /* restore original rounding mode (asserted to be "to-nearest" above) */
2996
2997 inf = MIN(infcand1, infcand2);
2998
2999 extr = exp(-1.0);
3000 if( operand.inf <= extr && extr <= operand.sup )
3001 {
3002 extr = SCIPnextafter(extr, SCIP_REAL_MAX);
3003 sup = MAX3(supcand1, supcand2, extr);
3004 }
3005 else
3006 sup = MAX(supcand1, supcand2);
3007
3008 assert(inf <= sup);
3009 SCIPintervalSetBounds(resultant, inf, sup);
3010}
3011
3012/** computes exact upper bound on \f$ a x^2 + b x \f$ for x in [xlb, xub], b an interval, and a scalar
3013 *
3014 * Uses Algorithm 2.2 from Domes and Neumaier: Constraint propagation on quadratic constraints (2008).
3015 */
3017 SCIP_Real infinity, /**< value for infinity */
3018 SCIP_Real a, /**< coefficient of x^2 */
3019 SCIP_INTERVAL b_, /**< coefficient of x */
3020 SCIP_INTERVAL x /**< range of x */
3021 )
3022{
3023 SCIP_Real b;
3024 SCIP_Real u;
3025
3026 assert(!SCIPintervalIsEmpty(infinity, x));
3027 assert(b_.inf < infinity);
3028 assert(b_.sup > -infinity);
3029 assert( x.inf < infinity);
3030 assert( x.sup > -infinity);
3031
3032 /* handle b*x separately */
3033 if( a == 0.0 )
3034 {
3035 if( (b_.inf <= -infinity && x.inf < 0.0 ) ||
3036 ( b_.inf < 0.0 && x.inf <= -infinity) ||
3037 ( b_.sup > 0.0 && x.sup >= infinity) ||
3038 ( b_.sup >= infinity && x.sup > 0.0 ) )
3039 {
3040 u = infinity;
3041 }
3042 else
3043 {
3044 SCIP_ROUNDMODE roundmode;
3045 SCIP_Real cand1, cand2, cand3, cand4;
3046
3047 roundmode = intervalGetRoundingMode();
3049 cand1 = b_.inf * x.inf;
3050 cand2 = b_.inf * x.sup;
3051 cand3 = b_.sup * x.inf;
3052 cand4 = b_.sup * x.sup;
3053 u = MAX(MAX(cand1, cand2), MAX(cand3, cand4));
3054
3055 intervalSetRoundingMode(roundmode);
3056 }
3057
3058 return u;
3059 }
3060
3061 if( x.sup <= 0.0 )
3062 { /* change sign of x: enclose a*x^2 + [-bub, -blb]*(-x) for (-x) in [-xub, -xlb] */
3063 u = x.sup;
3064 x.sup = -x.inf;
3065 x.inf = -u;
3066 b = -b_.inf;
3067 }
3068 else
3069 {
3070 b = b_.sup;
3071 }
3072
3073 if( x.inf >= 0.0 )
3074 { /* upper bound for a*x^2 + b*x */
3075 SCIP_ROUNDMODE roundmode;
3076 SCIP_Real s,t;
3077
3078 if( b >= infinity )
3079 return infinity;
3080
3081 roundmode = intervalGetRoundingMode();
3083
3084 u = MAX(x.inf * (a*x.inf + b), x.sup * (a*x.sup + b));
3085 s = b/2;
3086 t = s/negate(a);
3087 if( t > x.inf && negate(2*a)*x.sup > b && s*t > u )
3088 u = s*t;
3089
3090 intervalSetRoundingMode(roundmode);
3091 return u;
3092 }
3093 else
3094 {
3095 SCIP_INTERVAL xlow = x;
3096 SCIP_Real cand1;
3097 SCIP_Real cand2;
3098 assert(x.inf < 0.0 && x.sup > 0);
3099
3100 xlow.sup = 0; /* so xlow is lower part of interval */
3101 x.inf = 0; /* so x is upper part of interval now */
3102 cand1 = SCIPintervalQuadUpperBound(infinity, a, b_, xlow);
3103 cand2 = SCIPintervalQuadUpperBound(infinity, a, b_, x);
3104 return MAX(cand1, cand2);
3105 }
3106}
3107
3108/** stores range of quadratic term in resultant
3109 *
3110 * given scalar a and intervals b and x, computes interval for \f$ a x^2 + b x \f$ */
3112 SCIP_Real infinity, /**< value for infinity */
3113 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
3114 SCIP_Real sqrcoeff, /**< coefficient of x^2 */
3115 SCIP_INTERVAL lincoeff, /**< coefficient of x */
3116 SCIP_INTERVAL xrng /**< range of x */
3117 )
3118{
3119 SCIP_Real tmp;
3120
3121 if( SCIPintervalIsEmpty(infinity, xrng) )
3122 {
3123 SCIPintervalSetEmpty(resultant);
3124 return;
3125 }
3126 if( sqrcoeff == 0.0 )
3127 {
3128 SCIPintervalMul(infinity, resultant, lincoeff, xrng);
3129 return;
3130 }
3131
3132 resultant->sup = SCIPintervalQuadUpperBound(infinity, sqrcoeff, lincoeff, xrng);
3133
3134 tmp = lincoeff.inf;
3135 lincoeff.inf = -lincoeff.sup;
3136 lincoeff.sup = -tmp;
3137 resultant->inf = -SCIPintervalQuadUpperBound(infinity, -sqrcoeff, lincoeff, xrng);
3138
3139 assert(resultant->sup >= resultant->inf);
3140}
3141
3142/** computes interval with positive solutions of a quadratic equation with interval coefficients
3143 *
3144 * Given intervals a, b, and c, this function computes an interval that contains all positive solutions of \f$ a x^2 + b x \in c\f$ within xbnds.
3145 */
3147 SCIP_Real infinity, /**< value for infinity */
3148 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
3149 SCIP_INTERVAL sqrcoeff, /**< coefficient of x^2 */
3150 SCIP_INTERVAL lincoeff, /**< coefficient of x */
3151 SCIP_INTERVAL rhs, /**< right hand side of equation */
3152 SCIP_INTERVAL xbnds /**< bounds on x */
3153 )
3154{
3155 assert(resultant != NULL);
3156
3157 /* find x>=0 s.t. a.inf x^2 + b.inf x <= c.sup -> -a.inf x^2 - b.inf x >= -c.sup */
3158 if( lincoeff.inf <= -infinity || rhs.sup >= infinity || sqrcoeff.inf <= -infinity )
3159 {
3160 resultant->inf = 0.0;
3161 resultant->sup = infinity;
3162 }
3163 else
3164 {
3165 SCIPintervalSolveUnivariateQuadExpressionPositiveAllScalar(infinity, resultant, -sqrcoeff.inf, -lincoeff.inf, -rhs.sup, xbnds);
3166 SCIPdebugMessage("solve %g*x^2 + %g*x >= %g gives [%.20f, %.20f]\n", -sqrcoeff.inf, -lincoeff.inf, -rhs.sup, resultant->inf, resultant->sup);
3167 }
3168
3169 /* find x>=0 s.t. a.sup x^2 + b.sup x >= c.inf */
3170 if( lincoeff.sup < infinity && rhs.inf > -infinity && sqrcoeff.sup < infinity )
3171 {
3172 SCIP_INTERVAL res2;
3173 /* coverity[uninit_use_in_call] */
3174 SCIPintervalSolveUnivariateQuadExpressionPositiveAllScalar(infinity, &res2, sqrcoeff.sup, lincoeff.sup, rhs.inf, xbnds);
3175 SCIPdebugMessage("solve %g*x^2 + %g*x >= %g gives [%.20f, %.20f]\n", sqrcoeff.sup, lincoeff.sup, rhs.inf, res2.inf, res2.sup);
3176 SCIPdebugMessage("intersection of [%.20f, %.20f] and [%.20f, %.20f]", resultant->inf, resultant->sup, res2.inf, res2.sup);
3177 /* intersect both results */
3178 SCIPintervalIntersect(resultant, *resultant, res2);
3179 SCIPdebugPrintf(" gives [%.20f, %.20f]\n", resultant->inf, resultant->sup);
3180 }
3181 /* else res2 = [0, infty] */
3182
3183 if( resultant->inf >= infinity || resultant->sup <= -infinity )
3184 {
3185 SCIPintervalSetEmpty(resultant);
3186 }
3187}
3188
3189/** computes interval with negative solutions of a quadratic equation with interval coefficients
3190 *
3191 * Given intervals a, b, and c, this function computes an interval that contains all negative solutions of \f$ a x^2 + b x \in c\f$ within xbnds.
3192 */
3194 SCIP_Real infinity, /**< value for infinity */
3195 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
3196 SCIP_INTERVAL sqrcoeff, /**< coefficient of x^2 */
3197 SCIP_INTERVAL lincoeff, /**< coefficient of x */
3198 SCIP_INTERVAL rhs, /**< right hand side of equation */
3199 SCIP_INTERVAL xbnds /**< bounds on x */
3200 )
3201{
3202 SCIP_Real tmp;
3203
3204 /* change in variables y = -x, thus get all positive solutions of
3205 * a * y^2 + (-b) * y in c with -xbnds as bounds on y
3206 */
3207
3208 tmp = lincoeff.inf;
3209 lincoeff.inf = -lincoeff.sup;
3210 lincoeff.sup = -tmp;
3211
3212 tmp = xbnds.inf;
3213 xbnds.inf = -xbnds.sup;
3214 xbnds.sup = -tmp;
3215
3216 SCIPintervalSolveUnivariateQuadExpressionPositive(infinity, resultant, sqrcoeff, lincoeff, rhs, xbnds);
3217
3218 tmp = resultant->inf;
3219 resultant->inf = -resultant->sup;
3220 resultant->sup = -tmp;
3221}
3222
3223
3224/** computes positive solutions of a quadratic equation with scalar coefficients
3225 *
3226 * Givens scalar a, b, and c, this function computes an interval that contains all positive solutions of \f$ a x^2 + b x \geq c\f$ within xbnds.
3227 * Implements Algorithm 3.2 from Domes and Neumaier: Constraint propagation on quadratic constraints (2008).
3228 */
3230 SCIP_Real infinity, /**< value for infinity */
3231 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
3232 SCIP_Real sqrcoeff, /**< coefficient of x^2 */
3233 SCIP_Real lincoeff, /**< coefficient of x */
3234 SCIP_Real rhs, /**< right hand side of equation */
3235 SCIP_INTERVAL xbnds /**< bounds on x */
3236 )
3237{
3238 SCIP_ROUNDMODE roundmode;
3239 SCIP_Real b;
3240 SCIP_Real delta;
3241 SCIP_Real z;
3242
3243 assert(resultant != NULL);
3244 assert(sqrcoeff < infinity);
3245 assert(sqrcoeff > -infinity);
3246
3247 if( sqrcoeff == 0.0 )
3248 {
3249 /* special handling for linear b * x >= c
3250 *
3251 * The non-negative solutions here are:
3252 * b < 0, c <= 0 : [0, c/b]
3253 * b <= 0, c > 0 : empty
3254 * b > 0, c > 0 : [c/b, infty]
3255 * b >= 0, c <= 0 : [0, infty]
3256 *
3257 * The same should have been computed below, but without the sqrcoeff, terms simplify (thus, also less rounding).
3258 */
3259
3260 if( lincoeff <= 0.0 && rhs > 0.0 )
3261 {
3262 SCIPintervalSetEmpty(resultant);
3263 return;
3264 }
3265
3266 if( lincoeff >= 0.0 && rhs <= 0.0 )
3267 {
3268 /* [0,infty] cap xbnds */
3269 resultant->inf = MAX(0.0, xbnds.inf);
3270 resultant->sup = xbnds.sup;
3271 return;
3272 }
3273
3274 roundmode = intervalGetRoundingMode();
3275
3276 if( lincoeff < 0.0 && rhs <= 0.0 )
3277 {
3278 /* [0,c/b] cap xbnds */
3279 resultant->inf = MAX(0.0, xbnds.inf);
3280
3282 resultant->sup = rhs / lincoeff;
3283 if( xbnds.sup < resultant->sup )
3284 resultant->sup = xbnds.sup;
3285 }
3286 else
3287 {
3288 assert(lincoeff > 0.0);
3289 assert(rhs > 0.0);
3290
3291 /* [c/b, infty] cap xbnds */
3292
3294 resultant->inf = rhs / lincoeff;
3295 if( resultant->inf < xbnds.inf )
3296 resultant->inf = xbnds.inf;
3297
3298 resultant->sup = xbnds.sup;
3299 }
3300
3301 intervalSetRoundingMode(roundmode);
3302
3303 return;
3304 }
3305
3306 resultant->inf = 0.0;
3307 resultant->sup = infinity;
3308
3309 roundmode = intervalGetRoundingMode();
3310
3311 /* this should actually be round_upwards, but unless lincoeff is min_double,
3312 * there shouldn't be any rounding happening when dividing by 2, i.e., shifting exponent,
3313 * so it is ok to not change the rounding mode here
3314 */
3315 b = lincoeff / 2.0;
3316
3317 if( lincoeff >= 0.0 )
3318 { /* b >= 0.0 */
3319 if( rhs > 0.0 )
3320 { /* b >= 0.0 and c > 0.0 */
3322 delta = b*b + sqrcoeff*rhs;
3323 if( delta < 0.0 )
3324 {
3325 SCIPintervalSetEmpty(resultant);
3326 }
3327 else
3328 {
3330 z = SCIPnextafter(sqrt(delta), SCIP_REAL_MAX);
3332 z += b;
3333 resultant->inf = negate(negate(rhs)/z);
3334 if( sqrcoeff < 0.0 )
3335 resultant->sup = z / negate(sqrcoeff);
3336 }
3337 }
3338 else
3339 { /* b >= 0.0 and c <= 0.0 */
3340 if( sqrcoeff < 0.0 )
3341 {
3343 delta = b*b + sqrcoeff*rhs;
3345 z = SCIPnextafter(sqrt(delta), SCIP_REAL_MAX);
3347 z += b;
3348 resultant->sup = z / negate(sqrcoeff);
3349 }
3350 }
3351 }
3352 else
3353 { /* b < 0.0 */
3354 if( rhs > 0.0 )
3355 { /* b < 0.0 and c > 0.0 */
3356 if( sqrcoeff > 0.0 )
3357 {
3359 delta = b*b + sqrcoeff*rhs;
3361 z = SCIPnextafter(sqrt(delta), SCIP_REAL_MIN);
3363 z += negate(b);
3364 resultant->inf = z / sqrcoeff;
3365 }
3366 else
3367 {
3368 SCIPintervalSetEmpty(resultant);
3369 }
3370 }
3371 else
3372 { /* b < 0.0 and c <= 0.0 */
3374 delta = b*b + sqrcoeff * rhs;
3375 if( delta >= 0.0 )
3376 {
3377 /* let resultant = [0,-c/z] for now */
3379 z = SCIPnextafter(sqrt(delta), SCIP_REAL_MIN);
3380 /* continue with downward rounding, because we want z (>= 0) to be small,
3381 * because -rhs/z needs to be large (-rhs >= 0)
3382 */
3384 z += negate(b);
3385 /* also now compute rhs/z with downward rounding, so that -(rhs/z) becomes large */
3386 resultant->sup = negate(rhs/z);
3387
3388 if( sqrcoeff > 0.0 )
3389 {
3390 /* for a > 0, the result is [0,-c/z] \vee [z/a,infinity]
3391 * currently, resultant = [0,-c/z]
3392 */
3393 SCIP_Real zdiva;
3394
3395 zdiva = z/sqrcoeff;
3396
3397 if( xbnds.sup < zdiva )
3398 {
3399 /* after intersecting with xbnds, result is [0,-c/z], so we are done */
3400 }
3401 else if( xbnds.inf > resultant->sup )
3402 {
3403 /* after intersecting with xbnds, result is [z/a,infinity] */
3404 resultant->inf = zdiva;
3405 resultant->sup = infinity;
3406 }
3407 else
3408 {
3409 /* after intersecting with xbnds we can neither exclude [0,-c/z] nor [z/a,infinity],
3410 * so put resultant = [0,infinity] (intersection with xbnds happens below)
3411 * @todo we could create a hole here
3412 */
3413 resultant->sup = infinity;
3414 }
3415 }
3416 else
3417 {
3418 /* for a < 0, the result is [0,-c/z], so we are done */
3419 }
3420 }
3421 }
3422 }
3423
3424 SCIPintervalIntersect(resultant, *resultant, xbnds);
3425
3426 intervalSetRoundingMode(roundmode);
3427}
3428
3429/** solves a quadratic equation with interval coefficients
3430 *
3431 * Given intervals a, b and c, this function computes an interval that contains all solutions of \f$ a x^2 + b x \in c\f$ within xbnds.
3432 */
3434 SCIP_Real infinity, /**< value for infinity */
3435 SCIP_INTERVAL* resultant, /**< resultant interval of operation */
3436 SCIP_INTERVAL sqrcoeff, /**< coefficient of x^2 */
3437 SCIP_INTERVAL lincoeff, /**< coefficient of x */
3438 SCIP_INTERVAL rhs, /**< right hand side of equation */
3439 SCIP_INTERVAL xbnds /**< bounds on x */
3440 )
3441{
3442 SCIP_INTERVAL xpos;
3443 SCIP_INTERVAL xneg;
3444
3445 assert(resultant != NULL);
3446 assert(!SCIPintervalIsEmpty(infinity, sqrcoeff));
3447 assert(!SCIPintervalIsEmpty(infinity, lincoeff));
3448 assert(!SCIPintervalIsEmpty(infinity, rhs));
3449
3450 /* special handling for lincoeff * x = rhs without 0 in lincoeff
3451 * rhs/lincoeff gives a good interval that we just have to intersect with xbnds
3452 * the code below would also work, but uses many more case distinctions to get to a result that should be the same (though epsilon differences can sometimes be observed)
3453 */
3454 if( sqrcoeff.inf == 0.0 && sqrcoeff.sup == 0.0 && (lincoeff.inf > 0.0 || lincoeff.sup < 0.0) )
3455 {
3456 SCIPintervalDiv(infinity, resultant, rhs, lincoeff);
3457 SCIPintervalIntersect(resultant, *resultant, xbnds);
3458 SCIPdebugMessage("solving [%g,%g]*x = [%g,%g] for x in [%g,%g] gives [%g,%g]\n", lincoeff.inf, lincoeff.sup, rhs.inf, rhs.sup, xbnds.inf, xbnds.sup, resultant->inf, resultant->sup);
3459 return;
3460 }
3461
3462 SCIPdebugMessage("solving [%g,%g]*x^2 + [%g,%g]*x = [%g,%g] for x in [%g,%g]\n", sqrcoeff.inf, sqrcoeff.sup, lincoeff.inf, lincoeff.sup, rhs.inf, rhs.sup, xbnds.inf, xbnds.sup);
3463
3464 /* find all x>=0 such that a*x^2+b*x = c */
3465 if( xbnds.sup >= 0 )
3466 {
3467 SCIPintervalSolveUnivariateQuadExpressionPositive(infinity, &xpos, sqrcoeff, lincoeff, rhs, xbnds);
3468 SCIPdebugMessage(" solutions of [%g,%g]*x^2 + [%g,%g]*x in [%g,%g] for x in [%g,%g] are [%.15g,%.15g]\n",
3469 sqrcoeff.inf, sqrcoeff.sup, lincoeff.inf, lincoeff.sup, rhs.inf, rhs.sup, MAX(xbnds.inf, 0.0), xbnds.sup, xpos.inf, xpos.sup);
3470 }
3471 else
3472 {
3473 SCIPintervalSetEmpty(&xpos);
3474 }
3475
3476 /* find all x<=0 such that a*x^2-b*x = c */
3477 if( xbnds.inf <= 0.0 )
3478 {
3479 SCIPintervalSolveUnivariateQuadExpressionNegative(infinity, &xneg, sqrcoeff, lincoeff, rhs, xbnds);
3480 SCIPdebugMessage(" solutions of [%g,%g]*x^2 + [%g,%g]*x in [%g,%g] for x in [%g,%g] are [%g,%g]\n",
3481 sqrcoeff.inf, sqrcoeff.sup, lincoeff.inf, lincoeff.sup, rhs.inf, rhs.sup, xbnds.inf, MIN(xbnds.sup, 0.0), xneg.inf, xneg.sup);
3482 }
3483 else
3484 {
3485 SCIPintervalSetEmpty(&xneg);
3486 }
3487
3488 SCIPintervalUnify(resultant, xpos, xneg);
3489 SCIPdebugMessage(" unify gives [%g,%g]\n", SCIPintervalGetInf(*resultant), SCIPintervalGetSup(*resultant));
3490}
3491
3492/** stores range of bivariate quadratic term in resultant
3493 *
3494 * Given scalars \f$a_x\f$, \f$a_y\f$, \f$a_{xy}\f$, \f$b_x\f$, and \f$b_y\f$ and intervals for \f$x\f$ and \f$y\f$,
3495 * computes interval for \f$ a_x x^2 + a_y y^2 + a_{xy} x y + b_x x + b_y y \f$.
3496 *
3497 * \attention The operations are not applied rounding-safe here!
3498 */
3500 SCIP_Real infinity, /**< value for infinity in interval arithmetics */
3501 SCIP_INTERVAL* resultant, /**< buffer where to store result of operation */
3502 SCIP_Real ax, /**< square coefficient of x */
3503 SCIP_Real ay, /**< square coefficient of y */
3504 SCIP_Real axy, /**< bilinear coefficients */
3505 SCIP_Real bx, /**< linear coefficient of x */
3506 SCIP_Real by, /**< linear coefficient of y */
3507 SCIP_INTERVAL xbnds, /**< bounds on x */
3508 SCIP_INTERVAL ybnds /**< bounds on y */
3509 )
3510{
3511 /* we use double double precision and finally widen the computed range by 1e-8% to compensate for not computing rounding-safe here */
3512 SCIP_Real minval;
3513 SCIP_Real maxval;
3514 SCIP_Real val;
3515 SCIP_Real x;
3516 SCIP_Real y;
3517 SCIP_Real denom;
3518
3519 assert(resultant != NULL);
3520 assert(xbnds.inf <= xbnds.sup);
3521 assert(ybnds.inf <= ybnds.sup);
3522
3523 /* if we are separable, then fall back to use SCIPintervalQuad two times and add */
3524 if( axy == 0.0 )
3525 {
3526 SCIP_INTERVAL tmp;
3527
3528 SCIPintervalSet(&tmp, bx);
3529 SCIPintervalQuad(infinity, resultant, ax, tmp, xbnds);
3530
3531 SCIPintervalSet(&tmp, by);
3532 SCIPintervalQuad(infinity, &tmp, ay, tmp, ybnds);
3533
3534 SCIPintervalAdd(infinity, resultant, *resultant, tmp);
3535
3536 return;
3537 }
3538
3539 SCIPintervalSet(resultant, 0.0);
3540
3541 minval = infinity;
3542 maxval = -infinity;
3543
3544 /* check minima/maxima of expression */
3545 denom = 4.0 * ax * ay - axy * axy;
3546 if( REALABS(denom) > 1e-9 )
3547 {
3548 x = (axy * by - 2.0 * ay * bx) / denom;
3549 y = (axy * bx - 2.0 * ax * by) / denom;
3550 if( xbnds.inf <= x && x <= xbnds.sup && ybnds.inf <= y && y <= ybnds.sup )
3551 {
3552 val = (axy * bx * by - ay * bx * bx - ax * by * by) / denom;
3553 minval = MIN(val, minval);
3554 maxval = MAX(val, maxval);
3555 }
3556 }
3557 else if( REALABS(2.0 * ay * bx - axy * by) <= 1e-9 )
3558 {
3559 /* The whole line (x, -bx/axy - (axy/2ay) x) defines an extreme point with value -ay bx^2 / axy^2
3560 * If x is unbounded, then there is an (x,y) with y in ybnds where the extreme value is assumed.
3561 * If x is bounded on at least one side, then we can rely that the checks below for x at one of its bounds will check this extreme point.
3562 */
3563 if( xbnds.inf <= -infinity && xbnds.sup >= infinity )
3564 {
3565 val = -ay * bx * bx / (axy * axy);
3566 minval = MIN(val, minval);
3567 maxval = MAX(val, maxval);
3568 }
3569 }
3570
3571 /* check boundary of box xbnds x ybnds */
3572
3573 if( xbnds.inf <= -infinity )
3574 {
3575 /* check value for x -> -infinity */
3576 if( ax > 0.0 )
3577 maxval = infinity;
3578 else if( ax < 0.0 )
3579 minval = -infinity;
3580 else if( ax == 0.0 )
3581 {
3582 /* bivar(x,y) tends to -(bx+axy y) * infinity */
3583
3584 if( ybnds.inf <= -infinity )
3585 val = (axy < 0.0 ? -infinity : infinity);
3586 else if( bx + axy * ybnds.inf < 0.0 )
3587 val = infinity;
3588 else
3589 val = -infinity;
3590 minval = MIN(val, minval);
3591 maxval = MAX(val, maxval);
3592
3593 if( ybnds.sup >= infinity )
3594 val = (axy < 0.0 ? infinity : -infinity);
3595 else if( bx + axy * ybnds.sup < 0.0 )
3596 val = infinity;
3597 else
3598 val = -infinity;
3599 minval = MIN(val, minval);
3600 maxval = MAX(val, maxval);
3601 }
3602 }
3603 else
3604 {
3605 /* get range of bivar(xbnds.inf, y) for y in ybnds */
3606 SCIP_INTERVAL tmp;
3607 SCIP_INTERVAL ycoef;
3608
3609 SCIPintervalSet(&ycoef, axy * xbnds.inf + by);
3610 SCIPintervalQuad(infinity, &tmp, ay, ycoef, ybnds);
3611 SCIPintervalAddScalar(infinity, &tmp, tmp, (SCIP_Real)(ax * xbnds.inf * xbnds.inf + bx * xbnds.inf));
3612 minval = MIN(tmp.inf, minval);
3613 maxval = MAX(tmp.sup, maxval);
3614 }
3615
3616 if( xbnds.sup >= infinity )
3617 {
3618 /* check value for x -> infinity */
3619 if( ax > 0.0 )
3620 maxval = infinity;
3621 else if( ax < 0.0 )
3622 minval = -infinity;
3623 else if( ax == 0.0 )
3624 {
3625 /* bivar(x,y) tends to (bx+axy y) * infinity */
3626
3627 if( ybnds.inf <= -infinity )
3628 val = (axy > 0.0 ? -infinity : infinity);
3629 else if( bx + axy * ybnds.inf > 0.0 )
3630 val = infinity;
3631 else
3632 val = -infinity;
3633 minval = MIN(val, minval);
3634 maxval = MAX(val, maxval);
3635
3636 if( ybnds.sup >= infinity )
3637 val = (axy > 0.0 ? infinity : -infinity);
3638 else if( bx + axy * ybnds.sup > 0.0 )
3639 val = infinity;
3640 else
3641 val = -infinity;
3642 minval = MIN(val, minval);
3643 maxval = MAX(val, maxval);
3644 }
3645 }
3646 else
3647 {
3648 /* get range of bivar(xbnds.sup, y) for y in ybnds */
3649 SCIP_INTERVAL tmp;
3650 SCIP_INTERVAL ycoef;
3651
3652 SCIPintervalSet(&ycoef, axy * xbnds.sup + by);
3653 SCIPintervalQuad(infinity, &tmp, ay, ycoef, ybnds);
3654 SCIPintervalAddScalar(infinity, &tmp, tmp, (SCIP_Real)(ax * xbnds.sup * xbnds.sup + bx * xbnds.sup));
3655 minval = MIN(tmp.inf, minval);
3656 maxval = MAX(tmp.sup, maxval);
3657 }
3658
3659 if( ybnds.inf <= -infinity )
3660 {
3661 /* check value for y -> -infinity */
3662 if( ay > 0.0 )
3663 maxval = infinity;
3664 else if( ay < 0.0 )
3665 minval = -infinity;
3666 else if( ay == 0.0 )
3667 {
3668 /* bivar(x,y) tends to -(by+axy x) * infinity */
3669
3670 if( xbnds.inf <= -infinity )
3671 val = (axy < 0.0 ? -infinity : infinity);
3672 else if( by + axy * xbnds.inf < 0.0 )
3673 val = infinity;
3674 else
3675 val = -infinity;
3676 minval = MIN(val, minval);
3677 maxval = MAX(val, maxval);
3678
3679 if( xbnds.sup >= infinity )
3680 val = (axy < 0.0 ? infinity : -infinity);
3681 else if( by + axy * xbnds.sup < 0.0 )
3682 val = infinity;
3683 else
3684 val = -infinity;
3685 minval = MIN(val, minval);
3686 maxval = MAX(val, maxval);
3687 }
3688 }
3689 else
3690 {
3691 /* get range of bivar(x, ybnds.inf) for x in xbnds */
3692 SCIP_INTERVAL tmp;
3693 SCIP_INTERVAL xcoef;
3694
3695 SCIPintervalSet(&xcoef, axy * ybnds.inf + bx);
3696 SCIPintervalQuad(infinity, &tmp, ax, xcoef, xbnds);
3697 SCIPintervalAddScalar(infinity, &tmp, tmp, ay * ybnds.inf * ybnds.inf + by * ybnds.inf);
3698 minval = MIN(tmp.inf, minval);
3699 maxval = MAX(tmp.sup, maxval);
3700 }
3701
3702 if( ybnds.sup >= infinity )
3703 {
3704 /* check value for y -> infinity */
3705 if( ay > 0.0 )
3706 maxval = infinity;
3707 else if( ay < 0.0 )
3708 minval = -infinity;
3709 else if( ay == 0.0 )
3710 {
3711 /* bivar(x,y) tends to (by+axy x) * infinity */
3712
3713 if( xbnds.inf <= -infinity )
3714 val = (axy > 0.0 ? -infinity : infinity);
3715 else if( by + axy * xbnds.inf > 0.0 )
3716 val = infinity;
3717 else
3718 val = -infinity;
3719 minval = MIN(val, minval);
3720 maxval = MAX(val, maxval);
3721
3722 if( xbnds.sup >= infinity )
3723 val = (axy > 0.0 ? infinity : -infinity);
3724 else if( by + axy * xbnds.sup > 0.0 )
3725 val = infinity;
3726 else
3727 val = -infinity;
3728 minval = MIN(val, minval);
3729 maxval = MAX(val, maxval);
3730 }
3731 }
3732 else
3733 {
3734 /* get range of bivar(x, ybnds.sup) for x in xbnds */
3735 SCIP_INTERVAL tmp;
3736 SCIP_INTERVAL xcoef;
3737
3738 SCIPintervalSet(&xcoef, axy * ybnds.sup + bx);
3739 SCIPintervalQuad(infinity, &tmp, ax, xcoef, xbnds);
3740 SCIPintervalAddScalar(infinity, &tmp, tmp, (SCIP_Real)(ay * ybnds.sup * ybnds.sup + by * ybnds.sup));
3741 minval = MIN(tmp.inf, minval);
3742 maxval = MAX(tmp.sup, maxval);
3743 }
3744
3745 minval -= 1e-10 * REALABS(minval);
3746 maxval += 1e-10 * REALABS(maxval);
3747 SCIPintervalSetBounds(resultant, (SCIP_Real)minval, (SCIP_Real)maxval);
3748
3749 SCIPdebugMessage("range for %gx^2 + %gy^2 + %gxy + %gx + %gy = [%g, %g] for x = [%g, %g], y=[%g, %g]\n",
3750 ax, ay, axy, bx, by, minval, maxval, xbnds.inf, xbnds.sup, ybnds.inf, ybnds.sup);
3751}
3752
3753/** solves a bivariate quadratic equation for the first variable
3754 *
3755 * Given scalars \f$a_x\f$, \f$a_y\f$, \f$a_{xy}\f$, \f$b_x\f$ and \f$b_y\f$, and intervals for \f$x\f$, \f$y\f$, and rhs,
3756 * computes \f$ \{ x \in \mathbf{x} : \exists y \in \mathbf{y} : a_x x^2 + a_y y^2 + a_{xy} x y + b_x x + b_y y \in \mathbf{\mbox{rhs}} \} \f$.
3757 *
3758 * \attention the operations are not applied rounding-safe here
3759 */
3761 SCIP_Real infinity, /**< value for infinity in interval arithmetics */
3762 SCIP_INTERVAL* resultant, /**< buffer where to store result of operation */
3763 SCIP_Real ax, /**< square coefficient of x */
3764 SCIP_Real ay, /**< square coefficient of y */
3765 SCIP_Real axy, /**< bilinear coefficients */
3766 SCIP_Real bx, /**< linear coefficient of x */
3767 SCIP_Real by, /**< linear coefficient of y */
3768 SCIP_INTERVAL rhs, /**< right-hand-side of equation */
3769 SCIP_INTERVAL xbnds, /**< bounds on x */
3770 SCIP_INTERVAL ybnds /**< bounds on y */
3771 )
3772{
3773 /* we use double double precision and finally widen the computed range by 1e-8% to compensate for not computing rounding-safe here */
3774 SCIP_Real val;
3775
3776 assert(resultant != NULL);
3777
3778 if( axy == 0.0 )
3779 {
3780 /* if axy == 0, fall back to SCIPintervalSolveUnivariateQuadExpression */
3781 SCIP_INTERVAL ytermrng;
3782 SCIP_INTERVAL sqrcoef;
3783 SCIP_INTERVAL lincoef;
3784 SCIP_INTERVAL pos;
3785 SCIP_INTERVAL neg;
3786
3787 SCIPintervalSet(&lincoef, by);
3788 SCIPintervalQuad(infinity, &ytermrng, ay, lincoef, ybnds);
3789 SCIPintervalSub(infinity, &rhs, rhs, ytermrng);
3790
3791 SCIPintervalSet(&sqrcoef, ax);
3792
3793 /* get positive solutions, if of interest */
3794 if( xbnds.sup >= 0.0 )
3795 {
3796 SCIPintervalSet(&lincoef, bx);
3797 SCIPintervalSolveUnivariateQuadExpressionPositive(infinity, &pos, sqrcoef, lincoef, rhs, xbnds);
3798 }
3799 else
3801
3802 /* get negative solutions, if of interest */
3803 if( xbnds.inf < 0.0 )
3804 {
3805 SCIP_INTERVAL xbndsneg;
3806 SCIPintervalSet(&lincoef, -bx);
3807 SCIPintervalSetBounds(&xbndsneg, -xbnds.sup, -xbnds.inf);
3808 SCIPintervalSolveUnivariateQuadExpressionPositive(infinity, &neg, sqrcoef, lincoef, rhs, xbndsneg);
3809 if( !SCIPintervalIsEmpty(infinity, neg) )
3810 SCIPintervalSetBounds(&neg, -neg.sup, -neg.inf);
3811 }
3812 else
3814
3815 SCIPintervalUnify(resultant, pos, neg);
3816
3817 return;
3818 }
3819
3820 if( ybnds.inf <= -infinity || ybnds.sup >= infinity )
3821 {
3822 /* the code below is buggy if y is unbounded, see #2250
3823 * fall back to univariate case by solving a_x x^2 + b_x x + a_y y^2 + (a_xy xbnds + b_y) y in rhs
3824 */
3825 SCIP_INTERVAL ax_;
3826 SCIP_INTERVAL bx_;
3827 SCIP_INTERVAL ycoef;
3828 SCIP_INTERVAL ytermbounds;
3829
3830 *resultant = xbnds;
3831
3832 /* nothing we can do here if x is unbounded (we have a_xy != 0 here) */
3833 if( xbnds.inf <= -infinity && xbnds.sup >= infinity )
3834 return;
3835
3836 /* ycoef = axy xbnds + by */
3837 SCIPintervalMulScalar(infinity, &ycoef, xbnds, axy);
3838 SCIPintervalAddScalar(infinity, &ycoef, ycoef, by);
3839
3840 /* get bounds on ay y^2 + (axy xbnds + by) y */
3841 SCIPintervalQuad(infinity, &ytermbounds, ay, ycoef, ybnds);
3842
3843 /* now solve ax x^2 + bx x in rhs - ytermbounds */
3844 SCIPintervalSet(&ax_, ax);
3845 SCIPintervalSet(&bx_, bx);
3846 SCIPintervalSub(infinity, &rhs, rhs, ytermbounds);
3847 SCIPintervalSolveUnivariateQuadExpression(infinity, resultant, ax_, bx_, rhs, xbnds);
3848
3849 return;
3850 }
3851
3852 if( ax < 0.0 )
3853 {
3854 SCIP_Real tmp;
3855 tmp = rhs.inf;
3856 rhs.inf = -rhs.sup;
3857 rhs.sup = -tmp;
3858
3859 SCIPintervalSolveBivariateQuadExpressionAllScalar(infinity, resultant, -ax, -ay, -axy, -bx, -by, rhs, xbnds, ybnds);
3860 return;
3861 }
3862 assert(ax >= 0.0);
3863
3864 *resultant = xbnds;
3865
3866 if( ax > 0.0 )
3867 {
3868 SCIP_Real sqrtax;
3869 SCIP_Real minvalleft;
3870 SCIP_Real maxvalleft;
3871 SCIP_Real minvalright;
3872 SCIP_Real maxvalright;
3873 SCIP_Real ymin;
3874 SCIP_Real rcoef_y;
3875 SCIP_Real rcoef_yy;
3876 SCIP_Real rcoef_const;
3877
3878 sqrtax = sqrt(ax);
3879
3880 /* rewrite equation as (sqrt(ax)x + b(y))^2 \in r(rhs,y), where
3881 * b(y) = (bx + axy y)/(2sqrt(ax)), r(rhs,y) = rhs - ay y^2 - by y + b(y)^2
3882 *
3883 * -> r(rhs,y) = bx^2/(4ax) + rhs + (axy bx/(2ax) - by)*y + (axy^2/(4ax) - ay)*y^2
3884 */
3885 rcoef_y = axy * bx / (2.0*ax) - by;
3886 rcoef_yy = axy * axy / (4.0*ax) - ay;
3887 rcoef_const = bx * bx / (4.0*ax);
3888
3889#define CALCB(y) ((bx + axy * (y)) / (2.0 * sqrtax))
3890#define CALCR(c,y) (rcoef_const + (c) + (rcoef_y + rcoef_yy * (y)) * (y))
3891
3892 /* check whether r(rhs,y) is always negative */
3893 if( rhs.sup < infinity )
3894 {
3895 SCIP_INTERVAL ycoef;
3896 SCIP_Real ub;
3897
3898 SCIPintervalSet(&ycoef, (SCIP_Real)rcoef_y);
3899 ub = (SCIP_Real)(SCIPintervalQuadUpperBound(infinity, (SCIP_Real)rcoef_yy, ycoef, ybnds) + rhs.sup + rcoef_const);
3900
3901 if( EPSN(ub, 1e-9) )
3902 {
3903 SCIPintervalSetEmpty(resultant);
3904 return;
3905 }
3906 else if( ub < 0.0 )
3907 {
3908 /* it looks like there will be no solution (rhs < 0), but we are very close and above operations did not take care of careful rounding
3909 * thus, we relax rhs a be feasible a bit (-ub would be sufficient, but that would put us exactly onto the boundary)
3910 * see also #1861
3911 */
3912 rhs.sup += -2.0*ub;
3913 }
3914 }
3915
3916 /* we have sqrt(ax)x \in (-sqrt(r(rhs,y))-b(y)) \cup (sqrt(r(rhs,y))-b(y))
3917 * compute minima and maxima of both functions such that
3918 *
3919 * [minvalleft, maxvalleft ] = -sqrt(r(rhs,y))-b(y)
3920 * [minvalright, maxvalright] = sqrt(r(rhs,y))-b(y)
3921 */
3922
3923 minvalleft = infinity;
3924 maxvalleft = -infinity;
3925 minvalright = infinity;
3926 maxvalright = -infinity;
3927
3928 if( rhs.sup >= infinity )
3929 {
3930 /* we can't do much if rhs.sup is infinite
3931 * but we may do a bit of xbnds isn't too huge and rhs.inf > -infinity
3932 */
3933 minvalleft = -infinity;
3934 maxvalright = infinity;
3935 }
3936
3937 /* evaluate at lower bound of y, as long as r(rhs,ylb) > 0 */
3938 if( ybnds.inf <= -infinity )
3939 {
3940 /* check limit of +/-sqrt(r(rhs,y))-b(y) for y -> -infty */
3941 if( !EPSZ(ay, 1e-9) && axy * axy >= 4.0 * ax * ay )
3942 {
3943 if( axy < 0.0 )
3944 {
3945 minvalleft = -infinity;
3946
3947 if( ay > 0.0 )
3948 minvalright = -infinity;
3949 else
3950 maxvalright = infinity;
3951 }
3952 else
3953 {
3954 maxvalright = infinity;
3955
3956 if( ay > 0.0 )
3957 maxvalleft = infinity;
3958 else
3959 minvalleft = -infinity;
3960 }
3961 }
3962 else if( !EPSZ(ay, 1e-9) )
3963 {
3964 /* here axy * axy < 4 * ax * ay, so need to check for zeros of r(rhs,y), which is done below */
3965 }
3966 else
3967 {
3968 /* here ay = 0.0, which gives a limit of -by/2 for -sqrt(r(rhs,y))-b(y) */
3969 minvalleft = -by / 2.0;
3970 maxvalleft = -by / 2.0;
3971 /* here ay = 0.0, which gives a limit of +infinity for sqrt(r(rhs,y))-b(y) */
3972 maxvalright = infinity;
3973 }
3974 }
3975 else
3976 {
3977 SCIP_Real b;
3978 SCIP_Real c;
3979
3980 b = CALCB(ybnds.inf);
3981
3982 if( rhs.sup < infinity )
3983 {
3984 c = CALCR(rhs.sup, ybnds.inf);
3985
3986 if( c > 0.0 )
3987 {
3988 SCIP_Real sqrtc;
3989
3990 sqrtc = sqrt(c);
3991 minvalleft = MIN(-sqrtc - b, minvalleft);
3992 maxvalright = MAX( sqrtc - b, maxvalright);
3993 }
3994 }
3995
3996 if( rhs.inf > -infinity )
3997 {
3998 c = CALCR(rhs.inf, ybnds.inf);
3999
4000 if( c > 0.0 )
4001 {
4002 SCIP_Real sqrtc;
4003
4004 sqrtc = sqrt(c);
4005 maxvalleft = MAX(-sqrtc - b, maxvalleft);
4006 minvalright = MIN( sqrtc - b, minvalright);
4007 }
4008 }
4009 }
4010
4011 /* evaluate at upper bound of y, as long as r(rhs, yub) > 0 */
4012 if( ybnds.sup >= infinity )
4013 {
4014 /* check limit of +/-sqrt(r(rhs,y))-b(y) for y -> +infty */
4015 if( !EPSZ(ay, 1e-9) && axy * axy >= 4.0 * ax * ay )
4016 {
4017 if( axy > 0.0 )
4018 {
4019 minvalleft = -infinity;
4020
4021 if( ay > 0.0 )
4022 minvalright = -infinity;
4023 else
4024 maxvalright = infinity;
4025 }
4026 else
4027 {
4028 maxvalright = infinity;
4029
4030 if( ay > 0.0 )
4031 maxvalleft = infinity;
4032 else
4033 minvalleft = -infinity;
4034 }
4035 }
4036 else if( !EPSZ(ay, 1e-9) )
4037 {
4038 /* here axy * axy < 4 * ax * ay, so need to check for zeros of r(rhs,y), which will happen below */
4039 }
4040 else
4041 {
4042 /* here ay = 0.0, which gives a limit of -infinity for -sqrt(r(rhs,y))-b(y) */
4043 minvalleft = -infinity;
4044 /* here ay = 0.0, which gives a limit of -by/2 for sqrt(r(rhs,y))-b(y) */
4045 minvalright = MIN(minvalright, -by / 2.0);
4046 maxvalright = MAX(maxvalright, -by / 2.0);
4047 }
4048 }
4049 else
4050 {
4051 SCIP_Real b;
4052 SCIP_Real c;
4053
4054 b = CALCB(ybnds.sup);
4055
4056 if( rhs.sup < infinity )
4057 {
4058 c = CALCR(rhs.sup, ybnds.sup);
4059
4060 if( c > 0.0 )
4061 {
4062 SCIP_Real sqrtc;
4063
4064 sqrtc = sqrt(c);
4065 minvalleft = MIN(-sqrtc - b, minvalleft);
4066 maxvalright = MAX( sqrtc - b, maxvalright);
4067 }
4068 }
4069
4070 if( rhs.inf > -infinity )
4071 {
4072 c = CALCR(rhs.inf, ybnds.sup);
4073
4074 if( c > 0.0 )
4075 {
4076 SCIP_Real sqrtc;
4077
4078 sqrtc = sqrt(c);
4079 maxvalleft = MAX(-sqrtc - b, maxvalleft);
4080 minvalright = MIN( sqrtc - b, minvalright);
4081 }
4082 }
4083 }
4084
4085 /* evaluate at ymin = y_{_,+}, if inside ybnds
4086 * if ay = 0 or 2ay*bx == axy*by, then there is no ymin */
4087 if( !EPSZ(ay, 1e-9) )
4088 {
4089 if( REALABS(axy*axy - 4.0*ax*ay) > 1e-9 )
4090 {
4091 SCIP_Real sqrtterm;
4092
4093 if( rhs.sup < infinity )
4094 {
4095 sqrtterm = axy * axy * ay * (ay * bx * bx - axy * bx * by + ax * by * by - axy * axy * rhs.sup + 4.0 * ax * ay * rhs.sup);
4096 if( !EPSN(sqrtterm, 1e-9) )
4097 {
4098 sqrtterm = sqrt(MAX(sqrtterm, 0.0));
4099 /* check first candidate for extreme points of +/-sqrt(rhs(r,y))-b(y) */
4100 ymin = axy * ay * bx - 2.0 * ax * ay * by - sqrtterm;
4101 ymin /= ay;
4102 ymin /= 4.0 * ax * ay - axy * axy;
4103
4104 if( ymin > ybnds.inf && ymin < ybnds.sup )
4105 {
4106 SCIP_Real b;
4107 SCIP_Real c;
4108
4109 b = CALCB(ymin);
4110 c = CALCR(rhs.sup, ymin);
4111
4112 if( c > 0.0 )
4113 {
4114 SCIP_Real sqrtc;
4115
4116 sqrtc = sqrt(c);
4117 minvalleft = MIN(-sqrtc - b, minvalleft);
4118 maxvalright = MAX( sqrtc - b, maxvalright);
4119 }
4120 }
4121
4122 /* check second candidate for extreme points of +/-sqrt(rhs(r,y))-b(y) */
4123 ymin = axy * ay * bx - 2.0 * ax * ay * by + sqrtterm;
4124 ymin /= ay;
4125 ymin /= 4.0 * ax * ay - axy * axy;
4126
4127 if( ymin > ybnds.inf && ymin < ybnds.sup )
4128 {
4129 SCIP_Real b;
4130 SCIP_Real c;
4131
4132 b = CALCB(ymin);
4133 c = CALCR(rhs.sup, ymin);
4134
4135 if( c > 0.0 )
4136 {
4137 SCIP_Real sqrtc;
4138
4139 sqrtc = sqrt(c);
4140 minvalleft = MIN(-sqrtc - b, minvalleft);
4141 maxvalright = MAX( sqrtc - b, maxvalright);
4142 }
4143 }
4144 }
4145 }
4146
4147 if( rhs.inf > -infinity )
4148 {
4149 sqrtterm = axy * axy * ay * (ay * bx * bx - axy * bx * by + ax * by * by - axy * axy * rhs.inf + 4.0 * ax * ay * rhs.inf);
4150 if( !EPSN(sqrtterm, 1e-9) )
4151 {
4152 sqrtterm = sqrt(MAX(sqrtterm, 0.0));
4153 /* check first candidate for extreme points of +/-sqrt(r(rhs,y))-b(y) */
4154 ymin = axy * ay * bx - 2.0 * ax * ay * by - sqrtterm;
4155 ymin /= ay;
4156 ymin /= 4.0 * ax * ay - axy * axy;
4157
4158 if( ymin > ybnds.inf && ymin < ybnds.sup )
4159 {
4160 SCIP_Real b;
4161 SCIP_Real c;
4162
4163 b = CALCB(ymin);
4164 c = CALCR(rhs.inf, ymin);
4165
4166 if( c > 0.0 )
4167 {
4168 SCIP_Real sqrtc;
4169
4170 sqrtc = sqrt(c);
4171 maxvalleft = MAX(-sqrtc - b, maxvalleft);
4172 minvalright = MIN( sqrtc - b, minvalright);
4173 }
4174 }
4175
4176 /* check second candidate for extreme points of +/-sqrt(c(y))-b(y) */
4177 ymin = axy * ay * bx - 2.0 * ax * ay * by + sqrtterm;
4178 ymin /= ay;
4179 ymin /= 4.0 * ax * ay - axy * axy;
4180
4181 if( ymin > ybnds.inf && ymin < ybnds.sup )
4182 {
4183 SCIP_Real b;
4184 SCIP_Real c;
4185
4186 b = CALCB(ymin);
4187 c = CALCR(rhs.inf, ymin);
4188
4189 if( c > 0.0 )
4190 {
4191 SCIP_Real sqrtc;
4192
4193 sqrtc = sqrt(c);
4194 maxvalleft = MAX(-sqrtc - b, maxvalleft);
4195 minvalright = MIN( sqrtc - b, minvalright);
4196 }
4197 }
4198 }
4199 }
4200 }
4201 else if( REALABS(2.0 * ay * bx - axy * by) > 1e-9 )
4202 {
4203 if( rhs.sup < infinity )
4204 {
4205 ymin = - (4.0 * ay * bx * by - axy * by * by + 4.0 * axy * ay * rhs.sup);
4206 ymin /= 4.0 * ay;
4207 ymin /= 2.0 * ay * bx - axy * by;
4208
4209 if( ymin > ybnds.inf && ymin < ybnds.sup )
4210 {
4211 SCIP_Real b;
4212 SCIP_Real c;
4213
4214 b = CALCB(ymin);
4215 c = CALCR(rhs.sup, ymin);
4216
4217 if( c > 0.0 )
4218 {
4219 SCIP_Real sqrtc;
4220
4221 sqrtc = sqrt(c);
4222 minvalleft = MIN(-sqrtc - b, minvalleft);
4223 maxvalright = MAX( sqrtc - b, maxvalright);
4224 }
4225 }
4226 }
4227
4228 if( rhs.inf > -infinity )
4229 {
4230 ymin = - (4.0 * ay * bx * by - axy * by * by + 4.0 * axy * ay * rhs.inf);
4231 ymin /= 4.0 * ay;
4232 ymin /= 2.0 * ay * bx - axy * by;
4233
4234 if( ymin > ybnds.inf && ymin < ybnds.sup )
4235 {
4236 SCIP_Real b;
4237 SCIP_Real c;
4238
4239 b = CALCB(ymin);
4240 c = CALCR(rhs.inf, ymin);
4241
4242 if( c > 0.0 )
4243 {
4244 SCIP_Real sqrtc;
4245
4246 sqrtc = sqrt(c);
4247 maxvalleft = MAX(-sqrtc - b, maxvalleft);
4248 minvalright = MIN( sqrtc - b, minvalright);
4249 }
4250 }
4251 }
4252 }
4253 }
4254
4255 /* evaluate the case r(rhs,y) = 0, which is to min/max -b(y) w.r.t. r(rhs,y) = 0, y in ybnds
4256 * with the above assignments
4257 * rcoef_y = axy * bx / (2.0*ax) - by;
4258 * rcoef_yy = axy * axy / (4.0*ax) - ay;
4259 * rcoef_const = bx * bx / (4.0*ax);
4260 * we have r(rhs,y) = rhs + rcoef_const + rcoef_y * y + rcoef_yy * y^2
4261 *
4262 * thus, r(rhs,y) = 0 <-> rcoef_y * y + rcoef_yy * y^2 in -rhs - rcoef_const
4263 *
4264 */
4265 {
4266 SCIP_INTERVAL rcoef_yy_int;
4267 SCIP_INTERVAL rcoef_y_int;
4268 SCIP_INTERVAL rhs2;
4269 SCIP_Real b;
4270
4271 /* setup rcoef_yy, rcoef_y and -rhs-rcoef_const as intervals */
4272 SCIPintervalSet(&rcoef_yy_int, (SCIP_Real)rcoef_yy);
4273 SCIPintervalSet(&rcoef_y_int, (SCIP_Real)rcoef_y);
4274 SCIPintervalSetBounds(&rhs2, (SCIP_Real)(-rhs.sup - rcoef_const), (SCIP_Real)(-rhs.inf - rcoef_const));
4275
4276 /* first find all y >= 0 such that rcoef_y * y + rcoef_yy * y^2 in -rhs2, if ybnds.sup >= 0.0
4277 * and evaluate -b(y) w.r.t. these values
4278 */
4279 if( ybnds.sup >= 0.0 )
4280 {
4281 SCIP_INTERVAL ypos;
4282
4283 SCIPintervalSolveUnivariateQuadExpressionPositive(infinity, &ypos, rcoef_yy_int, rcoef_y_int, rhs2, ybnds);
4284 if( !SCIPintervalIsEmpty(infinity, ypos) )
4285 {
4286 assert(ypos.inf >= 0.0); /* we computed only positive solutions above */
4287 b = CALCB(ypos.inf);
4288 minvalleft = MIN(minvalleft, -b);
4289 maxvalleft = MAX(maxvalleft, -b);
4290 minvalright = MIN(minvalright, -b);
4291 maxvalright = MAX(maxvalright, -b);
4292
4293 if( ypos.sup < infinity )
4294 {
4295 b = CALCB(ypos.sup);
4296 minvalleft = MIN(minvalleft, -b);
4297 maxvalleft = MAX(maxvalleft, -b);
4298 minvalright = MIN(minvalright, -b);
4299 maxvalright = MAX(maxvalright, -b);
4300 }
4301 else
4302 {
4303 /* -b(y) = - (bx + axy * y) / (2.0 * sqrt(ax)) -> -sign(axy)*infinity for y -> infinity */
4304 if( axy > 0.0 )
4305 {
4306 minvalleft = -infinity;
4307 minvalright = -infinity;
4308 }
4309 else
4310 {
4311 maxvalleft = infinity;
4312 maxvalright = infinity;
4313 }
4314 }
4315 }
4316 }
4317
4318 /* next find all y <= 0 such that rcoef_y * y + rcoef_yy * y^2 in -rhs2, if ybnds.inf < 0.0
4319 * and evaluate -b(y) w.r.t. these values
4320 * (the case y fixed to 0 has been handled in the ybnds.sup >= 0 case above)
4321 */
4322 if( ybnds.inf < 0.0 )
4323 {
4324 SCIP_INTERVAL yneg;
4325
4326 SCIPintervalSolveUnivariateQuadExpressionNegative(infinity, &yneg, rcoef_yy_int, rcoef_y_int, rhs2, ybnds);
4327 if( !SCIPintervalIsEmpty(infinity, yneg) )
4328 {
4329 if( yneg.inf > -infinity )
4330 {
4331 b = CALCB(yneg.inf);
4332 minvalleft = MIN(minvalleft, -b);
4333 maxvalleft = MAX(maxvalleft, -b);
4334 minvalright = MIN(minvalright, -b);
4335 maxvalright = MAX(maxvalright, -b);
4336 }
4337 else
4338 {
4339 /* -b(y) = - (bx + axy * y) / (2.0 * sqrt(ax)) -> sign(axy)*infinity for y -> -infinity */
4340 if( axy > 0.0 )
4341 {
4342 maxvalleft = infinity;
4343 maxvalright = infinity;
4344 }
4345 else
4346 {
4347 minvalleft = -infinity;
4348 minvalright = -infinity;
4349 }
4350 }
4351
4352 assert(yneg.sup <= 0.0); /* we computed only negative solutions above */
4353 b = CALCB(yneg.sup);
4354 minvalleft = MIN(minvalleft, -b);
4355 maxvalleft = MAX(maxvalleft, -b);
4356 minvalright = MIN(minvalright, -b);
4357 maxvalright = MAX(maxvalright, -b);
4358 }
4359 }
4360 }
4361
4362 if( rhs.inf > -infinity && xbnds.inf > -infinity && EPSGT(xbnds.inf, maxvalleft / sqrtax, 1e-9) )
4363 {
4364 /* if sqrt(ax)*x > -sqrt(r(rhs,y))-b(y), then tighten lower bound of sqrt(ax)*x to lower bound of sqrt(r(rhs,y))-b(y)
4365 * this is only possible if rhs.inf > -infinity, otherwise the value for maxvalleft is not valid (but tightening wouldn't be possible for sure anyway) */
4366 assert(EPSGE(minvalright, minvalleft, 1e-9)); /* right interval should not be above lower bound of left interval */
4367 if( minvalright > -infinity )
4368 {
4369 assert(minvalright < infinity);
4370 resultant->inf = (SCIP_Real)(minvalright / sqrtax);
4371 }
4372 }
4373 else
4374 {
4375 /* otherwise, tighten lower bound of sqrt(ax)*x to lower bound of -sqrt(r(rhs,y))-b(y) */
4376 if( minvalleft > -infinity )
4377 {
4378 assert(minvalleft < infinity);
4379 resultant->inf = (SCIP_Real)(minvalleft / sqrtax);
4380 }
4381 }
4382
4383 if( rhs.inf > -infinity && xbnds.sup < infinity && EPSLT(xbnds.sup, minvalright / sqrtax, 1e-9) )
4384 {
4385 /* if sqrt(ax)*x < sqrt(r(rhs,y))-b(y), then tighten upper bound of sqrt(ax)*x to upper bound of -sqrt(r(rhs,y))-b(y)
4386 * this is only possible if rhs.inf > -infinity, otherwise the value for minvalright is not valid (but tightening wouldn't be possible for sure anyway) */
4387 assert(EPSLE(maxvalleft, maxvalright, 1e-9)); /* left interval should not be above upper bound of right interval */
4388 if( maxvalleft < infinity )
4389 {
4390 assert(maxvalleft > -infinity);
4391 resultant->sup = (SCIP_Real)(maxvalleft / sqrtax);
4392 }
4393 }
4394 else
4395 {
4396 /* otherwise, tighten upper bound of sqrt(ax)*x to upper bound of sqrt(r(rhs,y))-b(y) */
4397 if( maxvalright < infinity )
4398 {
4399 assert(maxvalright > -infinity);
4400 resultant->sup = (SCIP_Real)(maxvalright / sqrtax);
4401 }
4402 }
4403
4404 resultant->inf -= 1e-10 * REALABS(resultant->inf);
4405 resultant->sup += 1e-10 * REALABS(resultant->sup);
4406
4407#undef CALCB
4408#undef CALCR
4409 }
4410 else
4411 {
4412 /* case ax == 0 */
4413
4414 SCIP_Real c;
4415 SCIP_Real d;
4416 SCIP_Real ymin;
4417 SCIP_Real minval;
4418 SCIP_Real maxval;
4419
4420 /* consider -bx / axy in ybnds, i.e., bx + axy y can be 0 */
4421 if( EPSGE(-bx / axy, ybnds.inf, 1e-9) && EPSLE(-bx / axy, ybnds.sup, 1e-9) )
4422 {
4423 /* write as (bx + axy y) * x \in (c - ay y^2 - by y)
4424 * and estimate bx + axy y and c - ay y^2 - by y by intervals independently
4425 * @todo can we do better, as in the case where bx + axy y is bounded away from 0?
4426 */
4427 SCIP_INTERVAL lincoef;
4428 SCIP_INTERVAL myrhs;
4429 SCIP_INTERVAL tmp;
4430
4431 if( xbnds.inf < 0.0 && xbnds.sup > 0.0 )
4432 {
4433 /* if (bx + axy y) can be arbitrary small and x be both positive and negative,
4434 * then nothing we can tighten here
4435 */
4436 SCIPintervalSetBounds(resultant, xbnds.inf, xbnds.sup);
4437 return;
4438 }
4439
4440 /* store interval for (bx + axy y) in lincoef */
4441 SCIPintervalMulScalar(infinity, &lincoef, ybnds, axy);
4442 SCIPintervalAddScalar(infinity, &lincoef, lincoef, bx);
4443
4444 /* store interval for (c - ay y^2 - by y) in myrhs */
4445 SCIPintervalSet(&tmp, by);
4446 SCIPintervalQuad(infinity, &tmp, ay, tmp, ybnds);
4447 SCIPintervalSub(infinity, &myrhs, rhs, tmp);
4448
4449 if( lincoef.inf == 0.0 && lincoef.sup == 0.0 )
4450 {
4451 /* equation became 0.0 \in myrhs */
4452 if( myrhs.inf <= 0.0 && myrhs.sup >= 0.0 )
4453 *resultant = xbnds;
4454 else
4455 SCIPintervalSetEmpty(resultant);
4456 }
4457 else if( xbnds.inf >= 0.0 )
4458 {
4459 SCIP_INTERVAL a_;
4460
4461 /* need only positive solutions */
4462 SCIPintervalSet(&a_, 0.0);
4463 SCIPintervalSolveUnivariateQuadExpressionPositive(infinity, resultant, a_, lincoef, myrhs, xbnds);
4464 }
4465 else
4466 {
4467 SCIP_INTERVAL a_;
4468 SCIP_INTERVAL xbndsneg;
4469
4470 assert(xbnds.sup <= 0.0);
4471
4472 /* need only negative solutions */
4473 SCIPintervalSet(&a_, 0.0);
4474 SCIPintervalSetBounds(&lincoef, -lincoef.sup, -lincoef.inf);
4475 SCIPintervalSetBounds(&xbndsneg, -xbnds.sup, -xbnds.inf);
4476 SCIPintervalSolveUnivariateQuadExpressionPositive(infinity, resultant, a_, lincoef, myrhs, xbndsneg);
4477 if( !SCIPintervalIsEmpty(infinity, *resultant) )
4478 SCIPintervalSetBounds(resultant, -resultant->sup, -resultant->inf);
4479 }
4480
4481 return;
4482 }
4483
4484 minval = infinity;
4485 maxval = -infinity;
4486
4487 /* compute a lower bound on x */
4488 if( bx + axy * (axy > 0.0 ? ybnds.inf : ybnds.sup) > 0.0 )
4489 c = rhs.inf;
4490 else
4491 c = rhs.sup;
4492
4493 if( c > -infinity && c < infinity )
4494 {
4495 if( ybnds.inf <= -infinity )
4496 {
4497 /* limit is ay/axy * infinity if ay != 0.0 and -by/axy otherwise */
4498 if( EPSZ(ay, 1e-9) )
4499 minval = -by / axy;
4500 else if( ay * axy < 0.0 )
4501 minval = -infinity;
4502 }
4503 else
4504 {
4505 val = (c - ay * ybnds.inf * ybnds.inf - by * ybnds.inf) / (bx + axy * ybnds.inf);
4506 minval = MIN(val, minval);
4507 }
4508
4509 if( ybnds.sup >= infinity )
4510 {
4511 /* limit is -ay/axy * infinity if ay != 0.0 and -by/axy otherwise */
4512 if( EPSZ(ay, 1e-9) )
4513 minval = MIN(minval, -by / axy);
4514 else if( ay * axy > 0.0 )
4515 minval = -infinity;
4516 }
4517 else
4518 {
4519 val = (c - ay * ybnds.sup * ybnds.sup - by * ybnds.sup) / (bx + axy * ybnds.sup);
4520 minval = MIN(val, minval);
4521 }
4522
4523 if( !EPSZ(ay, 1e-9) )
4524 {
4525 d = ay * (ay * bx * bx - axy * (bx * by + axy * c));
4526 if( !EPSN(d, 1e-9) )
4527 {
4528 ymin = -ay * bx + sqrt(MAX(d, 0.0));
4529 ymin /= axy * ay;
4530
4531 if( ymin > ybnds.inf && ymin < ybnds.sup )
4532 {
4533 assert(bx + axy * ymin != 0.0);
4534
4535 val = (c - ay * ymin * ymin - by * ymin) / (bx + axy * ymin);
4536 minval = MIN(val, minval);
4537 }
4538
4539 ymin = -ay * bx - sqrt(MAX(d, 0.0));
4540 ymin /= axy * ay;
4541
4542 if(ymin > ybnds.inf && ymin < ybnds.sup )
4543 {
4544 assert(bx + axy * ymin != 0.0);
4545
4546 val = (c - ay * ymin * ymin - by * ymin) / (bx + axy * ymin);
4547 minval = MIN(val, minval);
4548 }
4549 }
4550 }
4551 }
4552 else
4553 {
4554 minval = -infinity;
4555 }
4556
4557 /* compute an upper bound on x */
4558 if( bx + axy * (axy > 0.0 ? ybnds.inf : ybnds.sup) > 0.0 )
4559 c = rhs.sup;
4560 else
4561 c = rhs.inf;
4562
4563 if( c > -infinity && c < infinity )
4564 {
4565 if( ybnds.inf <= -infinity )
4566 {
4567 /* limit is ay/axy * infinity if ay != 0.0 and -by/axy otherwise */
4568 if( EPSZ(ay, 1e-9) )
4569 maxval = -by / axy;
4570 else if( ay * axy > 0.0 )
4571 maxval = infinity;
4572 }
4573 else
4574 {
4575 val = (c - ay * ybnds.inf * ybnds.inf - by * ybnds.inf) / (bx + axy * ybnds.inf);
4576 maxval = MAX(val, maxval);
4577 }
4578
4579 if( ybnds.sup >= infinity )
4580 {
4581 /* limit is -ay/axy * infinity if ay != 0.0 and -by/axy otherwise */
4582 if( EPSZ(ay, 1e-9) )
4583 maxval = MAX(maxval, -by / axy);
4584 else if( ay * axy < 0.0 )
4585 maxval = infinity;
4586 }
4587 else
4588 {
4589 val = (c - ay * ybnds.sup * ybnds.sup - by * ybnds.sup) / (bx + axy * ybnds.sup);
4590 maxval = MAX(val, maxval);
4591 }
4592
4593 if( !EPSZ(ay, 1e-9) )
4594 {
4595 d = ay * (ay * bx * bx - axy * (bx * by + axy * c));
4596 if( !EPSN(d, 1e-9) )
4597 {
4598 ymin = ay * bx + sqrt(MAX(d, 0.0));
4599 ymin /= axy * ay;
4600
4601 if( ymin > ybnds.inf && ymin < ybnds.sup )
4602 {
4603 assert(bx + axy * ymin != 0.0); /* the case -bx/axy in ybnds was handled aboved */
4604 val = (c - ay * ymin * ymin - by * ymin) / (bx + axy * ymin);
4605 maxval = MAX(val, maxval);
4606 }
4607
4608 ymin = ay * bx - sqrt(MAX(d, 0.0));
4609 ymin /= axy * ay;
4610
4611 if( ymin > ybnds.inf && ymin < ybnds.sup )
4612 {
4613 assert(bx + axy * ymin != 0.0); /* the case -bx/axy in ybnds was handled aboved */
4614 val = (c - ay * ymin * ymin - by * ymin) / (bx + axy * ymin);
4615 maxval = MAX(val, maxval);
4616 }
4617 }
4618 }
4619 }
4620 else
4621 {
4622 maxval = infinity;
4623 }
4624
4625 if( minval > -infinity )
4626 resultant->inf = minval - 1e-10 * REALABS(minval);
4627 else
4628 resultant->inf = -infinity;
4629 if( maxval < infinity )
4630 resultant->sup = maxval + 1e-10 * REALABS(maxval);
4631 else
4632 resultant->sup = infinity;
4633 SCIPintervalIntersect(resultant, *resultant, xbnds);
4634 }
4635}
4636
4637/** propagates a weighted sum of intervals in a given interval
4638 *
4639 * Given \f$\text{constant} + \sum_i \text{weights}_i \text{operands}_i \in \text{rhs}\f$,
4640 * computes possibly tighter interval for each term.
4641 *
4642 * @attention Valid values are returned in resultants only if any tightening has been found and no empty interval, that is, function returns with non-zero and `*infeasible` = FALSE.
4643 *
4644 * @return Number of terms for which resulting interval is smaller than operand interval.
4645 */
4647 SCIP_Real infinity, /**< value for infinity in interval arithmetics */
4648 int noperands, /**< number of operands (intervals) to propagate */
4649 SCIP_INTERVAL* operands, /**< intervals to propagate */
4650 SCIP_Real* weights, /**< weights of intervals in sum */
4651 SCIP_Real constant, /**< constant in sum */
4652 SCIP_INTERVAL rhs, /**< right-hand-side interval */
4653 SCIP_INTERVAL* resultants, /**< array to store propagated intervals, if any reduction is found at all (check return code and *infeasible) */
4654 SCIP_Bool* infeasible /**< buffer to store if propagation produced empty interval */
4655 )
4656{
4657 SCIP_ROUNDMODE prevroundmode;
4658 SCIP_INTERVAL childbounds;
4659 SCIP_Real minlinactivity;
4660 SCIP_Real maxlinactivity;
4661 int minlinactivityinf;
4662 int maxlinactivityinf;
4663 int nreductions = 0;
4664 int c;
4665
4666 assert(noperands > 0);
4667 assert(operands != NULL);
4668 assert(weights != NULL);
4669 assert(resultants != NULL);
4670 assert(infeasible != NULL);
4671
4672 *infeasible = FALSE;
4673
4674 /* not possible to conclude finite bounds if the rhs is [-inf,inf] */
4675 if( SCIPintervalIsEntire(infinity, rhs) )
4676 return 0;
4677
4678 prevroundmode = SCIPintervalGetRoundingMode();
4680
4681 minlinactivity = constant;
4682 maxlinactivity = -constant; /* use -constant because of the rounding mode */
4683 minlinactivityinf = 0;
4684 maxlinactivityinf = 0;
4685
4686 SCIPdebugMessage("reverse prop with %d children: %.20g", noperands, constant);
4687
4688 /* shift coefficients into the intervals of the children (using resultants as working memory)
4689 * compute the min and max activities
4690 */
4691 for( c = 0; c < noperands; ++c )
4692 {
4693 childbounds = operands[c];
4694 SCIPdebugPrintf(" %+.20g*[%.20g,%.20g]", weights[c], childbounds.inf, childbounds.sup);
4695
4696 if( SCIPintervalIsEmpty(infinity, childbounds) )
4697 {
4698 *infeasible = TRUE;
4699 c = noperands; /* signal for terminate code to not copy operands to resultants because we return *infeasible == TRUE */ /*lint !e850*/
4700 goto TERMINATE;
4701 }
4702
4703 SCIPintervalMulScalar(infinity, &resultants[c], childbounds, weights[c]);
4704
4705 if( resultants[c].sup >= infinity )
4706 ++maxlinactivityinf;
4707 else
4708 {
4709 assert(resultants[c].sup > -infinity);
4710 maxlinactivity -= resultants[c].sup;
4711 }
4712
4713 if( resultants[c].inf <= -infinity )
4714 ++minlinactivityinf;
4715 else
4716 {
4717 assert(resultants[c].inf < infinity);
4718 minlinactivity += resultants[c].inf;
4719 }
4720 }
4721 maxlinactivity = -maxlinactivity; /* correct sign */
4722
4723 SCIPdebugPrintf(" = [%.20g,%.20g] in rhs = [%.20g,%.20g]\n",
4724 minlinactivityinf ? -infinity : minlinactivity,
4725 maxlinactivityinf ? infinity : maxlinactivity,
4726 rhs.inf, rhs.sup);
4727
4728 /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
4729 if( (minlinactivityinf >= 2 || rhs.sup >= infinity) && (maxlinactivityinf >= 2 || rhs.inf <= -infinity) )
4730 {
4731 c = noperands; /* signal for terminate code that it doesn't need to copy operands to resultants because we return nreductions==0 */
4732 goto TERMINATE;
4733 }
4734
4735 for( c = 0; c < noperands; ++c )
4736 {
4737 /* upper bounds of c_i is
4738 * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
4739 * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
4740 */
4741 SCIPintervalSetEntire(infinity, &childbounds);
4742 if( rhs.sup < infinity )
4743 {
4744 /* we are still in downward rounding mode, so negate and negate to get upward rounding */
4745 if( resultants[c].inf <= -infinity && minlinactivityinf <= 1 )
4746 {
4747 assert(minlinactivityinf == 1);
4748 childbounds.sup = SCIPintervalNegateReal(minlinactivity - rhs.sup);
4749 }
4750 else if( minlinactivityinf == 0 )
4751 {
4752 childbounds.sup = SCIPintervalNegateReal(minlinactivity - rhs.sup - resultants[c].inf);
4753 }
4754 }
4755
4756 /* lower bounds of c_i is
4757 * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
4758 * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
4759 */
4760 if( rhs.inf > -infinity )
4761 {
4762 if( resultants[c].sup >= infinity && maxlinactivityinf <= 1 )
4763 {
4764 assert(maxlinactivityinf == 1);
4765 childbounds.inf = rhs.inf - maxlinactivity;
4766 }
4767 else if( maxlinactivityinf == 0 )
4768 {
4769 childbounds.inf = rhs.inf - maxlinactivity + resultants[c].sup;
4770 }
4771 }
4772
4773 SCIPdebugMessage("child %d: %.20g*x in [%.20g,%.20g]", c, weights[c], childbounds.inf, childbounds.sup);
4774
4775 /* if interval arithmetics works correctly, then childbounds cannot be empty, which is also asserted in SCIPintervalDivScalar below
4776 * however, if running under valgrind, then interval arithmetics does not work correctly and thus one may run into an assert in SCIPintervalDivScalar
4777 * so this check avoids this by declaring the propagation to result in an empty interval (thus only do if asserts are on)
4778 */
4779#ifndef NDEBUG
4780 if( SCIPintervalIsEmpty(infinity, childbounds) )
4781 {
4782 *infeasible = TRUE;
4783 c = noperands; /*lint !e850*/
4784 goto TERMINATE;
4785 }
4786#endif
4787
4788 /* divide by the child coefficient */
4789 SCIPintervalDivScalar(infinity, &childbounds, childbounds, weights[c]);
4790
4791 SCIPdebugPrintf(" -> x = [%.20g,%.20g]\n", childbounds.inf, childbounds.sup);
4792
4793 SCIPintervalIntersect(&resultants[c], operands[c], childbounds);
4794 if( SCIPintervalIsEmpty(infinity, resultants[c]) )
4795 {
4796 *infeasible = TRUE;
4797 c = noperands; /*lint !e850*/
4798 goto TERMINATE;
4799 }
4800
4801 if( resultants[c].inf != operands[c].inf || resultants[c].sup != operands[c].sup )
4802 ++nreductions;
4803 }
4804
4805TERMINATE:
4806 SCIPintervalSetRoundingMode(prevroundmode);
4807
4808 if( c < noperands )
4809 {
4810 BMScopyMemoryArray(&resultants[c], &operands[c], noperands - c); /*lint !e776 !e866*/
4811 }
4812
4813 return nreductions;
4814}
SCIP_VAR * a
Definition: circlepacking.c:66
SCIP_VAR ** b
Definition: circlepacking.c:65
SCIP_VAR ** y
Definition: circlepacking.c:64
SCIP_VAR ** x
Definition: circlepacking.c:63
common defines and data types used in all packages of SCIP
#define NULL
Definition: def.h:248
#define EPSGE(x, y, eps)
Definition: def.h:187
#define EPSISINT(x, eps)
Definition: def.h:195
#define SCIP_REAL_MAX
Definition: def.h:158
#define SCIP_Bool
Definition: def.h:91
#define EPSLE(x, y, eps)
Definition: def.h:185
#define MIN(x, y)
Definition: def.h:224
#define MAX3(x, y, z)
Definition: def.h:228
#define SCIP_Real
Definition: def.h:156
#define EPSLT(x, y, eps)
Definition: def.h:184
#define ABS(x)
Definition: def.h:216
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define EPSN(x, eps)
Definition: def.h:190
#define SCIP_REAL_MIN
Definition: def.h:159
#define REALABS(x)
Definition: def.h:182
#define EPSGT(x, y, eps)
Definition: def.h:186
#define EPSZ(x, eps)
Definition: def.h:188
#define infinity
Definition: gastrans.c:80
SCIP_Real SCIPnextafter(SCIP_Real from, SCIP_Real to)
Definition: misc.c:9440
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11162
void SCIPintervalMulSup(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSetRoundingModeUpwards(void)
void SCIPintervalIntersectEps(SCIP_INTERVAL *resultant, SCIP_Real eps, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalAddSup(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalMulScalarInf(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
void SCIPintervalSetRoundingModeDownwards(void)
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalScalprodScalarsInf(SCIP_Real infinity, SCIP_INTERVAL *resultant, int length, SCIP_INTERVAL *operand1, SCIP_Real *operand2)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Bool SCIPintervalIsPositiveInfinity(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_Real SCIPintervalPowerScalarIntegerSup(SCIP_Real operand1, int operand2)
void SCIPintervalSquareRoot(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalMulInf(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalScalprodScalarsSup(SCIP_Real infinity, SCIP_INTERVAL *resultant, int length, SCIP_INTERVAL *operand1, SCIP_Real *operand2)
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
void SCIPintervalSetRoundingModeToNearest(void)
void SCIPintervalPower(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds)
void SCIPintervalSignPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Real SCIPintervalPowerScalarIntegerInf(SCIP_Real operand1, int operand2)
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
void SCIPintervalScalprodScalars(SCIP_Real infinity, SCIP_INTERVAL *resultant, int length, SCIP_INTERVAL *operand1, SCIP_Real *operand2)
void SCIPintervalUnify(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalAbs(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_Real SCIPintervalAbsMax(SCIP_INTERVAL interval)
void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
void SCIPintervalSetRoundingModeTowardsZero(void)
void SCIPintervalCos(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalSolveBivariateQuadExpressionAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
void SCIPintervalMax(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalIntersect(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSquare(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
int SCIP_ROUNDMODE
Definition: intervalarith.h:65
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
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)
SCIP_Bool SCIPintervalHasRoundingControl(void)
void SCIPintervalSin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalSolveUnivariateQuadExpressionPositive(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
void SCIPintervalAddInf(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalMin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalAddVectors(SCIP_Real infinity, SCIP_INTERVAL *resultant, int length, SCIP_INTERVAL *operand1, SCIP_INTERVAL *operand2)
SCIP_Bool SCIPintervalIsNegativeInfinity(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
void SCIPintervalReciprocal(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalPowerScalarInteger(SCIP_INTERVAL *resultant, SCIP_Real operand1, int operand2)
void SCIPintervalEntropy(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalMul(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalPowerScalarScalar(SCIP_INTERVAL *resultant, SCIP_Real operand1, SCIP_Real operand2)
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
void SCIPintervalSign(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
void SCIPintervalLog(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
void SCIPintervalMulScalarSup(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Bool SCIPintervalAreDisjointEps(SCIP_Real eps, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSolveUnivariateQuadExpressionNegative(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds)
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
void SCIPintervalSolveUnivariateQuadExpressionPositiveAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_Real lincoeff, SCIP_Real rhs, SCIP_INTERVAL xbnds)
void SCIPintervalQuadBivar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_Bool SCIPintervalAreDisjoint(SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPintervalPropagateWeightedSum(SCIP_Real infinity, int noperands, SCIP_INTERVAL *operands, SCIP_Real *weights, SCIP_Real constant, SCIP_INTERVAL rhs, SCIP_INTERVAL *resultants, SCIP_Bool *infeasible)
void SCIPintervalExp(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSetRational(SCIP_INTERVAL *resultant, SCIP_RATIONAL *value)
void SCIPintervalScalprod(SCIP_Real infinity, SCIP_INTERVAL *resultant, int length, SCIP_INTERVAL *operand1, SCIP_INTERVAL *operand2)
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_Real SCIPrationalRoundReal(SCIP_RATIONAL *rational, SCIP_ROUNDMODE_RAT roundmode)
Definition: rational.cpp:2110
static const double pi_d_l
#define SCIP_ROUND_NEAREST
static SCIP_Real negate(SCIP_Real x)
static SCIP_ROUNDMODE intervalGetRoundingMode(void)
#define SCIP_ROUND_ZERO
#define CALCB(y)
#define CALCR(c, y)
#define SCIP_ROUND_UPWARDS
static const double pi_d_u
#define SCIP_ROUND_DOWNWARDS
static void intervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
interval arithmetics for provable bounds
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
SCIP_Real SCIPnegateReal(SCIP_Real x)
Definition: misc.c:10473
internal miscellaneous methods
real eps
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPdebugMessage
Definition: pub_message.h:96
#define SCIPdebugPrintf
Definition: pub_message.h:99
wrapper for rational number arithmetic
SCIP_Real sup
Definition: intervalarith.h:57
SCIP_Real inf
Definition: intervalarith.h:56
@ SCIP_R_ROUND_UPWARDS
Definition: type_rational.h:58
@ SCIP_R_ROUND_DOWNWARDS
Definition: type_rational.h:57