On this page:
ival
ival?
ival-lo
ival-hi
ival-pi
ival-e
2.1 Interval Operations
ival-add
ival-sub
ival-neg
ival-mul
ival-div
ival-fabs
ival-sqrt
ival-cbrt
ival-hypot
ival-exp
ival-exp2
ival-exp2m1
ival-log
ival-log2
ival-log10
ival-log1p
ival-logb
ival-asin
ival-acos
ival-atan
ival-sinh
ival-cosh
ival-tanh
ival-asinh
ival-acosh
ival-atanh
ival-erf
ival-erfc
ival-rint
ival-round
ival-ceil
ival-floor
ival-trunc
ival-fmin
ival-fmax
ival-copysign
ival-fdim
ival-fma
ival-pow
ival-sin
ival-cos
ival-tan
ival-atan2
ival-fmod
ival-remainder
ival-tgamma
ival-lgamma
ival-sort
2.2 Interval Helper Functions
monotonic->ival
comonotonic->ival
ival-union
ival-split
2.3 Boolean Intervals
ival-true
ival-false
ival-uncertain
ival-<
ival-<=
ival->
ival->=
ival-==
ival-!=
ival-and
ival-or
ival-not
ival-if
2.4 Error Intervals
ival-error?
ival-illegal
ival-assert
ival-then
2.5 Movability flags
close-enough->ival
8.17.0.1

2 Interval Arithmetic🔗ℹ

A standard Rival interval contains two bigfloat? values and includes both endpoints. Neither endpoint is allowed to be +nan.bf.

procedure

(ival lo [hi])  ival?

  lo : (or/c bigfloat? boolean?)
  hi : (or/c bigfloat? boolean?) = lo
Constructs an interval given two endpoints lo and hi. If hi isn’t given, the interval contains a single point, lo. Single-point intervals are considered immovable, while all other intervals are considered movable. If either endpoint is +nan.bf, an illegal interval is returned.

You can also use the ival form for matches:

> (define x (ival 0.bf 2.bf))
> x

(ival 0.bf (bf 2))

> (match-define (ival lo hi) (ival-sqrt x))
> lo

0.bf

> hi

(bf #e1.414213562373095048801688724209698078575)

This is the preferred way to access interval endpoints.

procedure

(ival? obj)  boolean?

  obj : any/c
Determines whether an object is an interval.

procedure

(ival-lo x)  (or/c bigfloat? boolean?)

  x : ival?
(ival-hi x)  (or/c bigfloat? boolean?)
  x : ival?
These accessor methods provide an alternative way of accessing the two endpoints of an interval when a match is not convenient.

procedure

(ival-pi)  ival?

(ival-e)  ival?
Rival also provides two interval constants. Since π and e are not exact bigfloat? values, these constants are implemented as functions, which return different intervals at different bf-precisions.

2.1 Interval Operations🔗ℹ

Rival aims to ensure three properties of all helper functions:

Weak completeness (tightness) is the strongest possible property, while soundness (validity) is the weakest, with refinement somewhere in between.

procedure

(ival-add a b)  ival?

  a : ival?
  b : ival?

procedure

(ival-sub a b)  ival?

  a : ival?
  b : ival?

procedure

(ival-neg a)  ival?

  a : ival?

procedure

(ival-mul a b)  ival?

  a : ival?
  b : ival?

procedure

(ival-div a b)  ival?

  a : ival?
  b : ival?

procedure

(ival-fabs a)  ival?

  a : ival?

procedure

(ival-sqrt a)  ival?

  a : ival?

procedure

(ival-cbrt a)  ival?

  a : ival?

procedure

(ival-hypot a b)  ival?

  a : ival?
  b : ival?

procedure

(ival-exp a)  ival?

  a : ival?

procedure

(ival-exp2 a)  ival?

  a : ival?

procedure

(ival-exp2m1 a)  ival?

  a : ival?

procedure

(ival-log a)  ival?

  a : ival?

procedure

(ival-log2 a)  ival?

  a : ival?

procedure

(ival-log10 a)  ival?

  a : ival?

procedure

(ival-log1p a)  ival?

  a : ival?

procedure

(ival-logb a)  ival?

  a : ival?

procedure

(ival-asin a)  ival?

  a : ival?

procedure

(ival-acos a)  ival?

  a : ival?

procedure

(ival-atan a)  ival?

  a : ival?

procedure

(ival-sinh a)  ival?

  a : ival?

procedure

(ival-cosh a)  ival?

  a : ival?

procedure

(ival-tanh a)  ival?

  a : ival?

procedure

(ival-asinh a)  ival?

  a : ival?

procedure

(ival-acosh a)  ival?

  a : ival?

procedure

(ival-atanh a)  ival?

  a : ival?

procedure

(ival-erf a)  ival?

  a : ival?

procedure

(ival-erfc a)  ival?

  a : ival?

procedure

(ival-rint a)  ival?

  a : ival?

procedure

(ival-round a)  ival?

  a : ival?

procedure

(ival-ceil a)  ival?

  a : ival?

procedure

(ival-floor a)  ival?

  a : ival?

procedure

(ival-trunc a)  ival?

  a : ival?

procedure

(ival-fmin a b)  ival?

  a : ival?
  b : ival?

procedure

(ival-fmax a b)  ival?

  a : ival?
  b : ival?

procedure

(ival-copysign a b)  ival?

  a : ival?
  b : ival?

procedure

(ival-fdim a b)  ival?

  a : ival?
  b : ival?
These are all interval functions with arguments in the order corresponding to the same-name math.h functions. The precision of the output can be set with bf-precision. All of these functions are weakly complete, returning the tightest possible intervals for the strongest possible guarantees.

procedure

(ival-fma a b c)  ival?

  a : ival?
  b : ival?
  c : ival?

procedure

(ival-pow a b)  ival?

  a : ival?
  b : ival?

procedure

(ival-sin a)  ival?

  a : ival?

procedure

(ival-cos a)  ival?

  a : ival?

procedure

(ival-tan a)  ival?

  a : ival?

procedure

(ival-atan2 a b)  ival?

  a : ival?
  b : ival?
These interval functions, like the previous set, are analogous to the same-name math.h functions and set their precision with bf-precision. However, these functions are more complex and do not guarantee weak completeness. We do, however, have high confidence that they satisfy the refinement property.

procedure

(ival-fmod a b)  ival?

  a : ival?
  b : ival?

procedure

(ival-remainder a b)  ival?

  a : ival?
  b : ival?
Like the others, these interval functions take arguments and return values analogous to the same-name math.h functions and produce output with bf-precision precision. However, these functions do not guarantee refinement in all cases due to several subtle double-rounding cases.

procedure

(ival-tgamma a)  ival?

  a : ival?

procedure

(ival-lgamma a)  ival?

  a : ival?
These two interval functions (which take arguments and return values analogous to the same-name math.h functions and produce output with bf-precision precision) are extremely slow, and we have only moderate confidence that these functions satisfy soundness in all cases. We do not recommended using these functions in typical use cases or at high precision.

Changed in version 1.7 of package rival: Added ival-tgamma and ival-lgamma

procedure

(ival-sort lst <)  (listof ival?)

  lst : (listof ival?)
  < : 
(-> (or/c bigfloat? boolean?)
   (or/c bigfloat? boolean?)
   boolean?)
Sorts a list of intervals using a comparator function.

2.2 Interval Helper Functions🔗ℹ

Rival provides simple helper methods to define your own interval functions.

procedure

(monotonic->ival fn)  (-> ival? ival?)

  fn : (-> bigfloat? (or/c bigfloat? boolean?))

procedure

(comonotonic->ival fn)  (-> ival? ival?)

  fn : (-> bigfloat? (or/c bigfloat? boolean?))
These functions lift a (weakly) (co-)monotonic bigfloat function to a function on intervals. A weakly monotonic function is one where larger inputs produce larger (or equal) outputs; a weakly co-monotonic function is one where larger inputs produce smaller (or equal) outputs. For example:

> (define ival-cube (monotonic->ival (lambda (x) (bf* x x x))))
> (ival-cube (ival -1.bf 3.bf))

(ival (bf -1) (bf 27))

Note that if a non-(co-)monotonic function is passed, the results will not be sound.

procedure

(ival-union a b)  ival?

  a : ival?
  b : ival?
Computes the union of two intervals. Maintains error flags, and movability flags when possible.

procedure

(ival-split a x)  
(or/c ival? #f) (or/c ival? #f)
  a : ival?
  x : bigfloat?
Splits an interval at a point, returning the two halves of that interval on either side of the split point. If the point is not within the interval, one of the two output intervals will be #f instead. This can be used to define simple, non-monotonic interval functions. For example:

> (define (ival-fabs x)
    (match/values (ival-split x 0.bf)
      [(#f hi) hi]
      [(lo #f) (ival-neg lo)]
      [(lo hi) (ival-union (ival-neg lo) hi)]))
> (ival-fabs (ival -1.bf 1.bf))

(ival -0.bf (bf 1))

2.3 Boolean Intervals🔗ℹ

Rival supports boolean intervals, whose endpoints are boolean?.

Note that an ival? must have either two bigfloat? intervals, or two boolean? intervals, never one of each. However, this constraint is not enforced by contracts or the type system.

In a boolean interval, #f is considered less than #t, yielding three boolean interval values:

value

ival-true : ival?

value

ival-false : ival?

value

ival-uncertain : ival?

Shorthands for (ival #f) and (ival #t), representing true and false, and (ival #f #t), representing an uncertain value that might be true or false.

procedure

(ival-< a ...)  ival?

  a : ival?

procedure

(ival-<= a ...)  ival?

  a : ival?

procedure

(ival-> a ...)  ival?

  a : ival?

procedure

(ival->= a ...)  ival?

  a : ival?

procedure

(ival-== a ...)  ival?

  a : ival?
Comparison operations, where all input intervals must be real intervals while the output interval is boolean. The answer can be ival-true or ival-false when, for example, intervals do not overlap. However, in many cases ival-uncertain is the only possible answer:

> (ival-< (ival -1.bf 3.bf) (ival 1.bf 5.bf))

(ival #f #t)

With zero or one argument, these functions yield ival-true, while with more arguments they function as chained comparators much like the analogous Racket comparison functions like <. Their behavior with illegal intervals is undefined.

procedure

(ival-!= a ...)  ival?

  a : ival?
Returns (ival #t) only if all input intervals do not overlap. In this way it is like a distinct? method.

Boolean intervals can be combined logically.

procedure

(ival-and a ...)  ival?

  a : ival?

procedure

(ival-or a ...)  ival?

  a : ival?

procedure

(ival-not a)  ival?

  a : ival?
The expected logical operations extended to boolean intervals using a standard tripartite logic.

procedure

(ival-if cond if-true if-false)  ival?

  cond : ival?
  if-true : ival?
  if-false : ival?
Here, cond must be a boolean interval, while if-true and if-false should be intervals of the same type, either both real or both boolean. If cond is uncertain, the union of if-true and if-false is returned.

Note that typically, uses of ival-if are incomplete because they are not flow-sensitive. For example, (if (< x 0) (- x) x) is always non-negative, but:

> (define (bad-ival-fabs x)
    (ival-if (ival-< x (ival 0.bf)) (ival-neg x) x))
> (bad-ival-fabs (ival -1.bf 1.bf))

(ival (bf -1) (bf 1))

The reason for this is that both branches, (ival-neg x) and x, evaluate to (ival -1.bf 1.bf); the condition (ival-< x (ival 0.bf)) does not refine the value of x in either branch.

2.4 Error Intervals🔗ℹ

Sometimes an interval will contain invalid inputs to some function. For example, sqrt is undefined for negative inputs! In cases like this, Rival’s output interval will only consider valid inputs:

> (ival-sqrt (ival -1.bf 1.bf))

(ival 0.bf (bf 1))

If none of the values in the interval are valid, a special ival-illegal value will be returned:

> (ival-sqrt (ival (bf -4) (bf -2)))

ival-illegal

Moreover, when an interval is computed by discarding invalid inputs, special error flags are set that can be retrieved with ival-error?:

> (ival-error? (ival-sqrt (ival 1.bf 4.bf)))

(ival #f #f)

> (ival-error? (ival-sqrt (ival -1.bf 1.bf)))

(ival #f #t)

> (ival-error? (ival-sqrt (ival (bf -4) (bf -2))))

(ival #t #t)

procedure

(ival-error? a)  ival?

  a : ival?
Returns a boolean interval indicating whether any inputs were discarded when computing a. These flags are "sticky": further computations on a will maintain the already-set error flags.

A real interval containing no values, with error flags indicating that all valid values have been discarded. All operations on ival-illegal yield an illegal interval.

procedure

(ival-assert c [msg])  ival?

  c : ival?
  msg : identity = #t
Returns an illegal interval if c is false, a legal interval if c is true, and a partially-legal one if c’s truth value is unknown. The value of the output interval is always the constant #t.

If msg is passed, it can be any value except #f, and it is stored in the error flags instead of #t. This can be used to provide the user with details on what caused the error. We recommend using a symbol or string as the error message.

procedure

(ival-then a ... b)  ival?

  a : ival?
  b : ival?
In other words, it raises an error if any of the as did, and otherwise returns b.

2.5 Movability flags🔗ℹ

The typical use case for Rival is to recompute a certain expression at ever higher bf-precision, until the computed interval is narrow enough. However, interval arithmetic is not complete. For example, due to the limitations of math/bigfloat’s underlying MPFR library, it’s impossible to compute (/ (exp x) (exp x)) for large enough values of x:

> (define x (ival (bf 1e+100)))
> (ival-div (ival-exp x) (ival-exp x))

(ival 0.bf +inf.bf)

The same result will hold for any bf-precision. While it’s impossible to detect this in all cases, Rival provides support for movability flags that can detect many such instances automatically. Movability flags are correctly propagated by all of Rival’s supported libraries, and are set by a couple of functions such as ival-exp.

The only access to movability flags is via close-enough->ival.

procedure

(close-enough->ival fn)  (-> ival? ival?)

  fn : 
(-> (or/c bigfloat? boolean?)
(or/c bigfloat? boolean?) boolean?)
The argument to close-enough is a function that determines whether two interval endpoints are close enough. The returned function can be used to determine if an interval will ever be close enough. The result will be ival-true if it is already close enough; ival-uncertain in most cases; and ival-false if Rival can prove that no evaluation at a higher precision can yield a close enough interval:

> (define (close-enough x y) (bf< (bf- y x) 1.bf))
> (define ival-close-enough? (close-enough->ival close-enough))
> (ival-close-enough? (ival 1.bf))

(ival #t #t)

> (ival-close-enough? (ival 1.bf 5.bf))

(ival #f #t)

> (define x (ival (bf 1e+100)))
> (ival-close-enough? (ival-div (ival-exp x) (ival-exp x)))

(ival #f #f)

Using movability flags via close-enough->ival can often cut short tedious timeout loops on impossible examples.

Note that, because of movability flags, there are actually many functionally different intervals with the same endpoints. For example, there are actually four different uncertain boolean intervals: regular uncertain intervals, which might become certain at higher precision; biased-true intervals, which are uncertain at this precision but which can’t be disproven true at any precision; biased-false intervals; and the provably uncertain intervals, which can’t be made certain at any higher precision. Movability flags at a ton of complexity to interval arithmetic, but Rival hides all of that from you inside close-enough->ival.