ThickNumbers
A ThickNumber{T}
is an abstract type denoting objects that act like numbers–they have standard algebraic operations +
, -
, *
, and /
–but also have properties of a connected set, specifically occupying some "width," e.g., a segment of the real number line. Examples of possible concrete subtypes include intervals, gaussian random variables, and potentially others. While the parameter T
in ThickNumber
does not necessarily have to be T<:Real
, it should have an ordering so that "width" has some meaning.
This documentation is aimed at:
- users who what to know how to manipulate
ThickNumber
objects. Users should read:- The Fundamental Principle of ThickNumbers (FPTN), which explains key differences between
ThickNumber
s and "point" numbers - The ThickNumber API, which lists the main functions used to manipulate ThickNumbers.
- The Fundamental Principle of ThickNumbers (FPTN), which explains key differences between
- developers who want to create a new
ThickNumber
subtype. Developers should read the two sections above followed by Creating a new ThickNumber subtype, and then refer to the API reference sections as needed.
The Fundamental Principle of ThickNumbers (FPTN)
An important issue that must be understood at the outset is a generalization of the Fundamental Theorem of Interval Arithmetic (Moore, R. E. 1966, Interval analysis), which we adopt as:
If f(x::T)
is a function and X
a ThickNumber{T}
, then f(X)
should either error or return another ThickNumber
such that f(x) ∈ f(X)
for "most" or all x ∈ X
. This principle generalizes to functions with more than one argument, f(x::T, y::T)
, but does not include mixtures of argument types like f(x::T, X::ThickNumber{T})
.
Here, "most" is directed at possible subtypes like Gaussian random variables, where one would expect that f(X)
returns a value appropriate for x
drawn near the center of the distribution X
but not necessarily for those in the tails.
FPTN has subtle implications, particularly for 2-argument functions intended to return a Bool
. For example, ==(x, y)
is a standard 2-argument Julia function, and the FPTN implies that ==(X::ThickNumber, Y::ThickNumber)
cannot be defined (it must error): after all, returning true
would imply that x == y
for any choice x ∈ X
and y ∈ Y
, and this is impossible unless X
and Y
are either empty or each contain only a single value. Concretely, if 1..3
constructs an interval, then 1..3 == 1..3
returning true
would require that 1.5 == 1.5
and also 1.5 == 2.5
since both 1.5
and 2.5
can be drawn from 1..3
. This is obviously impossible, thus having 1..3 == 1..3
return true
would be a violation of the FPTN; it must error instead.
Because numbers are iterable in Julia, set operations like X ⊆ Y
also cannot be defined (it would require that each number in X
is a subset of every number in Y
); however, operations like intersect(X, Y)
(i.e., X ∩ Y
) are valid because x ∩ y
returns ∅
if x != y
and ∅
is a subset of all other sets.
To avoid violating the FPTN, we replace operators like ==
with custom operators that work only on ThickNumber{T}
but not T
. For Base
Julia functions, a convention is to add _tn
after the standard function name: isequal_tn(X, Y)
replaces the "intent" of isequal(X, Y)
. Often these have unicode equivalents, which typically (though not always) involve a "dot" somewhere in the symbol.
See the API section below for a more complete list of these replacements.
The ThickNumber API
Let x
and y
refer to a standard "point" numbers and X
and Y
corresponding ThickNumber
s such that x ∈ X
and y ∈ Y
.
Querying values
With only a few exceptions, the names of these come from the Interval Arithmetic Standard (IEEE Std 1788-2015).
loval(X)
: return the "lower bound" (which may not be "fuzzy" for some ThickNumber subtypes) ofX
(similar toinf
in the IEEE standard, but without promising the true infimum)hival(X)
: return the "upper bound" ofX
(similar tosup
in the IEEE standard)mid(X)
: return the midpoint ofX
wid(X)
: return the width (hival - loval
) ofX
rad(X)
: return the half-width ofX
(half the value ofwid(X)
)mag(X)
: the largest absolute value contained inX
mig(X)
: the smallest absolute value contained inX
You can also check a few basic properties, like whether the values contained in X
are finite:
Type information
valuetype(X)
: return the type of numbers contained inX
(e.g.,Float64
)
Generic constructors
Each ThickNumber
subtype has its own constructor(s), but if you need a way to write generic code that works for multiple ThickNumber
subtypes, you may be able to use:
lohi
:lohi(TN, lo, hi)
creates a ThickNumberX
wheretypeof(X) <: TN
,loval(X) ≈ lo
, andhival(X) ≈ hi
. (It's approximate because of floating-point roundoff error and the fact that not all ThickNumber subtypes encode these bounds directly.)midrad
creates a ThickNumber from its midpoint and radius (seemid
andrad
).
Note that some ThickNumber subtypes might need additional arguments, so there may be some that cannot be constructed generically and for which lohi
and midrad
might error.
Comparison operators
For an explanation of why these aren't just ==
, <
, etc, read The Fundamental Principle of ThickNumbers (FPTN).
iseq_tn
(i.e.,iseq(X, Y)
, or the unicode analogX ⩦ Y
) checks equality betweenX
andY
(i.e., the replacement forx == y
)isequal_tn(X, Y)
replacesisequal(x, y)
(see the Julia docs for the subtle difference between==
andisequal
).isapprox_tn(X, Y)
(unicodeX ⩪ Y
) checks approximate equality (≈
) betweenX
andY
X ≺ Y
(typed with\prec
-TAB) andX ≻ Y
(\succ
-TAB) test whether "all" values inX
are strictly less or greater, respectively, than "all" values inY
.isless_tn(X, Y)
replacesisless(x, y)
(see the Julia docs for the subtle difference between<
andisless
)X ⪯ Y
(\preceq
-TAB) andX ⪰ Y
(\succeq
-TAB) replace<=
and>=
, respectively.
Set operations
issubset_tn
replaces⊆
(unicode:⫃
)is_strict_subset_tn
replaces⊂
(unicode:⪽
)issupset_tn
replaces⊇
(unicode:⫄
)is_strict_supset_tn
replaces⊃
(unicode:⪾
)hull
creates a number that contains its arguments
API reference
The API is described more completely in: