# aiken/interval

In a eUTxO-based blockchain like Cardano, the management of time can be finicky.

Indeed, in order to maintain a complete determinism in the execution of scripts, it is impossible to introduce a notion of “current time” since the execution would then depend on factor that are external to the transaction itself: the ineluctable stream of time flowing in our universe.

Hence, to work around that, we typically define time intervals, which gives window – a.k.a intervals – within which the transaction can be executed. From within a script, it isn’t possible to know when exactly the script is executed, but we can reason about the interval bounds to validate pieces of logic.

# Types

## Interval<a>

A type to represent intervals of values. Interval are inhabited by a type `a` which is useful for non-infinite intervals that have a finite lower-bound and/or upper-bound.

This allows to represent all kind of mathematical intervals:

``````// [1; 10]
let i0: Interval<PosixTime> = Interval
{ lower_bound:
IntervalBound { bound_type: Finite(1), is_inclusive: True }
, upper_bound:
IntervalBound { bound_type: Finite(10), is_inclusive: True }
}
``````
``````// (20; infinity)
let i1: Interval<PosixTime> = Interval
{ lower_bound:
IntervalBound { bound_type: Finite(20), is_inclusive: False }
, upper_bound:
IntervalBound { bound_type: PositiveInfinity, is_inclusive: False }
}
``````

### Constructors

• ``Interval { lower_bound: IntervalBound<a>, upper_bound: IntervalBound<a> }``

## IntervalBound<a>

An interval bound, either inclusive or exclusive.

### Constructors

• ``IntervalBound { bound_type: IntervalBoundType<a>, is_inclusive: Bool }``

## IntervalBoundType<a>

A type of interval bound. Where finite, a value of type `a` must be provided. `a` will typically be an `Int`, representing a number of seconds or milliseconds.

### Constructors

• ``NegativeInfinity``
• ``Finite(a)``
• ``PositiveInfinity``

# Functions

## `after(lower_bound: a) -> Interval<a>`

Create an interval that includes all values greater than the given bound. i.e [lower_bound, +INF)

``````interval.after(10) == Interval {
lower_bound: IntervalBound { bound_type: Finite(10), is_inclusive: True },
upper_bound: IntervalBound { bound_type: PositiveInfinity, is_inclusive: True },
}
``````

## `before(upper_bound: a) -> Interval<a>`

Create an interval that includes all values before (and including) the given bound. i.e (-INF, upper_bound]

``````interval.before(100) == Interval {
lower_bound: IntervalBound { bound_type: NegativeInfinity, is_inclusive: True },
upper_bound: IntervalBound { bound_type: Finite(100), is_inclusive: True },
}
``````

## `between(lower_bound: a, upper_bound: a) -> Interval<a>`

Create an interval that includes all values between two bounds, including the bounds. i.e. [lower_bound, upper_bound]

``````interval.between(10, 100) == Interval {
lower_bound: IntervalBound { bound_type: Finite(10), is_inclusive: True },
upper_bound: IntervalBound { bound_type: Finite(100), is_inclusive: True },
}
``````

## `contains(self: Interval<Int>, elem: Int) -> Bool`

Checks whether an element is contained within the interval.

``````let iv =
Interval {
lower_bound: IntervalBound {
bound_type: Finite(14),
is_inclusive: True
},
upper_bound: IntervalBound {
bound_type: Finite(42),
is_inclusive: False
},
}

interval.contains(iv, 25) == True
interval.contains(iv, 0) == False
interval.contains(iv, 14) == True
interval.contains(iv, 42) == False
``````

## `empty() -> Interval<a>`

Create an empty interval that contains no value.

``````interval.contains(empty(), 0) == False
interval.contains(empty(), 1000) == False
``````

## `entirely_after(lower_bound: a) -> Interval<a>`

Create an interval that includes all values after (and not including) the given bound. i.e (lower_bound, +INF)

``````interval.entirely_after(10) == Interval {
lower_bound: IntervalBound { bound_type: Finite(10), is_inclusive: False },
upper_bound: IntervalBound { bound_type: PositiveInfinity, is_inclusive: True },
}
``````

## `entirely_before(upper_bound: a) -> Interval<a>`

Create an interval that includes all values before (and not including) the given bound. i.e (-INF, upper_bound)

``````interval.entirely_before(10) == Interval {
lower_bound: IntervalBound { bound_type: NegativeInfinity, is_inclusive: True },
upper_bound: IntervalBound { bound_type: Finite(10), is_inclusive: False },
}
``````

## `entirely_between(lower_bound: a, upper_bound: a) -> Interval<a>`

Create an interval that includes all values between two bounds, excluding the bounds. i.e. (lower_bound, upper_bound)

``````interval.entirely_between(10, 100) == Interval {
lower_bound: IntervalBound { bound_type: Finite(10), is_inclusive: False },
upper_bound: IntervalBound { bound_type: Finite(100), is_inclusive: False },
}
``````

## `everything() -> Interval<a>`

Create an interval that contains every possible values. i.e. (-INF, +INF)

``````interval.contains(everything(), 0) == True
interval.contains(everything(), 1000) == True
``````

## `hull(iv1: Interval<Int>, iv2: Interval<Int>) -> Interval<Int>`

Computes the smallest interval containing the two given intervals, if any

``````let iv1 = between(0, 10)
let iv2 = between(2, 14)
hull(iv1, iv2) == between(0, 14)

let iv1 = between(5, 10)
let iv2 = before(0)
hull(iv1, iv2) == before(10)

let iv1 = entirely_after(0)
let iv2 = between(10, 42)
hull(iv1, iv2) = entirely_after(0)
``````

## `intersection(iv1: Interval<Int>, iv2: Interval<Int>) -> Interval<Int>`

Computes the largest interval contains in the two given intervals, if any.

``````let iv1 = interval.between(0, 10)
let iv2 = interval.between(2, 14)
interval.intersection(iv1, iv2) == interval.between(2, 10)

let iv1 = interval.entirely_before(10)
let iv2 = interval.entirely_after(0)
interval.intersection(iv1, iv2) == interval.entirely_between(0, 10)

let iv1 = interval.between(0, 1)
let iv2 = interval.between(2, 3)
interval.intersection(iv1, iv2) |> interval.is_empty
``````

## `is_empty(self: Interval<Int>) -> Bool`

Tells whether an interval is empty; i.e. that is contains no value.

``````let iv1 = interval.empty()

let iv2 = Interval {
lower_bound: IntervalBound { bound_type: Finite(0), is_inclusive: False },
upper_bound: IntervalBound { bound_type: Finite(0), is_inclusive: False },
}

let iv3 = Interval {
lower_bound: IntervalBound { bound_type: Finite(0), is_inclusive: False },
upper_bound: IntervalBound { bound_type: Finite(100), is_inclusive: False },
}

interval.is_empty(iv1) == True
interval.is_empty(iv2) == True
interval.is_empty(iv3) == False

// Note: Two empty intervals are not necessarily equal.
iv1 != iv2
``````

## `is_entirely_after(self: Interval<Int>, point: Int) -> Bool`

Check whether the interval is entirely after the point “a”

``````interval.is_entirely_after(interval.after(10), 5) == True
interval.is_entirely_after(interval.after(10), 10) == False
interval.is_entirely_after(interval.after(10), 15) == False
interval.is_entirely_after(interval.between(10, 20), 30) == False
interval.is_entirely_after(interval.between(10, 20), 5) == True``````

## `is_entirely_before(self: Interval<Int>, point: Int) -> Bool`

Check whether the interval is entirely before the point “a”

``````interval.is_entirely_before(interval.before(10), 15) == True
interval.is_entirely_before(interval.before(10), 10) == False
interval.is_entirely_before(interval.before(10), 5) == False
interval.is_entirely_before(interval.between(10, 20), 30) == True
interval.is_entirely_before(interval.between(10, 20), 5) == False``````

## `max(left: IntervalBound<Int>, right: IntervalBound<Int>) -> IntervalBound<Int>`

Return the highest bound of the two.

``````let ib1 = IntervalBound { bound_type: Finite(0), is_inclusive: False }
let ib2 = IntervalBound { bound_type: Finite(1), is_inclusive: False }

interval.max(ib1, ib2) == ib2
``````

## `min(left: IntervalBound<Int>, right: IntervalBound<Int>) -> IntervalBound<Int>`

Return the smallest bound of the two.

``````let ib1 = IntervalBound { bound_type: Finite(0), is_inclusive: False }
let ib2 = IntervalBound { bound_type: Finite(1), is_inclusive: False }

interval.min(ib1, ib2) == ib1
``````