{-| Module : Interval Algebra Axioms Description : Properties of Intervals Copyright : (c) NoviSci, Inc 2020 License : BSD3 Maintainer : bsaul@novisci.com This module exports a single typeclass @IntervalAxioms@ which contains 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 FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} module IntervalAlgebra.RelationProperties ( IntervalRelationProperties(..) ) 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 Test.QuickCheck (Arbitrary (arbitrary), Property, (===), (==>)) allIArelations :: (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). class ( IntervalSizeable a b ) => IntervalRelationProperties a b where -- | For any two pair of intervals exactly one 'IntervalRelation' should hold prop_exclusiveRelations:: 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 :: 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 :: Interval a -> Interval a -> Property prop_IAbefore i j = before i j ==> (i `meets` k) && (k `meets` j) where k = beginerval (diff (begin j) (end i)) (end i) prop_IAstarts:: Interval a -> Interval a -> Property prop_IAstarts i j | starts i j = (j == fromJust (i .+. k)) === True | otherwise = starts i j === False where k = beginerval (diff (end j) (end i)) (end i) prop_IAfinishes:: Interval a -> Interval a -> Property prop_IAfinishes i j | finishes i j = (j == fromJust ( k .+. i)) === True | otherwise = finishes i j === False where k = beginerval (diff (begin i) (begin j)) (begin j) prop_IAoverlaps:: 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 = beginerval (diff (begin j) (begin i)) (begin i) l = beginerval (diff (end i) (begin j)) (begin j) m = beginerval (diff (end j) (end i)) (end i) prop_IAduring:: 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 = beginerval (diff (begin i) (begin j)) (begin j) l = beginerval (diff (end j) (end i)) (end i) prop_disjoint_predicate :: (Ord a) => Interval a -> Interval a -> Property prop_disjoint_predicate = prop_predicate_unions disjointRelations disjoint prop_notdisjoint_predicate :: (Ord a) => Interval a -> Interval a -> Property prop_notdisjoint_predicate = prop_predicate_unions (complement disjointRelations) notDisjoint prop_concur_predicate :: (Ord a) => Interval a -> Interval a -> Property prop_concur_predicate = prop_predicate_unions (complement disjointRelations) concur prop_within_predicate :: (Ord a) => Interval a -> Interval a -> Property prop_within_predicate = prop_predicate_unions withinRelations within prop_enclosedBy_predicate :: (Ord a) => Interval a -> Interval a -> Property prop_enclosedBy_predicate = prop_predicate_unions withinRelations enclosedBy prop_encloses_predicate :: (Ord a) => Interval a -> Interval a -> Property prop_encloses_predicate = prop_predicate_unions (converse withinRelations) encloses instance IntervalRelationProperties Int Int instance IntervalRelationProperties Day Integer instance IntervalRelationProperties UTCTime NominalDiffTime