A note on interval endpoints

In general, it is possible for the disjoint intervals comprising a step function to be closed, half-closed or open. However the internals of staircase package do not explicitly model which interval endpoints are open and which are closed - and do not explicitly model the value of the step function at the interval endpoints. Does this mean we cannot use staircase to evaluate a step function f at interval endpoints? Not quite. The internals of staircase permit \(\lim_{x \to z} f(x)\) to be calculated, so under certain assumptions the value at interval endpoints can be inferred:

  • if f is comprised of only left-closed intervals then \(f(z) = \lim_{x \to z^{+}} f(x)\) for all z (including interval endpoints)

  • if f is comprised of only right-closed intervals then \(f(z) = \lim_{x \to z^{-}} f(x)\) for all z (including interval endpoints)

To simplify explanation, we refer to step functions comprising of only left-closed intervals, as left-closed step functions, and extend the same concept to right-closed step functions. In staircase v1 it was suggested that users make an assumption to work with either left-closed step functions, or right-closed step functions. In staircase v2 this assumption is made explicit at the time of initialising staircase.Stairs instances via the closed parameter. Consider the following example:

In [1]: import staircase as sc

In [2]: import matplotlib.pyplot as plt

In [3]: sf1 = sc.Stairs(closed="left").layer(0, 1)

In [4]: sf2 = sc.Stairs(closed="right").layer(0, 1)

In [5]: fig, axes = plt.subplots(ncols=2, figsize=(7,3), sharex=True, sharey=True)

In [6]: sf1.plot(ax=axes[0], arrows=True);

In [7]: axes[0].set_title("sf1 (left-closed)");

In [8]: sf2.plot(ax=axes[1], arrows=True);

In [9]: axes[1].set_title("sf2 (right-closed)");

It should be clear that whether a step function in staircase is left-closed, or right-closed, cannot be deduced from the plotting function. Let’s see how it makes a difference when sampling:

In [10]: sf1([0, 0.5, 1])
Out[10]: array([1, 1, 0])

In [11]: sf2([0, 0.5, 1])
Out[11]: array([0, 1, 1])

Note that the closed parameter has a default value of “left”. This is motivated by the fact that time based intervals, such as hours, days and years, are left-closed. Once a staircase.Stairs object has been created it cannot change from left-closed to right-closed, and vice versa.