packages feed

interval-algebra-2.2.0: src/IntervalAlgebra/RelationProperties.hs

{-|
Module      : Interval Algebra Axioms
Description : Properties of Intervals
Copyright   : (c) NoviSci, Inc 2020-2022
                  TargetRWE, 2023
License     : BSD3
Maintainer  : bsaul@novisci.com 2020-2022, bbrown@targetrwe.com 2023

This module exports property-based tests for the axioms in section 1 of [Allen
and Hayes (1987)](https://doi.org/10.1111/j.1467-8640.1989.tb00329.x).  The
notation below is that of the original paper.

This module is useful if creating a new instance of interval types that you
want to test.

-}
{- HLINT ignore -}
{-# LANGUAGE ExplicitForAll        #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeApplications      #-}

module IntervalAlgebra.RelationProperties where

import           Data.Maybe                        (fromJust, isJust, isNothing)
import           Data.Set                          (Set, disjointUnion,
                                                    fromList, member)
import           Data.Time                         as DT (Day, NominalDiffTime,
                                                          UTCTime)
import           IntervalAlgebra.Arbitrary
import           IntervalAlgebra.Core
import           IntervalAlgebra.IntervalUtilities ((.+.))
import           Test.QuickCheck                   (Arbitrary (arbitrary),
                                                    Property, (===), (==>))

allIArelations :: (SizedIv (Interval a), Ord a) => [ComparativePredicateOf1 (Interval a)]
allIArelations =
  [ equals
  , meets
  , metBy
  , before
  , after
  , starts
  , startedBy
  , finishes
  , finishedBy
  , overlaps
  , overlappedBy
  , during
  , contains
  ]

-- A collection of properties for the interval algebra. Some of these come from
-- figure 2 in  [Allen and Hayes
-- (1987)](https://doi.org/10.1111/j.1467-8640.1989.tb00329.x).

-- | For any two pair of intervals exactly one 'IntervalRelation' should hold
prop_exclusiveRelations::  (SizedIv (Interval a), Ord a) => Interval a -> Interval a -> Property
prop_exclusiveRelations x y =
  (  1 == length (filter id $ map (\r -> r x y) allIArelations)) === True

-- | Given a set of interval relations and predicate function, test that the
-- predicate between two interval is equivalent to the relation of two intervals
-- being in the set of relations.
prop_predicate_unions :: (SizedIv (Interval a), Ord a) =>
      Set IntervalRelation
    -> ComparativePredicateOf2 (Interval a) (Interval a)
    -> Interval a
    -> Interval a
    -> Property
prop_predicate_unions s pred i0 i1 =
  pred i0 i1 === (relate i0 i1 `elem` s)

prop_IAbefore :: forall a. (SizedIv (Interval a), Ord a, Ord (Moment (Interval a))) => Interval a -> Interval a -> Property
prop_IAbefore i j =
  before i j ==> (i `meets` k) && (k `meets` j)
    where k = safeInterval (end i, begin j)

prop_IAstarts:: (SizedIv (Interval a), Ord a, Ord (Moment (Interval a))) => Interval a -> Interval a -> Property
prop_IAstarts i j
  | starts i j = (j == fromJust (i .+. k)) === True
  | otherwise     = starts i j === False
    where k = safeInterval (end i, end j)

prop_IAfinishes:: (SizedIv (Interval a), Ord a, Ord (Moment (Interval a))) => Interval a -> Interval a -> Property
prop_IAfinishes i j
  | finishes i j = (j == fromJust ( k .+. i)) === True
  | otherwise       = finishes i j === False
    where k = safeInterval (begin j, begin i)

prop_IAoverlaps:: forall a. (SizedIv (Interval a), Ord a, Ord (Moment (Interval a))) => Interval a -> Interval a -> Property
prop_IAoverlaps i j
  | overlaps i j = ((i == fromJust ( k .+. l )) &&
                      (j == fromJust ( l .+. m ))) === True
  | otherwise       = overlaps i j === False
    where k = safeInterval (begin i, begin j)
          l = safeInterval (begin j, end i)
          m = safeInterval (end i, end j)

prop_IAduring:: forall a. (SizedIv (Interval a), Ord a, Ord (Moment (Interval a))) => Interval a -> Interval a-> Property
prop_IAduring i j
  | during i j = (j == fromJust ( fromJust (k .+. i) .+. l)) === True
  | otherwise     = during i j === False
    where k = safeInterval (begin j, begin i)
          l = safeInterval (end i, end j)

prop_disjoint_predicate :: (SizedIv (Interval a), Ord a) =>
      Interval a
    -> Interval a
    -> Property
prop_disjoint_predicate = prop_predicate_unions disjointRelations disjoint

prop_notdisjoint_predicate :: (SizedIv (Interval a), Ord a) =>
      Interval a
    -> Interval a
    -> Property
prop_notdisjoint_predicate =
  prop_predicate_unions (complement disjointRelations) notDisjoint

prop_concur_predicate :: (SizedIv (Interval a), Ord a) =>
      Interval a
    -> Interval a
    -> Property
prop_concur_predicate =
  prop_predicate_unions (complement disjointRelations) concur

prop_within_predicate :: (SizedIv (Interval a), Ord a) =>
      Interval a
    -> Interval a
    -> Property
prop_within_predicate = prop_predicate_unions withinRelations within

prop_enclosedBy_predicate :: (SizedIv (Interval a), Ord a) =>
      Interval a
    -> Interval a
    -> Property
prop_enclosedBy_predicate = prop_predicate_unions withinRelations enclosedBy

prop_encloses_predicate :: (SizedIv (Interval a), Ord a) =>
      Interval a
    -> Interval a
    -> Property
prop_encloses_predicate = prop_predicate_unions (converse withinRelations) encloses