# A Standards compliant Interval Arithmetic Library

Solving some bugs with the help of ITF1788 Test Suite to make the package a little more close to perfect is what I have worked on this summer. From "I can't solve this error, I have no idea about it" to "Hurrah!, I have finally solved it" it has really been an enriching experience for me. The way I have approached my endeavor is by taking every new error as a challenge and no matter how many hours(or days) it may take to learn about that error, it has to be solved.

`using Pkg;`

`Pkg.add("IntervalArithmetic")`

#### Brief Background

The main focus of interval arithmetic is a simple way to calculate upper and lower endpoints for the range of values of a function in one or more variables. These endpoints are not necessarily the supremum or infimum, since the precise calculation of those values can be difficult or impossible. Treatment is typically limited to real intervals, so quantities of form

formula not implemented`ITF1788`

stands for Interval Test framework for IEEE 1788, these tests are also written in Julia, and my job is to check what test is not passing in IntervalArithmetic.jl and IntervalContractors.jl and edit the packages to satisfy them. Debugging mathematical code was fun but challenging too. Since a part of my work, in these three months was on decorations and reverse functions, it is good you know about them before reading the main part of the blog.

#### Decorations

The reverse function of a function f calculates the (interval hull of) its inverse function, `f⁻¹`

. For example, `sin_rev(Y::Interval, X::Interval)`

calculates the (interval hull of) those x ∈ X such that `sin(x)`

∈ Y. This can also be thought of as an inverse function, calculating `X_new := sin⁻¹(Y) ∩ X`

. The return value is `(Y, X_new)`

. Functions such as `mul_rev(C::Interval, A::Interval, B::Interval)`

take three arguments, and correspond to `C = A * B`

; they return `(C, A_new, B_new),`

with `A_new and B_new`

similarly defined to be the corresponding inverse images of the multiplication operator in each component.

I have named my Pull requests according to the name of the files in the test suite.

#### A*. *Libieeep1788testsrev.jl

I decided to start with the biggest file in the suite which is `libieeep1788testsrev.jl`

and the first thing I needed to do was add decorations for all the reverse functions in `IntervalContractors.jl`

`Pkg.add(PackageSpec(path="https://github.com/krish8484/IntervalContractors.jl.git", rev="decorated_reverse"))`

`using IntervalContractors`

`using IntervalArithmetic`

#### Add decorations for reverse functions

I was a bit confused about how to add decorations for all the functions in `IntervalContractors.jl`

but nothing seemed to work, so that encouraged me to fall back to the standard and then I found this

This solved most of my problems and simply a trivial decoration was provided for these functions. Example,

`tan_rev(DecoratedInterval(Interval(-0x1.d02967c31p+53, 0x1.d02967c31p+53), def), DecoratedInterval(Interval(-Inf, 1.5707965), def))`

`cosh_rev(DecoratedInterval(Interval(1.0, Inf), def), DecoratedInterval(Interval(0.0, Inf), dac))`

But the decorations were not the only thing to be implemented, there were some minor bugs in the functions as well(now solved) which are mentioned below

*Power_rev* when the power is 0 (a = x^0)

There is an issue about this in the repository which was opened last year issue #25 and of course, it was pointed out by the tests as well.

After observing the outputs from other standard-compliant libraries, and thinking about the possible solution, it was finally fixed.

Now, the function returns expected outputs

`power_rev(Interval(1.0, 1.0), Interval(1.0, 1.0), 0)[2]`

`power_rev(Interval(-1.0, 0.0), Interval(5.0, 10.0), 0)[2]`

#### Function `mulrevIEEE1788`

was not returning the correct outputs

This issue was fixed by using extended_div(a function in IntervalArithmetic) in place of the '/' operator (obviously, not very easy to spot and this required a lot of time)

`mul_rev_IEEE1788(Interval(-Inf, -0.1), Interval(-2.1, -0.4))`

`mul_rev_IEEE1788(Interval(-2.0, 1.1), Interval(0.04, Inf), Interval(0.04, Inf))`

`Cosh_rev`

was not returning negative values

Apparently, this function must return negative values as well which it was not and now fixed

`cosh_rev(DecoratedInterval(Interval(0x1.8b07551d9f55p+0, 0x1.89bca168970c6p+432), com), DecoratedInterval(Interval(-Inf, 0.0), dac))`

`cosh_rev(DecoratedInterval(Interval(0x1.8b07551d9f55p+0, 0x1.89bca168970c6p+432), com))`

Apart from the above points, a default value was added to each of these functions which were required by the tests This completed `libieeep1788testsrev.jl`

.

All of the above points have been incorporated into one PR(#25).

### B. *Ieee1788-constructors.jl*

Next file to be solved was *ieee1788-constructors.jl*

#### Making `nai()`

a decorated interval

According to the standard and the tests(obviously), `nai()`

should be a decorated interval, there was also an open issue(#233) regarding this. Now,

`import Pkg; Pkg.add("IntervalArithmetic")`

`using IntervalArithmetic`

`full `

`nai()`

#### String Parsing Minor bugs in parsing strings

**1)****empty**** in ****@interval**

Now,

`"[ empty ]") (`

**2)****com**** was returned as a decoration instead of ****def****, even after it was specified as an argument**.

Now,

`"3.56?1_def") (`

A minor change to deprecate `interval_part`

to `interval`

was also done in the same PR which was an open Issue#212.

After these changes all test from `ieee1788-constructors.jl`

pass and the work is in PR#386.

Closes Issue#222.

### C. *Mpfi.jl and Fi.lib.jl*

Some new functions were implemented to complete these 2 files from the test suite, the functions are listed below, the only tough part is dealing with these files was to take care of the roundings (Phew!)

**1)****cot**

`cot(Interval(0x1.921fb745205b6p+4, 0x1.9ca9d998c8f0cp+4))`

**2)****coth**

`coth(Interval(-0x3.f03d06503caa2p+92, -0x5.9d7eeea9b9ee0p-264))`

There was an open issue(Issue#301) about the roundings of cot and coth from the previous year's JSOC/GSOC which has been solved.

**3)****cbrt**

`cbrt(Interval(-0x1856e4be527197p-354, 0xd8p0))`

Closed Issue#310

**4)****csc**

`csc(Interval(7.0, 7.0))`

**5)****csch**

`csch(Interval(0x10000000000001p-58, 0x10000000000001p-53))`

**6)****hypot**

`hypot(Interval(0x1854bfb363dc39p-50, 0x19f625847a5899p-48), Interval(0x1854bfb363dc39p-50, 0x19f625847a5899p-48))`

Closed Issue#368

**7)****sec**

`sec(Interval(-4.0, -4.0))`

**8)****sech**

`sech(Interval(0.0, +8.0))`

Above work can be found at PR#390

### D. C-xsc.jl

The only thing needed to be done in the file is to add a new function which is the `nthroot`

function, it was added and now all tests from this file satisfy...

`julia> nthroot(Interval(1024.0, 1024.0), 10)`

`[2, 2]`

`julia> nthroot(Interval(0, 81), -4)`

`[0.333333, ∞]`

`julia> nthroot(Interval(-81, 81), 4)`

`[0, 3]`

### E. Display Interval{Float32} with f0

`Pkg.add("IntervalArithmetic")`

`using IntervalArithmetic`

This is a simple display feature to display Float32 with f0 while using Intervals in IntervalArithemtic.jl to solve Issue #387

`Interval{Float32}(2, 7)`

Above work has been implemented in PR #391

### F. Add arithmetic operations of numbers with different types

Earlier, while doing arithmetic operations on Intervals, functions from Base were getting called instead of functions from `IntervalArithmetic.jl.`

Now, the correct functions are getting called,

`julia> @which (3f0..4f0) / 2.1`

`/(a::Interval{T}, x::S) where {T, S<:AbstractFloat} in IntervalArithmetic at /home/krish8484/.julia/dev/IntervalArithmetic/src/intervals/arithmetic.jl:152`

`julia> Interval{BigFloat}(2,4)/2`

`[1, 2]₂₅₆`

`julia> x = (3f0..4f0) / 2.1`

`[1.42857f0, 1.90477f0]`

`julia> @which (3f0..4f0) + 2.1`

`+(a::Interval{T}, b::S) where {T, S<:AbstractFloat} in IntervalArithmetic at /home/krish8484/.julia/dev/IntervalArithmetic/src/intervals/arithmetic.jl:69`

This solves issue #389

Above work has been implemented in PR #392

### G. libieeep1788_class.jl

#### @decorated now responds to `setprecision()`

`julia> typeof(@decorated(1, 2))`

`DecoratedInterval{Float64}`

`julia> setprecision(Interval, 256)`

`256`

`julia> typeof(@decorated(1, 2))`

`DecoratedInterval{BigFloat}`

`@decorated`

now throws an `ArgumentError`

just like `@interval`

for improper inputs

`julia> @decorated(2, -1)`

`ERROR: ArgumentError: `[2.0, -1.0]` is not a valid interval. Need `a ≤ b` to construct `interval(a, b)`.`

`Stacktrace:`

` [1] interval(::Float64, ::Float64) at C:\Users\ASUS\.julia\dev\IntervalArithmetic\src\intervals\intervals.jl:107`

` [2] top-level scope at REPL[2]:1`

`julia> @decorated("[ -1.0 , 1.0]_fooo") #this was one of ITF1788 Test`

`ERROR: LoadError: ArgumentError: Cannot process fooo as decoration`

`Stacktrace:`

` [1] parse(::Type{DecoratedInterval{Float64}}, ::String) at C:\Users\ASUS\.julia\dev\IntervalArithmetic\src\parsing.jl:48`

` [2] @decorated(::LineNumberNode, ::Module, ::Vararg{Any,N} where N) at C:\Users\ASUS\.julia\dev\IntervalArithmetic\src\decorations\intervals.jl:138`

`in expression starting at REPL[3]:1`

#### Better string handling for `@interval`

and `@decorated`

`julia> @decorated("[ Nai ]") == nai()`

`true`

`julia> @decorated("[-1.0, +infinity]_def") == DecoratedInterval(Interval(-1.0, Inf), def)`

`true`

`julia> @test_throws ArgumentError @interval("[ -inf , INF ]_com")`

`Test Passed`

` Thrown: ArgumentError`

#### Error Handling in intervals

Appropriate error is thrown when the exception of that kind occurs

`julia> @test_throws IntervalArithmetic.IntvlPartOfNaI interval(@decorated("[nai]"))`

`Test Passed`

` Thrown: IntervalArithmetic.IntvlPartOfNaI`

Above work is implemented in PR#398

### H. libieeep1788_reduction.jl

Some polishing was to Yash Gupta's Pull Request to add some new functions in the library

`julia> vector_sumAbs([1.0, -2.0, 3.0], RoundNearest)`

`6.0`

`julia> vector_sum([1.0, 2.0, 3.0], RoundNearest)`

`6.0`

`julia> vector_sumSquare([1.0, 2.0, 3.0], RoundNearest)`

`14.0`

`julia> vector_dot([1.0, 2.0, 3.0], [1.0, 2.0, 3.0], RoundNearest)`

`14.0`

`julia> isnan(vector_dot([1.0, 2.0, -Inf, 4.0], [1.0, 2.0, 0.0, 3.0], RoundNearest))`

`true`

Above work has been implemented in PR #399

### I. libieeep1788_bool.jl

Most of the tests from this file were already satisfied. The only thing added was for these functions to deal with `nai`

Now, all tests from this file pass

`julia> strictprecedes(nai(), DecoratedInterval(Interval(3.0, 4.0), trv))`

`false`

`julia> isdisjoint(nai(), DecoratedInterval(Interval(3.0, 4.0), def))`

`false`

Above work has been implemented in PR #400

### J. libieeep1788_tests_overlap.jl

Most of the work in this file was done by Yash Gupta in PR #266, I have only increased the code coverage and removed the superfluous new file.

This function(`overap`

) gives the relation between 2 intervals

`julia> overlap(∅, Interval(1.0, 2.0))`

`"firstEmpty"`

`julia> overlap(Interval(1.0, 2.0), Interval(2.0, Inf)) == "meets"`

`true`

`julia> overlap(Interval(2.0, 2.0), Interval(0.0, Inf))`

`"containedBy"`

`julia> overlap(Interval(1.0, 2.0), Interval(0.0, 2.0))`

`"finishes"`

`julia> overlap(Interval(3.0, 4.0), Interval(1.0, 2.0))`

`"after"`

`julia> overlap(Interval(1.5, 2.5), Interval(1.0, 2.0))`

`"overlappedBy"`

`julia> overlap(Interval(0.0, 3.0), Interval(2.0, 2.0))`

`"contains"`

### Concluding Remarks

I have learned a lot this summer, working under David Sanders and trying to debug `IntervalArithmetic.jl`

, I have implemented a lot more than I thought I could and I wish to stay with Julia in the coming years. I hope I get more opportunities in the future to collaborate with mentors for Julia Projects, and in the process be a more prominent part of this wonderful community.