@toryt/allen
TypeScript icon, indicating that this package has built-in type declarations

0.8.2 • Public • Published

Allen

Validate and reason about relations between intervals, and between points and intervals, in JavaScript and TypeScript.

When working with intervals, we often want to express constraints (invariants) that limit acceptable combinations. Expressing this correctly proves difficult in practice. Falling back to working with isolated start and end points, and reasoning about their relations, in practice proves to be even much more difficult and error-prone. This problem was tackled in 1983 by James Allen:

Good synopses of this theory are

This library does not help with inference.

ppwcode dotnet-util-allen offers a C# version of the functionality of this library.

How to use

Example

JavaScript

const { AllenRelation, PointIntervalRelation } = require('@toryt/allen')

function allenRelationExample () {
  const iiCondition1 = AllenRelation.fromString('psSd')
  const iiCondition2 = AllenRelation.fromString('sde')
  const iiCondition = iiCondition1.compose(iiCondition2)

  const i1 = { start: '2022-11-04', end: '2023-04-12' }
  const i2 = { start: '2021-08-22' }

  const iiActual = AllenRelation.relation(i1, i2)
  if (!iiActual.implies(iiCondition)) {
    throw new Error(`i1 and i2 do no uphold ${iiCondition.toString()}`)
  }

  return iiActual
}

function pointIntervalExample () {
  const piCondition1 = PointIntervalRelation.or(PointIntervalRelation.BEFORE, PointIntervalRelation.TERMINATES)
  const iiCondition2 = AllenRelation.fromString('sde')
  const piCondition = piCondition1.compose(iiCondition2)

  const p = '2021-08-15'
  const i = { start: '2021-08-22' }

  const piActual = PointIntervalRelation.relation(p, i)
  if (!piActual.implies(piCondition)) {
    throw new Error(`p and i2 do not uphold ${piCondition.toString()}`)
  }

  return piActual
}

TypeScript

import { AllenRelation, Interval, PointIntervalRelation } from '@toryt/allen'

function allenRelationExample (): AllenRelation {
  const iiCondition1: AllenRelation = AllenRelation.fromString<AllenRelation>('psSd')
  const iiCondition2: AllenRelation = AllenRelation.fromString<AllenRelation>('sde')
  const iiCondition: AllenRelation = iiCondition1.compose(iiCondition2)

  const i1: Interval<string> = { start: '2022-11-04', end: '2023-04-12' }
  const i2: Interval<string> = { start: '2021-08-22' }

  const iiActual: AllenRelation = AllenRelation.relation(i1, i2)
  if (!iiActual.implies(iiCondition)) {
    throw new Error(`i1 and i2 do no uphold ${iiCondition.toString()}`)
  }

  return iiActual
}

function pointIntervalExample (): PointIntervalRelation {
  const piCondition1: PointIntervalRelation = PointIntervalRelation.or(
    PointIntervalRelation.BEFORE,
    PointIntervalRelation.TERMINATES
  )
  const iiCondition2: AllenRelation = AllenRelation.fromString<AllenRelation>('sde')
  const piCondition: PointIntervalRelation = piCondition1.compose(iiCondition2)

  const p: string = '2021-08-15'
  const i: Interval<string> = { start: '2021-08-22' }

  const piActual: PointIntervalRelation = PointIntervalRelation.relation(p, i)
  if (!piActual.implies(piCondition)) {
    throw new Error(`p and i2 do not uphold ${piCondition.toString()}`)
  }

  return piActual
}

Algebra

We find that there are 5 basic relations possible between a definite point and a definite interval:

  • t is BEFORE I (b)

    before

  • t COMMENCES I (c)

    begins

  • t IN I (i)

    in

  • t TERMINATESI(t`)

    ends

  • t is AFTER I (a)

    after

and that there are 13 basic relations possible between definite intervals:

Basic relation (.) Illustration
i1 precedes i2 (p) precedes
i1 meets i2 (m) meets
i1 overlaps i2 (o) overlaps
i1 is finished by i2 (F) is finished by
i1 contains i2 (D) contains
i1 starts i2 (s) starts
i1 equals i2 (e) equals
i1 is started by i2 (S) is started by
i1 during i2 (d) during
i1 finishes i2 (f) finishes
i1 is overlapped by i2 (O) is overlapped by
i1 is met by i2 (M) is met by
i1 is preceded by i2 (P) is preceded by

These 5, respectively 13, basic relations are an orthogonal basis for all possible general relation-conditions between a point and an interval (PointIntervalRelation), respectively between two intervals (AllenRelation).

(bt) says that a point can be before an interval, or terminate it. (sde) says that an interval i1 may start an interval i2, may be during i2, or be equal to it. Each general relation expresses a certain amount of uncertainty, where a basic relation expresses certainty, and the FULL relation ( (bcita), respectively (pmoFDseSdfOMP)) expresses complete uncertainty.

These 32 (25), respectively 8192 (213), general relations form an algebra, with the operations

  • complement
  • converse (only for AllenRelation)
  • min
  • or
  • and
  • compose

A relation to be used as a condition to the problem at hand is build using these operations.

A relation implies another relation, or not. E.g., if we have determined that a relation between i1 and i2 is (oO), and we need it to be (pmoOMP), this is ok because (oO) implies (pmoOMP). If the relation is (oeO) however, it is not ok, because (pmoOMP) does not allow the intervals to be equal.

Things get even more interesting when we need to reason about indefinite intervals, where the start or end is unknown 🤷.

There are some pitfalls.

Details

All functions and methods are protected with explicit asserts, that throw when a precondition is violated. Although written in TypeScript, types are verified dynamically too, so that type safety is ensured dynamically when the library is used with plain JavaScript too.

Where to find

Repo, CI, issues, pull requests This project is maintained in Bitbucket (repo, CI, issues, pull requests, …).

TODO Branches are copied automatically to [GitHub] by CI. This is done as backup, and because open source projects are more easily found there. Issues and pull requests there will not be reviewed.

npm

@toryt/allen

Style

JavaScript Style Guide

This code uses the application to TypeScript of the Standard coding style. Tests require complete code coverage.

License

Released under the Apache License, Version 2.0.

Copyright © 2022 by Jan Dockx

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Notes

This code was based on a Java implementation last updated in December 2008.

Readme

Keywords

Package Sidebar

Install

npm i @toryt/allen

Weekly Downloads

16

Version

0.8.2

License

Apache-2.0

Unpacked Size

2.92 MB

Total Files

97

Last publish

Collaborators

  • jandockx