DancingGrumpyCat / Intervals

Python module supporting math intervals as an abstraction and superset of the range function.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Intervals

Python module supporting math intervals. Functions as an abstraction and superset of the range function.

Many methods and examples herein are taken from Interval Arithmetic—Wikipedia .

Basic usage example

In [1]: # INITIALIZATION

In [2]: interval_1 = Interval.from_string("[0, 5)")  # [0.0, 5.0)

In [3]: interval_2 = Interval(3, 6)  # [3, 6)

In [4]: # METHODS & PROPERTIES

In [5]: print(interval_1)
Out[5]: [0.0, 5.0)

In [6]: list(interval_1.step(2, start=0))
Out[6]: [0, 2, 4]

In [7]: list(interval_1.step(2, start=-1))
Out[7]: [1, 3]

In [8]: list(interval_1.step(-1, start=5))  # does not include 5 because upper_bound is open
Out[8]: [4, 3, 2, 1, 0]

In [9]: interval_1.interval_type
Out[9]: <IntervalType.HALF_OPEN: 'half-open'>

In [10]: interval_1.width
Out[10]: 5.0

In [11]: 0 in interval_1
Out[11]: True

In [12]: 5 in interval_1
Out[12]: False

In [13]: print(interval_1 + 2)
[2.0, 7.0)

In [14]: print(-interval_1)  # note that the closed and opened bounds swap order too
(-5.0, 0.0]

In [15]: print(5 / interval_1)
[1.0, inf)

In [16]: print(interval_1 & interval_2)
[3, 5.0)

>>> print(interval_1 | interval_2)
[0.0, 6)
>>> print((interval_1 + interval_2) / 2)
[1.5, 5.5)

Plus-Minus form

In [1]: interval_3 = Interval.from_string("2 +- 1.2")  # 2 plus or minus 1.2

In [2]: print(interval_3)
[0.8, 3.2)

In [3]: print(interval_3.width)
2.4000000000000004

The following (all spaces are removed, so others are also possible) are also equivalent:

Interval.from_string("2 pm 1.2")
Interval.from_string("2 +- 1.2")
Interval.from_string("2 +/- 1.2")
Interval.from_string("2 ± 1.2")
Interval.from_string("2 pm 1.2")
Interval.from_string("2 p/m 1.2")
Interval(0.8, 3.2)

How it can replace range

Instead of the following examples:

# 1.
for x in range(10):
  ...

# 2.
[x**2 for x in range(10, 15, 2)]

you can now write

# 1.
for x in Interval(10):
  ...

# 2.
[x**2 for x in Interval(10, 15).step(2)]

and you can do a lot more, like floating point values:

In [1]: from math import tau
In [2]: theta = tau / 12
In [3]: print(*(
   ...: Interval(0, tau)
   ...: .closed()
   ...: .step(theta)
   ...: ), sep=",\n")
0,
0.5235987755982988,
1.0471975511965976,
1.5707963267948966,
2.0943951023931953,
2.617993877991494,
3.141592653589793,
3.665191429188092,
4.1887902047863905,
4.71238898038469,
5.235987755982988,
5.759586531581287,
6.283185307179586

Arithmetic operations between two intervals

In [1]: weight = Interval.from_string("80 +- 0.5")  # accurate to the nearest kg
In [2]: height = Interval.from_string("1.79 +- 0.005")  # accurate to the nearest cm
In [3]: bmi = weight / height ** 2
In [4]: print(round(bmi, 3))
[24.673, 25.266)

Infinity

You can create infinite (unbounded) intervals. I recommend combining this with the itertools modules islice and takewhile, since the outputs tend to be infinite generators.

Any side that is unbounded like this must be closed; doing integers = Interval(-inf, +inf, lower_closure="open") does the same thing as integers = Interval(-inf, +inf, lower_closure="closed").

Using itertools

In [1]: from itertools import islice, takewhile

In [2]: from random import random

In [3]: interval_4 = POSITIVE_REALS + 1

In [4]: n_1mod4 = interval_4.step(4)

In [5]: list(islice(n_1mod4, 10))
Out[5]: [1, 5, 9, 13, 17, 21, 25, 29, 33, 37]

In [6]: list(takewhile(lambda _: random() > 1/4, n_1mod4))
Out[6]: [1, 5, 9, 13]


In [7]: list(takewhile(lambda _: random() > 1/4, n_1mod4))
Out[7]: []

In [8]: list(takewhile(lambda _: random() > 1/4, n_1mod4))
Out[8]: [21, 25]

Utils

In [1]: interval_5 = Interval(0, 5)
In [2]: interval_6 = Interval(3, 12)

rand_uniform

(Uses random.random—not cryptographically secure.) Generates values random floats within the interval's bounds.

In [3]: rand_uniform(interval_5)
Out[3]: [4.64997216360891]

In [4]: rand_uniform(interval_5, values=5)
Out[4]:
[2.545513603508707,
 0.5394888009944876,
 3.872705211980179,
 0.8273514007287991,
 4.209282455847249]

lerp, invlerp, and remap

In [5]: lerp(interval_5, 0.3)
Out[5]: 1.5

In [6]: invlerp(interval_5, 1.5)
Out[6]: 0.3

In [7]: remap(interval_5, interval_6, 2.5)
Out[7]: 7.5

About

Python module supporting math intervals as an abstraction and superset of the range function.

License:MIT License


Languages

Language:Python 100.0%