Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make decorated interval the default #590

Merged
merged 33 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c421962
Make decorated interval the default
OlivierHnt Oct 30, 2023
ecfc3ef
Remove warning
OlivierHnt Oct 30, 2023
f9d5afe
Fix decoration
OlivierHnt Oct 30, 2023
25d6630
Fix tests
OlivierHnt Oct 30, 2023
731df23
Fix tests
OlivierHnt Oct 30, 2023
d20e2df
Fix NaI
OlivierHnt Nov 1, 2023
01921a0
Minor cleanup
OlivierHnt Nov 13, 2023
0b14d21
Add docstring for `_unsafe_bareinterval`
OlivierHnt Nov 13, 2023
e9271ff
Remove decoration `bad` in favour of a new field
OlivierHnt Nov 13, 2023
45990ac
Minor cleanup
OlivierHnt Nov 14, 2023
1390772
Remove `signbit`
OlivierHnt Nov 14, 2023
70c9abf
Fix `pow` and cleanup
OlivierHnt Nov 14, 2023
56cec04
Fix tests
OlivierHnt Nov 14, 2023
5991c5b
Special display for unguaranteed interval
OlivierHnt Nov 14, 2023
9c1283e
Cleanup
OlivierHnt Nov 18, 2023
49d6c8e
Update docs
OlivierHnt Nov 18, 2023
cb6c91e
Fix doctest
OlivierHnt Nov 18, 2023
736971f
Do not error for missing docstring
OlivierHnt Nov 18, 2023
bde155f
Rename `guarantee` to `isguaranteed`
OlivierHnt Nov 27, 2023
d1ab589
Delete empty file decorations.md
OlivierHnt Nov 27, 2023
ad4bc09
Fix missing field infos in docstring
OlivierHnt Nov 27, 2023
0dd6a75
Update `isguaranteed` docstring
OlivierHnt Nov 27, 2023
795dd3b
Update docs
OlivierHnt Nov 27, 2023
a0f88ce
Ensures `NaN` is converted to a NaI
OlivierHnt Nov 28, 2023
1df80e0
Update docs
OlivierHnt Nov 28, 2023
ecbb119
Minor cleanup
OlivierHnt Nov 28, 2023
fb730de
Fix typo
OlivierHnt Dec 1, 2023
d7fcc98
Fix error for boolean functions from Base
OlivierHnt Dec 1, 2023
5d7dbf2
Add docstrings
OlivierHnt Dec 1, 2023
7844416
Fix bug
OlivierHnt Dec 1, 2023
5fb425d
Fix `StackOverflow`
OlivierHnt Dec 1, 2023
7b2def0
Fix `StackOverFlow`
OlivierHnt Dec 1, 2023
dfb71a6
Set correct cuurent version
OlivierHnt Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ makedocs(;
"Manual" => [
"Constructing intervals" => "manual/construction.md",
"Usage" => "manual/usage.md",
"Decorations" => "manual/decorations.md",
"API" => "manual/api.md"
]
]
],
warnonly = true
)

deploydocs(;
Expand Down
15 changes: 0 additions & 15 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,3 @@ If you use the IntervalArithmetic library in your publication, research, teachin

- [MPFI.jl](https://github.com/andrioni/MPFI.jl), a Julia wrapper around the [MPFI C library](http://perso.ens-lyon.fr/nathalie.revol/software.html), a multiple-precision interval arithmetic library based on MPFR
- [Intervals.jl](https://github.com/invenia/Intervals.jl), an alternative implementation of basic interval functions by Invenia Technical Computing



## History

This project began in 2014 during a masters' course in the postgraduate programs of Mathematics and Physics at the Universidad Nacional Autónoma de México. It was initially written in Python, then reinitiated in 2015 and rewritten in Julia. We thank the participants of the courses for their contribution, energy and ideas.


## Support

Financial support is acknowledged from DGAPA-UNAM PAPIME grants PE-105911 and PE-107114, and DGAPA-UNAM PAPIIT grant IN-117214.

Luis Benet acknowledges support from *Cátedra Marcos Moshinsky* (2013).

David P. Sanders acknowledges a sabbatical fellowship from CONACYT and thanks Alan Edelman and the Julia group at MIT for hosting his sabbatical visit.
208 changes: 175 additions & 33 deletions docs/src/manual/construction.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,188 @@
# Constructing intervals

Constructing an interval is the most basic operation in the library. The [`interval`](@ref) constructor is the standard way to create an interval. It accepts one or two values, and an optional bound type.
The library provides two interval types. The first one is [`BareInterval`](@ref), corresponding to a basic implementation of intervals, stored by their infimum and supremum. The second type is [`Interval`](@ref) and builds on top of bare intervals, with the additional fields `decoration` and `isguaranteed`. See the sections below.

```@repl construction
using IntervalArithmetic
setformat(:full) # print the interval in full
interval(0.1) # interval(Float64, 0.1)
interval(0.1, 0.2) # interval(Float64, 0.1, 0.2)
interval(3.1f0) # interval(Float32, 3.1f0)
interval(π) # interval(Float64, π)
interval(BigFloat, π)
interval(Inf) # not valid since infinity is not part of an interval
interval(3, 2) # not valid since the lower bound is strictly greater than the upper bound
setdisplay(:full) # print the interval in full
bareinterval(1, π) # `bareinterval(Float64, 1, π)`
interval(1, π) # `interval(Float64, 1, π)`, interval decorated with `com` (common)
```

The submodule `IntervalArithmetic.Symbols` exports the infix operator `..` as an alias for `interval`.
Therefore, we **strongly recommend the use of [`Interval`](@ref) over [`BareInterval`](@ref)** to better track the effect of functions according to the IEEE Standard 1788-2015 specifications. For instance, taking the square root of an interval discards the negative part of the interval, without any notice for bare intervals:

```@repl construction
using IntervalArithmetic.Symbols
0.1..0.2 # interval(0.1, 0.2)
sqrt(bareinterval(-1, 1)) # `sqrt(bareinterval(0, 1))`
sqrt(interval(-1, 1)) # interval decorated with `trv` (trivial)
```



### Decorations

A *decoration* is a label that indicates the status of a given interval. Decorated intervals provide valuable information on the result of evaluating a function on an initial interval.

Upon the application of a function ``f`` on an interval ``x``, the resulting interval ``f(x)`` has either one of the following decorations:

- `com` (common): ``x`` is a closed, bounded, non-empty subset of the domain of ``f``, ``f`` is continuous on the interval ``x``, and ``f(x)`` is bounded.

- `dac` (defined and continuous): ``x`` is a non-empty subset of the domain of ``f``, and ``f`` is continuous on ``x``.

- `def` (defined): ``x`` is a non-empty subset of the domain of ``f``; in other words, ``f`` is defined at each point of ``x``.

- `trv` (trivial): ``f(x)`` carries no meaningful information.

- `ill` (ill-formed): ``f(x)`` is Not an Interval (NaI).

Each decoration is paired with an integer as follows: `ill = 0`, `trv = 1`, `def = 2`, `dac = 3` and `com = 4`. Then, decorations degrade according to the propagation order `com > dac > def > trv > ill`.

One can specify a decoration when constructing intervals. Otherwise, the interval is initialised with a decoration according to the underlying bare interval:

- `com`: non-empty and bounded.

- `dac`: unbounded.

- `trv`: empty.

- `ill`: NaI.


#### Examples

##### Common

```@repl construction
x = interval(0.5, 3)
sqrt(x)
```

Both input `x` and output `sqrt(x)` are common intervals since they are closed, bounded, non-empty and that ``\sqrt`` is continuous over ``[1/2, 3]``.

Observe that these decorations, together with the fact that any element of the interval `sqrt(x)` is also in the interval `x`, imply that the [Schauder Fixed-Point Theorem](https://en.wikipedia.org/wiki/Schauder_fixed-point_theorem) is satisfied. More precisely, this computation proves the existence of a fixed-point of ``\sqrt`` in ``[1/2, 3]`` (in this simple example, ``\sqrt(1) = 1``).

##### Defined and continuous

```@repl construction
x = interval(3, Inf)
sqrt(x)
```

Both the intervals are unbounded, hence the maximum possible decoration is `dac`.

Note that overflows can also produce the decoration `dac`:

```@repl construction
x = interval(floatmax(Float64))
x + interval(1)
```

The [`±`](@ref) (`\pm<tab>`) infix operator creates the interval from the midpoint and the radius.
##### Defined and continuous

```@repl construction
0 ± 1
x = interval(-3, 4)
sign(x)
```

The various string formats are as follows:
- No string parameter or `Empty` string ("[Empty]") returns an empty interval.
- `entire` ("[entire]") and "[,]" string returns entireinterval
- "[nai]" returns `Nai{Type}`
- "[m]" returns `Interval(m,m)`
- "[l, r]" returns `Interval(l, r)`
- "m?r" returns `Interval(m-r, m+r)`
- "m?ren" returns `Interval((m-r)en, (m+r)en)`
- "m?ru" or "m?rd" returns `Interval(m, m+r)` or `Interval(m-r, m)` respectively
- "m?" returns `Interval(m + 5 precision units, m - 5 precision units)`
- "m??" returns `Interval(-Inf, +Inf)`
- "m??u" or "m??d" returns `Interval(m, +Inf)` or `Interval(-Inf, m) respectively`

!!! warning
The ``\sign`` function is discontinuous at ``0``, but is defined everywhere on the input interval, so the decoration of the result is `def`.

##### Trivial

```@repl construction
x = interval(-3.5, 4)
sqrt(x)
```

The negative part of `x` is discarded before evaluating the ``\sqrt`` function since its domain is ``[0, \infty)``. The process of discarding parts of an interval that are not in the domain of a function is called *loose evaluation*. This event has been recorded by degrading the decoration of the resulting interval to `trv`, indicating that nothing is known about the relationship between `x` and `sqrt(x)`.

In this case, we know why the decoration was reduced to `trv`. Generally, if this were just a single step in a longer calculation, a resulting decoration `trv` shows only that something like this occured at some step.

For instance,

```@repl construction
f = asin ∘ sqrt
x = interval(-3, 3)
f(x)
y = interval(0, 3)
f(y)
```

In both cases, `asin(sqrt(X))` gives a result with the decoration `trv`; to find out where things went wrong, the function must be analyzed.

```@repl construction
sqrt(x) # `f(x)` has the decoration is `trv` since `x` contains negative values
sqrt(y) # the decoration is `com`
asin(sqrt(y)) # `f(x)` has the decoration is `trv` since `sqrt(y)` contains values stricly greater than `1`
```

This shows that loose evaluation occurred in different parts of `f` for `x` and `y`.

!!! danger
The decoration `trv` is an indicator of information loss. Often this also reveals that something unexpected occured. Therefore, any interval marked by this decoration may not be trusted and the code may need to be revised.

##### Ill-formed

```@repl construction
interval(2, 1)
interval(NaN)
```

These are all examples of ill-formed intervals, resulting in the decoration `ill`.

!!! danger
The decoration `ill` is an indicator that an error has occured. Therefore, any interval marked by this decoration cannot be trusted and the code needs to be debugged.



### Guarantee

A *guarantee* is yet an other label, independent of decorations, and not described by the IEEE Standard 1788-2015 specifications. Its purpose is to accomodate for Julia's extensive conversion and promotion system, while retaining reliability in computations. Specifically, an interval `x` constructed via [`interval`](@ref) satisfies `isguaranteed(x) == true`. However, if a call to `convert(::Type{<:Interval}, ::Real)` occurs, then the resulting interval `x` satisfies `isguaranteed(x) == false`.

OlivierHnt marked this conversation as resolved.
Show resolved Hide resolved
In contrast, a [`BareInterval`](@ref) can only be constructed via [`bareinterval`](@ref), it is not a subtype of `Real`, and there are no allowed conversion with `Number`. Thus, this interval type is always guaranteed.

!!! danger
A user interested in validated numerics should **always** have a resulting interval for which [`isguaranteed`](@ref) is `true`.



## More constructors

The submodule `IntervalArithmetic.Symbols` exports the infix operator `..` and `±` as an alias for `interval`; this submodule must be explicitly imported.

```@repl construction
using IntervalArithmetic.Symbols
0.1 .. 0.2 # interval(0.1, 0.2; format = :standard)
0.1 ± 0.2 # interval(0.1, 0.2; format = :midpoint)
```

Moreover, one can parse strings into intervals. The various string formats are the following:

- `"[m]"` is equivalent to `interval(m, m)`.

- `"[l, r]"` is equivalent to `interval(l, r)`.

- `"m?r"` is equivalent to `interval(m-r, m+r)`.

- `"m?ren"` is equivalent to `interval((m-r)*1en, (m+r)*1en)`.

- `"m?rd"` is equivalent to `interval(m-r, m)`.

- `"m?ru"` is equivalent to `interval(m, m+r)`.

- `"m?"` is equivalent to `interval(m + 5 precision units, m - 5 precision units)`.

- `"m??"` is equivalent to `interval(-Inf, +Inf)`.

- `"m??d"` is equivalent to `interval(-Inf, m)`.

- `"m??u"` is equivalent to `interval(m, +Inf)`.

- `"[Entire]"`, `"[entire]"` and `"[,]"` are equivalent to `entireinterval()`.

- `"[Empty]"`, `"[empty]"` and `"[]"` are equivalent to `emptyinterval()`.

- `"[nai]"` and any other unsupported string formats are equivalent to `nai()`.

To add a specific decoration, add `"_com"`, `"_dac"`, `"_dec"`, `"_trv"` and `"_ill"` at the end of the string.

!!! danger
Most real numbers cannot be exactly represented by floating-points. In such cases, the literal expression is rounded at parse time. To construct an interval enclosing the true real number, one must rely on the string constructor mentioned above.

For instance, consider
Expand All @@ -49,15 +191,15 @@ The various string formats are as follows:
x = 0.1
```

This appears to store the real number ``1/10`` in a variable `x` of type `Float64`. Yet,
This appears to store the real number ``1/10`` in a variable `x` of type `Float64`. Yet,

```@repl construction
x > 1//10
```

Hence, the floating-point `0.1` is (slightly) greater than the real number ``1/10`` since ``1/10`` *cannot be represented exactly in binary floating-point arithmetic, at any precision*. The true value must be approximated by a floating-point number with fixed precision -- this procedure is called rounding.
Hence, the floating-point `0.1` is (slightly) greater than the real number ``1/10`` since ``1/10`` **cannot be represented exactly in binary floating-point arithmetic, at any precision**. The true value must be approximated by a floating-point number with fixed precision -- this procedure is called rounding.

In particular, this implies that `interval(0.1)` *does not* contain the real number ``1/10``. A valid interval containing the real number ``1/10`` can be constructed by
In particular, this implies that `interval(0.1)` **does not** contain the real number ``1/10``. A valid interval containing the real number ``1/10`` can be constructed by

```@repl construction
I"0.1"
Expand Down
Loading
Loading