Manipulating intervals

Display modes

There are several useful output representations for intervals. The display is controlled globally by the setdisplay function, which has the following options:

  • interval output format:

    • :infsup: output of the form [1.09999, 1.30001], rounded to the current number of significant figures.

    • :full: output of the form Interval(1.0999999999999999, 1.3), as in the showfull function.

    • :midpoint: output in the midpoint-radius form, e.g. 1.2 ± 0.100001.

  • sigdigits :: Int keyword argument: number of significant digits to show in standard mode.

  • decorations :: Bool keyword argument: whether to show decorations or not.

julia> using IntervalArithmetic
julia> a = interval(1.1, pi) # default displayInterval{Float64}(1.1, 3.1415926535897936, com, true)
julia> setdisplay(; sigdigits = 10)Display options: - format: full - decorations: true (ignored) - NG flag: true (ignored) - significant digits: 10 (ignored)
julia> aInterval{Float64}(1.1, 3.1415926535897936, com, true)
julia> setdisplay(:full)Display options: - format: full - decorations: true (ignored) - NG flag: true (ignored) - significant digits: 10 (ignored)
julia> aInterval{Float64}(1.1, 3.1415926535897936, com, true)
julia> setdisplay(:midpoint)Display options: - format: midpoint - decorations: true - NG flag: true - significant digits: 10
julia> a(2.120796327 ± 1.020796327)_com
julia> setdisplay(; sigdigits = 4)Display options: - format: midpoint - decorations: true - NG flag: true - significant digits: 4
julia> a(2.121 ± 1.021)_com
julia> setdisplay(:infsup)Display options: - format: infsup - decorations: true - NG flag: true - significant digits: 4
julia> a[1.1, 3.142]_com

Arithmetic operations

Basic arithmetic operations (+, -, *, /, ^) are defined for pairs of intervals in a standard way: the result is the smallest interval containing the result of operating with each element of each interval. More precisely, for two intervals $X$ and $Y$ and an operation $\bigcirc$, we define the operation on the two intervals by

\[X \bigcirc Y \bydef \{ x \bigcirc y \,:\, x \in X \text{ and } y \in Y \}.\]

For example,

julia> using IntervalArithmetic
julia> setdisplay(:full)Display options: - format: full - decorations: true (ignored) - NG flag: true (ignored) - significant digits: 4 (ignored)
julia> X = interval(0, 1)Interval{Float64}(0.0, 1.0, com, true)
julia> Y = interval(1, 2)Interval{Float64}(1.0, 2.0, com, true)
julia> X + YInterval{Float64}(1.0, 3.0, com, true)

Due to the above definition, subtraction of two intervals may give poor enclosures:

julia> X - XInterval{Float64}(-1.0, 1.0, com, true)

Elementary functions

The main elementary functions are implemented. The functions for Interval{Float64} internally use routines from the correctly-rounded CRlibm library where possible, i.e. for the following functions defined in that library:

  • exp, expm1
  • log, log1p, log2, log10
  • sin, cos, tan
  • asin, acos, atan
  • sinh, cosh

Other functions that are implemented for Interval{Float64} internally convert to an Interval{BigFloat}, and then use routines from the MPFR library (BigFloat in Julia):

  • ^
  • exp2, exp10
  • atan, atanh

In particular, in order to obtain correct rounding for the power function (^), intervals are converted to and from BigFloat; this implies a significant slow-down in this case.

For example,

julia> X = interval(1)Interval{Float64}(1.0, 1.0, com, true)
julia> sin(X)Interval{Float64}(0.8414709848078965, 0.8414709848078966, com, true)
julia> cos(cosh(X))Interval{Float64}(0.027712143770207736, 0.02771214377020796, com, true)
julia> setprecision(BigFloat, 53)53
julia> Y = big(X)Interval{BigFloat}(1.0, 1.0, com, true)
julia> sin(Y)Interval{BigFloat}(0.8414709848078965, 0.84147098480789662, com, true)
julia> cos(cosh(Y))Interval{BigFloat}(0.027712143770207736, 0.027712143770207961, com, true)
julia> setprecision(BigFloat, 128)128
julia> sin(Y)Interval{BigFloat}(0.8414709848078965, 0.84147098480789662, com, true)

Comparisons

If the result of a comparison can be established with guarantee, it will be return, otherwise, an error is thrown.

julia> interval(1) < interval(2)true
julia> interval(1, 5) < interval(7, 9)true
julia> interval(1, 5) < interval(4.99, 9)ERROR: ArgumentError: `<` is purposely not supported for overlapping intervals. See instead `strictprecedes`
julia> interval(1.23) == interval(1.23)true
julia> interval(1.23) == interval(4.99, 9)false
julia> interval(1.23) == interval(1.2, 1.3)ERROR: ArgumentError: `==` is purposely not supported for overlapping non-thin intervals. See instead `isequal_interval`

In particular, if ... else ... end statements used for floating-points will often break with intervals.

See Philosophy for more details and why this choice was made.

Set operations

Set operations are all disallowed and error on intervals to avoid ambiguities. To perform set operations on intervals, use the *_interval equivalent explicitly, e.g. issubset_interval instead of issubset.

julia> issubset(interval(1, 2), interval(2))ERROR: ArgumentError: `issubset` is purposely not supported for intervals. See instead `issubset_interval`
julia> issubset_interval(interval(1, 2), interval(2))false
julia> intersect(interval(1, 2), interval(2))ERROR: ArgumentError: `intersect` is purposely not supported for intervals. See instead `intersect_interval`
julia> intersect_interval(interval(1, 2), interval(2))Interval{Float64}(2.0, 2.0, trv, true)

See Philosophy for more details and why this choice was made.

Piecewise functions

Since intervals don't play well with if ... else ... end statement, we provide a utility to define function by pieces:

julia> myabs = Piecewise(
           Domain{:open, :closed}(-Inf, 0) => x -> -x,
           Domain{:open, :open}(0, Inf) => identity
       )Piecewise function with 2 pieces:
  (-Inf, 0] -> Main.var"#1#2"()
  (0, Inf) -> identity
julia> myabs(-1.23)1.23
julia> myabs(interval(-1, 23))Interval{Float64}(0.0, 23.0, def, true)

The resulting function work with both standard numbers and intervals, and deal properly with the decorations of intervals.

Custom interval bounds type

A BareInterval{T} or Interval{T} have the restriction T <: Union{Rational,AbstractFloat} which is the parametric type for the bounds of the interval. Supposing one wishes to use their own numeric type MyNumType <: Union{Rational,AbstractFloat}, they must provide their own arithmetic operations (with correct rounding!).