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