Show HN: I made a calculator that works over disjoint sets of intervals

Posted by fouronnes3 9 hours ago

Counter171Comment30OpenOriginal

I've been studying interval arithmetic for the past few weeks and it's a really interesting field because while there is a ton of super interesting research published over the past decades, it has never really gotten the recognition that it deserves, IMO.

One reason for this is that standard interval arithmetic has really poor handling of division by intervals containing zero. If you compute 1 / [-1, 2] in regular interval arithmetic, you get either [-∞, +∞], or you have to say that the operation is undefined. Both solutions are virtually useless. The real answer of course is [-∞, -1] U [0.5, +∞]: i.e. a union of two disjoint intervals.

This is useful because you can confidently exclude a non empty set of the real numbers ([-1, 0.5]) from the set of possible values that you can get by dividing 1 by a number between -1 and 2.

But this definition of interval division yields a value that is not an interval. This is a problem if you want to define a closed arithmetic system, where you can build and evaluate arbitrary expression over interval values.

(This behavior extends to any non continuous function like tan() for example, which is implemented in my project - not without difficulties!)

Well the obvious solution is to define your arithmetic over disjoint unions of intervals. This is the subject of a 2017 paper called "Interval Unions" by by Schichl, H., Domes, F., Montanher, T. and Kofler, K..

This open-source project I made implements interval union arithmetic in TypeScript in the form of a simple interactive calculator, so you can try it out for yourself! The underlying TypeScript library is dependency free and implements interval union arithmetic over IEEE 754 double precision floats (JS native number type) with outward rounding. This guarantees accuracy of interval results in the presence of rounding issue inherent to floating point.

Comments

Comment by fouronnes3 9 hours ago

Author here. Outward rounding to combat precision issues is what interval arithmetic is most known for (try 0.1+0.2 with "full precision mode" enabled), but that's really a shame in my opinion. Outward rounding is cool, but the "inclusion property", as it's known in research papers, works at every scale! This is what enables things like:

     50 * (10 + [-1, 1])
    [450, 550]
which is lovely, I think. Adding the union layer to it enables even cooler things, like the true inverse of the square function. Did you know it's not sqrt? Try 'sqinv(64)'.

I made interval calculator actually mostly as a way to test my implementation of interval union arithmetic [0], which I needed for another project: a backwards updating spreadsheet [1][2].

[0] https://github.com/victorpoughon/not-so-float

[1] https://victorpoughon.github.io/bidicalc/

[2] https://news.ycombinator.com/item?id=46234734

Comment by thekoma 1 hour ago

Nice! I am interested in how the arithmetic you implemented differs from the IEEE 1788 Standard for Interval Arithmetic (and how the two linked papers relate to it). To address the challenges you mention, did you have to start from scratch or was it something that can build on top of the IEEE standard?

Comment by fouronnes3 1 hour ago

Interesting! I'm not familiar with IEEE 1788. The TypeScript library (not-so-float) that I wrote which powers the calculator uses the JS Number type which is double precision IEEE 754. Outward rounding is not supported by JS so I used a bit level manipulation hack by casting to TypedArray [0] to implement the equivalent of C's nextafter() function. Otherwise I mostly followed Hickey & van Emden paper which is really delightful [1]. The real hard work is actually generating all the test cases. Good luck getting 100% test coverage on interval division!

[0] https://github.com/victorpoughon/not-so-float/blob/main/src/...

[1] https://fab.cba.mit.edu/classes/S62.12/docs/Hickey_interval....

Comment by iamwil 5 hours ago

This is great. You might be interested in Matt Keeter's work on Implicit surfaces, and using interval math for its optimization:

https://youtu.be/UxGxsGnbyJ4?si=Oo6Lmc4ACaSr5Dk6&t=1006

Comment by memalign 5 hours ago

You might be interested in this graphing calculator I made using interval arithmetic:

https://memalign.github.io/m/formulagraph/index.html

Some detail on how this works, including links to the relevant interval math code:

https://memalign.github.io/p/formulagraph.html

Comment by dfgtu 16 minutes ago

Very nice work. I was wondering if it might be useful to combine this with a library for arbitrary precision arithmetic. How difficult do you think that might be?

Comment by fouronnes3 7 minutes ago

Thanks! Arbitrary precision arithmetic is definitely something I'd like to learn more about, yeah. Haven't had time to study it so much yet unfortunately.

Comment by akst 1 hour ago

Very cool! I don't entirely understand some of the operations, but for what I do understand its pretty neat.

I wish in classes we were introduced to a notion of arithmetic on intervals as it comes up. Like in basic statistics with confidence intervals there's ±, as well as in the quadratic equation. It found some what dissatisfying we couldn't chain the resulting a series of operations and instead repeat the operations for the 2 seperate values of the ±. I get a teacher would rather not get hung up on this because they want to bring it back to the application generally, like solving a more complicated equation or hypothesis testing in basic stats. I just wish they hinted at the idea we can do arithmetic on these kinds of things more generally.

I realise what you've got here is well beyond this, but seeing this was some level of validation that treating the interval as a piece of data with its own behaviour of certain operations does make some sense.

Comment by _Microft 4 hours ago

Very nice, thanks for sharing! Maybe show which upper or lower values are included in the intervals? A notation I am familiar with uses outward facing brackets if the value is not included in the interval. That always applies to infinity.

Applied to the cases here:

]-∞, -1] U [0.5, +∞[

The excluded interval in between becomes ]-1, 0.5[ then.

That’s how min (and analogously max) works, right? min(A, B) = [lo(A,B), lo (hi(A), hi(B))].

Edit: idea: copy a formula from the results section to the input field if the user clicks/taps on it.

Comment by adito 3 hours ago

From reading the linked paper[0], It explains closed interval only. "An interval union is a set of closed and disjoint intervals where the bounds of the extreme interval can be ±∞".

[0]: https://www.ime.usp.br/~montanhe/unions.pdf

Comment by fouronnes3 3 hours ago

It's possible to support that but it makes the code very very much more complicated. I've decided early on to not support it. Would be a cool addition though!

Comment by globular-toast 4 hours ago

I was also a bit confused by this. I thought the standard notation was round brackets, but maybe doesn't work well in ASCII?

Comment by qbit42 3 hours ago

Round brackets are standard in the US but that notation is used in France and some other places.

Comment by meindnoch 2 hours ago

  (0, 1)
Is this an twice-open interval or a 2D vector?

See, this is why Bourbaki introduced the ]0,1[ notation.

Comment by ttoinou 1 hour ago

Why not use disks / exterior disks in the complex numbers plane instead of intervals ? It might make the mental model easier to reason about

Comment by anematode 3 hours ago

Excellent!! I love interval arithmetic and also wrote a TS implementation for a graphing calculator project. Agree that it's very underrated, and I wish that directed rounding was exposed in more languages.

Comment by fouronnes3 3 hours ago

Yeah it's super interesting. Like you said, I learned that the IEEE 754 spec actually requires that complete implementations of floating point numbers expose a way to programmatically choose the rounding mode. As far as I know only C allows you to do that, and even then it depends on hardware support. For JS I had to use ugly typedarray casts. Which kinda only accidentally work due to endianess. But technically there should be an API for it!

There's other unused stuff in IEEE 754 like that: the inexact bit or signaling NaNs!

Comment by JSR_FDED 3 hours ago

I just read up on interval arithmetic. I understand its desirable properties. Where in practice have you applied it? What’s a real world application for interval arithmetic?

Comment by ngruhn 3 hours ago

It can be used in static analysis or type checking. E.g.

    if (x >= 0) {
      x += 10
      if (x =< 9) {
        // unreachable 
      }
    }
By maintaining an interval of possible values of x, you can detect the unreachable branch, because the interval becomes empty:

    initial: [-oo, oo]
    x >= 0 : [0, oo]
    x += 10: [10, oo]
    x =< 9 : [10, 9] (empty)

Comment by Oberdiah 58 minutes ago

I’m working on a static analyser at the moment that does this, and the inferences that can be made just from the information of intervals is quite impressive. One thing you run into pretty quickly though in a lot of languages is integer overflow ruining your day - in your example above the commented section is reachable for signed ints that support overflow and that adds a whole other layer of complexity to things.

Comment by thekoma 1 hour ago

We recently implemented this idea in an LLVM optimisation pass based on value-range information from sensor datasheets [1].

[1]: https://dl.acm.org/doi/pdf/10.1145/3640537.3641576

Comment by nickcw 2 hours ago

In physics, whenever you make a measurement it has a precision. Usually you represent this as a normal distribution, but for calculations it can be easier to represent this as an interval.

The police measure the distance my car travelled [ 99.9, 100.1 ] m and the time it took [ 3.3, 3.4 ] s - how fast was my car going? [29.38, 30.33] m/s according to the interval calculator.

Physics students learn exactly this method before they move on to more sophisticated analysis with error distributions.

Comment by ttoinou 1 hour ago

And one might want to approximate error distribution calculus with a method that will look like the one here

Comment by nicolodev 3 hours ago

It’s astonishing how nobody hasn’t mentioned abstract interpretation yet. Under classical static analysis, if you can “prove” that a variable does not have values in some unsound zones, you can e.g. “prove” soundness or apply further optimizations.

The interval abstract domain works under interval analysis with an algebra that’s the same of this calculator. It’s funny to implement something like that on source/binary level :)

Comment by teiferer 3 hours ago

The last point in your intro description can't be stressed enough: this allows for safe handling of rounding errors in floating point operations.

Though you are inherently losing precision: there are values in the output interval which don't have a corresponding input that causes this output.

Comment by dnnddidiej 2 hours ago

Interals can be used to model errors and uncertainty and this lets you see how they conpound in calculations like speed = distance over time.

Comment by petters 3 hours ago

You could add a feature where it will compute the global optimum of any function of a small number of variables. Branch and bound with interval arithmetic works well for a small number of variables.

Disjoint unions of intervals seems like a nice thing to have

Comment by boobsbr 3 hours ago

Neat.

Comment by wallhz 1 hour ago

[dead]

Comment by LXforever 2 hours ago

Very cool. This feels like one of those ideas that makes interval arithmetic go from “interesting but frustrating” to actually useful. I’d be curious how you handle the growth in the number of disjoint intervals over repeated operations, since that seems like the practical bottleneck.

Comment by fouronnes3 1 hour ago

I don't handle it, ahah. You are right that if you take any classical numerical computing algorithm and replace the floating point reals by interval unions, most of the time the number of intervals in the unions in each of your variables will grow very fast. This is one of the problems of unions and as far as I'm aware it's a topic of active academic research.