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