packages feed

interval-algebra 1.4.0 → 2.0.0

raw patch · 9 files changed

+240/−100 lines, 9 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- IntervalAlgebra.Arbitrary: instance (Test.QuickCheck.Arbitrary.Arbitrary b, Test.QuickCheck.Arbitrary.Arbitrary (IntervalAlgebra.Core.Interval a)) => Test.QuickCheck.Arbitrary.Arbitrary (IntervalAlgebra.PairedInterval.PairedInterval b a)
- IntervalAlgebra.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary (IntervalAlgebra.Core.Interval Data.Time.Calendar.Days.Day)
- IntervalAlgebra.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary (IntervalAlgebra.Core.Interval Data.Time.Clock.Internal.UTCTime.UTCTime)
- IntervalAlgebra.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary (IntervalAlgebra.Core.Interval GHC.Types.Int)
- IntervalAlgebra.Core: diffFromBegin :: (IntervalSizeable a b, Functor i1, Intervallic i0 a) => i0 a -> i1 a -> i1 b
- IntervalAlgebra.Core: diffFromEnd :: (IntervalSizeable a b, Functor i1, Intervallic i0 a) => i0 a -> i1 a -> i1 b
- IntervalAlgebra.Core: moment' :: (IntervalSizeable a b, Intervallic i a) => i a -> b
+ IntervalAlgebra.Core: instance (GHC.Classes.Ord a, Test.QuickCheck.Arbitrary.Arbitrary a) => Test.QuickCheck.Arbitrary.Arbitrary (IntervalAlgebra.Core.Interval a)
+ IntervalAlgebra.Core: shiftFromBegin :: (IntervalSizeable a b, Functor i1, Intervallic i0 a) => i0 a -> i1 a -> i1 b
+ IntervalAlgebra.Core: shiftFromEnd :: (IntervalSizeable a b, Functor i1, Intervallic i0 a) => i0 a -> i1 a -> i1 b
+ IntervalAlgebra.IntervalUtilities: allGapsWithinLessThanDuration :: (IntervalSizeable a b, Intervallic i0 a, IntervalCombinable i1 a, Monoid (t (Interval a)), Monoid (t (Maybe (Interval a))), Applicative t, Witherable t) => b -> i0 a -> t (i1 a) -> Bool
+ IntervalAlgebra.IntervalUtilities: anyGapsWithinAtLeastDuration :: (IntervalSizeable a b, Intervallic i0 a, IntervalCombinable i1 a, Monoid (t (Interval a)), Monoid (t (Maybe (Interval a))), Applicative t, Witherable t) => b -> i0 a -> t (i1 a) -> Bool
+ IntervalAlgebra.IntervalUtilities: lookahead :: (Intervallic i a, IntervalSizeable a b) => b -> i a -> Interval a
+ IntervalAlgebra.IntervalUtilities: lookback :: (Intervallic i a, IntervalSizeable a b) => b -> i a -> Interval a
+ IntervalAlgebra.IntervalUtilities: makeGapsWithinPredicate :: (Monoid (t (Interval a)), Monoid (t (Maybe (Interval a))), Applicative t, Witherable t, IntervalSizeable a b, Intervallic i0 a, IntervalCombinable i1 a) => ((b -> Bool) -> t b -> Bool) -> (b -> b -> Bool) -> b -> i0 a -> t (i1 a) -> Bool
+ IntervalAlgebra.IntervalUtilities: pairGaps :: (Intervallic i a, IntervalSizeable a b, IntervalCombinable i a) => [i a] -> [Maybe b]
+ IntervalAlgebra.PairedInterval: instance (Test.QuickCheck.Arbitrary.Arbitrary b, GHC.Classes.Ord a, Test.QuickCheck.Arbitrary.Arbitrary a) => Test.QuickCheck.Arbitrary.Arbitrary (IntervalAlgebra.PairedInterval.PairedInterval b a)
- IntervalAlgebra.Arbitrary: arbitraryWithRelation :: (IntervalSizeable a b, Intervallic i a, Arbitrary (i a)) => i a -> Set IntervalRelation -> Gen (Maybe (i a))
+ IntervalAlgebra.Arbitrary: arbitraryWithRelation :: forall i a b. (IntervalSizeable a b, Intervallic i a, Arbitrary (i a)) => i a -> Set IntervalRelation -> Gen (Maybe (i a))
- IntervalAlgebra.Core: beginerval :: IntervalSizeable a b => b -> a -> Interval a
+ IntervalAlgebra.Core: beginerval :: forall a b. IntervalSizeable a b => b -> a -> Interval a
- IntervalAlgebra.Core: beginervalMoment :: IntervalSizeable a b => a -> Interval a
+ IntervalAlgebra.Core: beginervalMoment :: forall a b. IntervalSizeable a b => a -> Interval a
- IntervalAlgebra.Core: enderval :: IntervalSizeable a b => b -> a -> Interval a
+ IntervalAlgebra.Core: enderval :: forall a b. IntervalSizeable a b => b -> a -> Interval a
- IntervalAlgebra.Core: endervalMoment :: IntervalSizeable a b => a -> Interval a
+ IntervalAlgebra.Core: endervalMoment :: forall a b. IntervalSizeable a b => a -> Interval a
- IntervalAlgebra.Core: expand :: (IntervalSizeable a b, Intervallic i a) => b -> b -> i a -> i a
+ IntervalAlgebra.Core: expand :: forall i a b. (IntervalSizeable a b, Intervallic i a) => b -> b -> i a -> i a
- IntervalAlgebra.Core: moment :: IntervalSizeable a b => b
+ IntervalAlgebra.Core: moment :: forall a. IntervalSizeable a b => b
- IntervalAlgebra.Core: momentize :: (IntervalSizeable a b, Intervallic i a) => i a -> i a
+ IntervalAlgebra.Core: momentize :: forall i a b. (IntervalSizeable a b, Intervallic i a) => i a -> i a

Files

ChangeLog.md view
@@ -1,5 +1,14 @@ # Changelog for interval-algebra +## 2.0++* Adds `Abitrary (Interval a)` instance generic over `Ord a, Arbitrary a`.+* Removes the `moment'` function from the `IntervalSizeable` class.+Use type application with `moment` instead, as in `moment @Int`, `moment @Day`, etc.+* Adds the following utility functions:+`lookback`, `lookahead`, `makeGapsWithinPredicate`,+`pairGaps`, `anyGapsWithinAtLeastDuration`, `allGapsWithinLessThanDuration`+ ## 1.4.0  * Adds the `safeInterval` function to `Core`,@@ -59,7 +68,7 @@  ## 0.10.0 -* Adds `diffFromBegin` (`diffFromEnd`) functions (not totally satisfied with these names) which change the reference point of the interval in the second argument by the difference from the `begin` (`end`) of the interval in the first argument.+* Adds `shiftFromBegin` (`shiftFromEnd`) functions (not totally satisfied with these names) which change the reference point of the interval in the second argument by the difference from the `begin` (`end`) of the interval in the first argument. * Adds a `Functor` instance for `PairedInterval b`s, which maps an `PairedInterval c a` to `PairedInterval c b`. That is, `fmap` acts on the interval type.  ## 0.9.0
interval-algebra.cabal view
@@ -1,6 +1,6 @@ cabal-version:  2.2 name:           interval-algebra-version:        1.4.0+version:        2.0.0 synopsis:       An implementation of Allen's interval algebra for temporal logic description:    Please see the README on GitHub at <https://github.com/novisci/interval-algebra> category:       Algebra,Time
src/IntervalAlgebra/Arbitrary.hs view
@@ -10,6 +10,8 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE Safe              #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}   module IntervalAlgebra.Arbitrary@@ -56,7 +58,7 @@                                                 , converse                                                 , duration                                                 , makePairedInterval-                                                , moment'+                                                , moment                                                 , predicate                                                 , strictWithinRelations                                                 )@@ -82,9 +84,6 @@ maxDiffTime :: Int maxDiffTime = 86399 -instance Arbitrary (Interval Int) where-  arbitrary = liftM2 beginerval arbitrarySizedPositive arbitrary- instance Arbitrary DT.Day where   arbitrary = sized (\s -> DT.ModifiedJulianDay <$> s `resize` arbitrary)   shrink    = (DT.ModifiedJulianDay <$>) . shrink . DT.toModifiedJulianDay@@ -100,31 +99,28 @@ instance Arbitrary DT.UTCTime  where   arbitrary = liftA2 UTCTime arbitrary arbitrary -instance Arbitrary (Interval DT.Day) where-  arbitrary = liftM2 beginerval arbitrary arbitrary--instance Arbitrary (Interval DT.UTCTime) where-  arbitrary = liftM2 beginerval arbitrary arbitrary--instance (Arbitrary b, Arbitrary (Interval a)) => Arbitrary (PairedInterval b a) where-  arbitrary = liftM2 makePairedInterval arbitrary arbitrary- -- | Conditional generation of intervals relative to a reference.  If the--- reference `iv` is of 'moment' duration, it is not possible to generate+-- reference @iv@ is of 'moment' duration, it is not possible to generate -- intervals from the strict enclose relations StartedBy, Contains, FinishedBy.--- If `iv` and `rs` are such that no possible relations can be generated, this+-- If @iv@ and @rs@ are such that no possible relations can be generated, this -- function returns `Nothing`. Otherwise, it returns `Just` an interval that--- satisfies at least one of the possible relations in `rs` relative to--- `iv`.+-- satisfies at least one of the possible relations in @rs@ relative to+-- @iv@. ----- >>> generate $ arbitraryWithRelation (beginerval 10 (0::Int)) (fromList [Before])+-- @+-- > import Test.QuickCheck (generate)+-- > import Data.Set (fromList)+-- > isJust $ generate $ arbitraryWithRelation (beginerval 10 (0::Int)) (fromList [Before]) -- Just (20, 22)--- >>> generate $ arbitraryWithRelation (beginerval 1 (0::Int)) (fromList [StartedBy])+-- > generate $ arbitraryWithRelation (beginerval 1 (0::Int)) (fromList [StartedBy]) -- Nothing--- >>> generate $ arbitraryWithRelation (beginerval 1 (0::Int)) (fromList [StartedBy, Before])+-- > generate $ arbitraryWithRelation (beginerval 1 (0::Int)) (fromList [StartedBy, Before]) -- Just (4, 13)+-- @+-- arbitraryWithRelation-  :: (IntervalSizeable a b, Intervallic i a, Arbitrary (i a))+  :: forall i a b+   . (IntervalSizeable a b, Intervallic i a, Arbitrary (i a))   => i a -- ^ reference interval   -> Data.Set.Set IntervalRelation -- ^ set of `IntervalRelation`s, of which at least one will hold for the generated interval relative to the reference   -> Gen (Maybe (i a))@@ -136,4 +132,4 @@  where   notStrictEnclose = Data.Set.difference rs (converse strictWithinRelations)   isEnclose        = Data.Set.null notStrictEnclose-  isMom            = duration iv == moment' iv+  isMom            = duration iv == moment @a
src/IntervalAlgebra/Core.hs view
@@ -181,8 +181,8 @@   , endervalFromBegin   , beginervalMoment   , endervalMoment-  , diffFromBegin-  , diffFromEnd+  , shiftFromBegin+  , shiftFromEnd   , momentize      -- ** Algebraic operations@@ -202,7 +202,9 @@   , IntervalSizeable(..)   ) where -import           Control.Applicative            ( Applicative(pure) )+import           Control.Applicative            ( Applicative(pure)+                                                , liftA2+                                                ) import           Control.DeepSeq                ( NFData ) import           Data.Binary                    ( Binary ) import           Data.Fixed                     ( Pico )@@ -261,6 +263,7 @@                                                 , Show                                                 , String                                                 , any+                                                , curry                                                 , fromInteger                                                 , fromRational                                                 , map@@ -273,6 +276,11 @@                                                 , toInteger                                                 , toRational                                                 )+import           Test.QuickCheck                ( Arbitrary(..)+                                                , resize+                                                , sized+                                                , suchThat+                                                )  {- | An @'Interval' a@ is a pair \( (x, y) \text{ such that } x < y\). To create intervals use the @'parseInterval'@, @'beginerval'@, or @'enderval'@ functions.@@ -283,20 +291,24 @@ newtype ParseErrorInterval = ParseErrorInterval String     deriving (Eq, Show) +-- | Helper defining what a valid relation is between begin and end of an+-- Interval.+isValidBeginEnd :: (Ord a) => a -> a -> Bool+isValidBeginEnd b e = b < e+ -- | Safely parse a pair of @a@s to create an @'Interval' a@. -- -- >>> parseInterval 0 1 -- Right (0, 1) --  -- >>> parseInterval 1 0--- Left "0<1"+-- Left (ParseErrorInterval "0<=1") --  parseInterval   :: (Show a, Ord a) => a -> a -> Either ParseErrorInterval (Interval a) parseInterval x y-  | x < y     = Right $ Interval (x, y)-  | otherwise = Left $ ParseErrorInterval $ show y ++ "<=" ++ show x-+  | isValidBeginEnd x y = Right $ Interval (x, y)+  | otherwise           = Left $ ParseErrorInterval $ show y ++ "<=" ++ show x -- | A synonym for `parseInterval` prsi :: (Show a, Ord a) => a -> a -> Either ParseErrorInterval (Interval a) prsi = parseInterval@@ -630,13 +642,9 @@ class (Ord a, Num b, Ord b) => IntervalSizeable a b | a -> b where      -- | The smallest duration for an 'Interval a'.-    moment :: b+    moment :: forall a . b     moment = 1 -    -- | Gives back a 'moment' based on the input's type.-    moment' :: Intervallic i a => i a -> b-    moment' x = moment @a-     -- | Determine the duration of an @'i a'@.     duration :: Intervallic i a => i a -> b     duration x = diff (end x) (begin x)@@ -659,15 +667,16 @@ -- (-1, 3) -- expand-  :: (IntervalSizeable a b, Intervallic i a)+  :: forall i a b+   . (IntervalSizeable a b, Intervallic i a)   => b -- ^ duration to subtract from the 'begin'   -> b -- ^ duration to add to the 'end'   -> i a   -> i a expand l r p = setInterval p i  where-  s = if l < moment' p then 0 else negate l-  e = if r < moment' p then 0 else r+  s = if l < moment @a then 0 else negate l+  e = if r < moment @a then 0 else r   i = Interval (add s $ begin p, add e $ end p)  -- | Expands an @i a@ to "left".@@ -699,15 +708,17 @@ -- (0, 2) -- beginerval-  :: (IntervalSizeable a b)+  :: forall a b+   . (IntervalSizeable a b)   => b -- ^ @dur@ation to add to the 'begin'    -> a -- ^ the 'begin' point of the 'Interval'   -> Interval a beginerval dur x = Interval (x, y)  where   i = Interval (x, x)-  d = max (moment' i) dur+  d = max (moment @a) dur   y = add d x+{-# INLINABLE beginerval #-}  -- | A synonym for `beginerval` bi@@ -716,8 +727,8 @@   -> a -- ^ the 'begin' point of the 'Interval'   -> Interval a bi = beginerval-{-# INLINABLE beginerval #-} + -- | Safely creates an 'Interval a' using @x@ as the 'end' and adding --   @negate max 'moment' dur@ to @x@ as the 'begin'. --@@ -731,12 +742,14 @@ -- (-2, 0) -- enderval-  :: (IntervalSizeable a b)+  :: forall a b+   . (IntervalSizeable a b)   => b -- ^ @dur@ation to subtract from the 'end'    -> a -- ^ the 'end' point of the 'Interval'   -> Interval a-enderval dur x = Interval (add (negate $ max (moment' i) dur) x, x)+enderval dur x = Interval (add (negate $ max (moment @a) dur) x, x)   where i = Interval (x, x)+{-# INLINABLE enderval #-}  -- | A synonym for `enderval` ei@@ -745,8 +758,8 @@   -> a -- ^ the 'end' point of the 'Interval'   -> Interval a ei = enderval-{-# INLINABLE enderval #-} + -- | Safely creates an @'Interval'@ from a pair of endpoints. -- IMPORTANT: This function uses 'beginerval',  -- thus if the second element of the pair is `<=` the first element,@@ -785,16 +798,16 @@ -- >>> beginervalMoment (10 :: Int) -- (10, 11) -- -beginervalMoment :: (IntervalSizeable a b) => a -> Interval a-beginervalMoment x = beginerval (moment' i) x where i = Interval (x, x)+beginervalMoment :: forall a b . (IntervalSizeable a b) => a -> Interval a+beginervalMoment x = beginerval (moment @a) x where i = Interval (x, x)  -- | Safely creates a new @Interval@ with 'moment' length with 'end' at @x@ -- -- >>> endervalMoment (10 :: Int) -- (9, 10) -- -endervalMoment :: (IntervalSizeable a b) => a -> Interval a-endervalMoment x = enderval (moment' i) x where i = Interval (x, x)+endervalMoment :: forall a b . (IntervalSizeable a b) => a -> Interval a+endervalMoment x = enderval (moment @a) x where i = Interval (x, x)  -- | Creates a new @Interval@ spanning the extent x and y. --@@ -808,36 +821,34 @@   e = max (end x) (end y)  -- | Modifies the endpoints of second argument's interval by taking the difference---   from the first's input's 'begin'.--- --- >>> diffFromBegin (Interval ((5::Int), 6)) (Interval (10, 15))+--   from the first's input's 'begin'. +-- >>> shiftFromBegin (Interval ((5::Int), 6)) (Interval (10, 15)) -- (5, 10) ----- >>> diffFromBegin (Interval ((1::Int), 2)) (Interval (3, 15))+-- >>> shiftFromBegin (Interval ((1::Int), 2)) (Interval (3, 15)) -- (2, 14) ---diffFromBegin+shiftFromBegin   :: (IntervalSizeable a b, Functor i1, Intervallic i0 a)   => i0 a   -> i1 a   -> i1 b-diffFromBegin i = fmap (`diff` begin i)+shiftFromBegin i = fmap (`diff` begin i)  -- | Modifies the endpoints of second argument's interval by taking the difference --   from the first's input's 'end'.------ >>> diffFromEnd (Interval ((5::Int), 6)) (Interval (10, 15))+-- >>> shiftFromEnd (Interval ((5::Int), 6)) (Interval (10, 15)) -- (4, 9) ----- >>> diffFromEnd (Interval ((1::Int), 2)) (Interval (3, 15))+-- >>> shiftFromEnd (Interval ((1::Int), 2)) (Interval (3, 15)) -- (1, 13) ---diffFromEnd+shiftFromEnd   :: (IntervalSizeable a b, Functor i1, Intervallic i0 a)   => i0 a   -> i1 a   -> i1 b-diffFromEnd i = fmap (`diff` end i)+shiftFromEnd i = fmap (`diff` end i)  -- | Changes the duration of an 'Intervallic' value to a moment starting at the  --   'begin' of the interval.@@ -845,8 +856,9 @@ -- >>> momentize (Interval (6, 10)) -- (6, 7) ---momentize :: (IntervalSizeable a b, Intervallic i a) => i a -> i a-momentize i = setInterval i (beginerval (moment' i) (begin i))+momentize+  :: forall i a b . (IntervalSizeable a b, Intervallic i a) => i a -> i a+momentize i = setInterval i (beginerval (moment @a) (begin i))  {- | The @'IntervalCombinable'@ typeclass provides methods for (possibly) combining@@ -936,3 +948,13 @@   moment = toEnum 1 :: NominalDiffTime   add    = addUTCTime   diff   = diffUTCTime++-- Arbitrary instances+instance (Ord a, Arbitrary a) => Arbitrary (Interval a) where+  arbitrary =+    sized+        (\s -> liftA2 (curry Interval)+                      (s `resize` arbitrary)+                      (s `resize` arbitrary)+        )+      `suchThat` (\i -> isValidBeginEnd (intervalBegin i) (intervalEnd i))
src/IntervalAlgebra/IntervalDiagram.hs view
@@ -103,7 +103,7 @@ Moreover, the type @b@ should be castable to @Int@, using its @'Witch.From' b Int@  instance. ->>> import PrettyPrinter (pretty)+>>> import Prettyprinter (pretty) >>> import IntervalAlgebra (beginerval) >>> pretty $ MkIntervalText '-' (beginerval 5 (0::Int)) -----@@ -144,8 +144,7 @@  Values of this type should only be created through the 'parseIntervalTextLine' function,-which checks that the inputs are parsed correctly and-uses the 'makeIntervalLine' function to form intervals +which checks that the inputs are parsed correctly to form intervals  that will be pretty-printed correctly.  >>> let i1 =  MkIntervalText '*' (beginerval 10 (5::Int))@@ -249,7 +248,7 @@   makeIntervalLine     :: NE.NonEmpty (IntervalText Int) -> NE.NonEmpty (IntervalText Int)   makeIntervalLine x =-    NE.head x NE.:| zipWith diffFromEnd (toList x) (NE.tail x)+    NE.head x NE.:| zipWith shiftFromEnd (toList x) (NE.tail x)    -- Creates all pairs of a list   pairs = go@@ -560,14 +559,11 @@  This function provides the most flexibility in producing interval diagrams. --To create @'IntervalText'@ values use its @'From'@ instance, as in:-->>> let mkIntrvl c d b = into @(IntervalText Int) (c, bi d (b :: Int))- Here's a basic diagram that shows how to put more than one interval interval on a line: +>>> :set -XTypeApplications -XFlexibleContexts -XOverloadedStrings+>>> let mkIntrvl c d b = into @(IntervalText Int) (c, bi d (b :: Int)) >>> let x = mkIntrvl  '=' 20 0 >>> let l1 = [ mkIntrvl '-' 1 4 ] >>> let l2 = [ mkIntrvl '*' 3 5, mkIntrvl '*' 5 10, mkIntrvl 'x' 1 17 ]@@ -684,6 +680,7 @@ using the 'defaultIntervalDiagramOptions'.   >>> import Data.Maybe (fromMaybe)+>>> import IntervalAlgebra.IntervalUtilities (gapsWithin) >>> pretty $ simpleIntervalDiagram (bi 10 (0 :: Int)) (fmap (bi 1) [0..9]) -  -
src/IntervalAlgebra/IntervalUtilities.hs view
@@ -6,12 +6,12 @@ Maintainer  : bsaul@novisci.com Stability   : experimental -In the examples below, @iv@ is a synonym for 'beginerval' used to save space. -}  {-# LANGUAGE Safe #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TupleSections #-}  module IntervalAlgebra.IntervalUtilities   (@@ -56,6 +56,16 @@   , filterEnclose   , filterEnclosedBy +    -- * Functions for manipulating intervals+  , lookback+  , lookahead++    -- * Gaps+  , makeGapsWithinPredicate+  , pairGaps+  , anyGapsWithinAtLeastDuration+  , allGapsWithinLessThanDuration+     -- * Misc utilities   , relations   , relationsL@@ -70,7 +80,7 @@ import qualified Control.Foldl                 as L import safe      Control.Monad                  ( Functor(fmap) ) import safe      Data.Bool                      ( (&&)-                                                , Bool+                                                , Bool(..)                                                 , not                                                 , otherwise                                                 , (||)@@ -90,10 +100,15 @@                                                 , maybeToList                                                 ) import safe      Data.Monoid                    ( Monoid(mempty) )-import safe      Data.Ord                       ( Ord(max, min) )+import safe      Data.Ord                       ( (<)+                                                , (>=)+                                                , Ord(max, min)+                                                ) import safe      Data.Semigroup                 ( Semigroup((<>)) ) import safe      Data.Traversable               ( Traversable(sequenceA) )-import safe      Data.Tuple                     ( fst )+import safe      Data.Tuple                     ( fst+                                                , uncurry+                                                ) import safe      GHC.Int                        ( Int ) import safe      GHC.Show                       ( Show ) import safe      IntervalAlgebra.Core           ( (<|>)@@ -155,7 +170,6 @@                                                 )  - ------------------------------------------------- -- Unexported utilties used in functions below -- -------------------------------------------------@@ -174,6 +188,103 @@   step (fs, Just x ) y = (fs <> pure (f x y), Just y)   done (fs, _) = fs +-- | Create a predicate function that checks whether within a provided spanning+--   interval, are there (e.g. any, all) gaps of (e.g. <, <=, >=, >) a specified+--   duration among  the input intervals?+makeGapsWithinPredicate+  :: ( Monoid (t (Interval a))+     , Monoid (t (Maybe (Interval a)))+     , Applicative t+     , Witherable.Witherable t+     , IntervalSizeable a b+     , Intervallic i0 a+     , IntervalCombinable i1 a+     )+  => ((b -> Bool) -> t b -> Bool)+  -> (b -> b -> Bool)+  -> (b -> i0 a -> t (i1 a) -> Bool)+makeGapsWithinPredicate f op gapDuration interval l =+  maybe False (f (`op` gapDuration) . durations) (gapsWithin interval l)++-- | Gets the durations of gaps (via 'IntervalAlgebra.(><)') between all pairs+--   of the input.+pairGaps+  :: (Intervallic i a, IntervalSizeable a b, IntervalCombinable i a)+  => [i a]+  -> [Maybe b]+pairGaps es = fmap (fmap duration . uncurry (><)) (pairs es)+-- Generate all pair-wise combinations of a single list.+-- pairs :: [a] -> [(a, a)]+-- copied from the hgeometry library+-- (https://hackage.haskell.org/package/hgeometry-0.12.0.4/docs/src/Data.Geometry.Arrangement.Internal.html#allPairs)+ where+  pairs = go+   where+    go []       = []+    go (x : xs) = fmap (x, ) xs <> go xs++-- | Creates a new @Interval@ of a provided lookback duration ending at the +--   'begin' of the input interval.+--+-- >>> lookback 4 (beginerval 10 (1 :: Int))+-- (-3, 1)+lookback+  :: (Intervallic i a, IntervalSizeable a b)+  => b   -- ^ lookback duration+  -> i a+  -> Interval a+lookback d x = enderval d (begin x)++-- | Creates a new @Interval@ of a provided lookahead duration beginning at the +--   'end' of the input interval.+--+-- >>> lookahead 4 (beginerval 1 (1 :: Int))+-- (2, 6)+lookahead+  :: (Intervallic i a, IntervalSizeable a b)+  => b   -- ^ lookahead duration+  -> i a+  -> Interval a+lookahead d x = beginerval d (end x)++-- | Within a provided spanning interval, are there any gaps of at least the+--   specified duration among the input intervals?+anyGapsWithinAtLeastDuration+  :: ( IntervalSizeable a b+     , Intervallic i0 a+     , IntervalCombinable i1 a+     , Monoid (t (Interval a))+     , Monoid (t (Maybe (Interval a)))+     , Applicative t+     , Witherable.Witherable t+     )+  => b       -- ^ duration of gap+  -> i0 a  -- ^ within this interval+  -> t (i1 a)+  -> Bool+anyGapsWithinAtLeastDuration = makeGapsWithinPredicate any (>=)++-- | Within a provided spanning interval, are all gaps less than the specified+--   duration among the input intervals?+--+-- >>> allGapsWithinLessThanDuration 30 (beginerval 100 (0::Int)) [beginerval 5 (-1), beginerval 99 10]+-- True+allGapsWithinLessThanDuration+  :: ( IntervalSizeable a b+     , Intervallic i0 a+     , IntervalCombinable i1 a+     , Monoid (t (Interval a))+     , Monoid (t (Maybe (Interval a)))+     , Applicative t+     , Witherable.Witherable t+     )+  => b       -- ^ duration of gap+  -> i0 a  -- ^ within this interval+  -> t (i1 a)+  -> Bool+allGapsWithinLessThanDuration = makeGapsWithinPredicate all (<)++ -- Used to combine two lists by combining the last element of @x@ and the first  -- element of @y@ by @f@. The combining function @f@ will generally return a  -- singleton list in the case that the last of x and head of y can be combined@@ -191,15 +302,17 @@ -- -- >>> relationsL [iv 1 0, iv 1 1]  -- [Meets]+-- relationsL :: (Foldable f, Intervallic i a) => f (i a) -> [IntervalRelation] relationsL = relations  -- | A generic form of 'relations' which can output any 'Applicative' and  --   'Monoid' structure. ----- >>> (relations [iv 1 0, iv 1 1]) :: [IntervalRelation (Interval Int)]+-- >>> (relations [iv 1 0,iv 1 1]) :: [IntervalRelation] -- [Meets] --+-- relations   :: (Foldable f, Applicative m, Intervallic i a, Monoid (m IntervalRelation))   => f (i a)@@ -239,6 +352,7 @@ --   sorted*. See 'gapsL' for a version that always returns a list. -- -- >>> gaps [iv 4 1, iv 4 8, iv 3 11]+-- Nothing -- gaps   :: ( IntervalCombinable i a@@ -416,7 +530,7 @@  -- | Returns 'Nothing' if *any* of the element of input satisfy the predicate condition. ----- >>> nothingIfAny (starts (iv 2 3)) [iv 3 3, iv 1 5]+-- >>> nothingIfAny (startedBy (iv 2 3)) [iv 3 3, iv 1 5] -- Just [(3, 6),(5, 6)] -- -- >>> nothingIfAny (starts (iv 2 3)) [iv 3 3, iv 1 5]
src/IntervalAlgebra/PairedInterval.hs view
@@ -23,6 +23,7 @@   , trivialize   ) where +import safe      Control.Applicative            ( liftA2 ) import safe      Control.DeepSeq                ( NFData ) import safe      Data.Bifunctor                 ( Bifunctor(bimap) ) import safe      Data.Binary                    ( Binary )@@ -34,6 +35,7 @@                                                 , before                                                 , extenterval                                                 )+import safe      Test.QuickCheck                ( Arbitrary(..) ) import safe      Witherable                     ( Filterable(filter) )  -- | An @Interval a@ paired with some other data of type @b@.@@ -105,3 +107,8 @@ --   @PairedInterval Empty a@(s). trivialize :: Functor f => f (Interval a) -> f (PairedInterval Empty a) trivialize = fmap toTrivialPair+++-- Arbitrary instance+instance (Arbitrary b, Ord a, Arbitrary a) => Arbitrary (PairedInterval b a) where+  arbitrary = liftA2 makePairedInterval arbitrary arbitrary
test/IntervalAlgebra/IntervalUtilitiesSpec.hs view
@@ -1,9 +1,7 @@-{- HLINT ignore -} {-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeApplications  #-}--+{- HLINT ignore -} module IntervalAlgebra.IntervalUtilitiesSpec   ( spec   ) where@@ -35,7 +33,7 @@                                                 , disjointRelations                                                 , duration                                                 , intervalRelations-                                                , moment'+                                                , moment                                                 , predicate                                                 , safeInterval                                                 , starts@@ -105,8 +103,6 @@                                                 ) import           Witherable                     ( Filterable ) -- -- Types for testing  -- SmallInterval is just to test properties for which events of interest are so@@ -294,7 +290,7 @@   rels  = refRelations ir   isEnclose =     Data.Set.null $ Data.Set.difference rels (converse strictWithinRelations)-  isMom = duration refIv == moment' refIv+  isMom = duration refIv == moment @Int   -- Check that the only relation remaining after applying a function is Before
test/IntervalAlgebraSpec.hs view
@@ -103,11 +103,11 @@       `shouldBe` True      it "beginervalMoment duration is moment"-      $          moment' (beginervalMoment (-13 :: Int))-      `shouldBe` (1 :: Int)+      $          duration (beginervalMoment (-13 :: Int))+      `shouldBe` (moment @Int)     it "endervalMoment duration is moment"-      $          moment' (endervalMoment (26 :: Int))-      `shouldBe` (1 :: Int)+      $          duration (endervalMoment (26 :: Int))+      `shouldBe` (moment @Int)      it "parsing fails on bad inputs" $ parseInterval 10 0 `shouldBe` Left       (IA.ParseErrorInterval "0<=10")@@ -203,7 +203,6 @@    describe "IntervalSizeable tests" $ do     it "moment is 1" $ moment @Int `shouldBe` 1-    it "moment' is 1" $ moment' (beginerval 1 (0 :: Int)) `shouldBe` 1     it "expandl doesn't change end" $ property (prop_expandl_end @Int)     it "expandr doesn't change begin" $ property (prop_expandr_begin @Int)     it "expand 0 5 Interval (0, 1) should be Interval (0, 6)"@@ -244,22 +243,22 @@       $          Right (enderval (-2 :: Int) 10)       `shouldBe` parseInterval (9 :: Int) (10 :: Int) -    it "diffFromBegin can convert Interval Int to Interval Int"-      $          diffFromBegin (beginerval 2 (4 :: Int)) (beginerval 2 10)+    it "shiftFromBegin can convert Interval Int to Interval Int"+      $          shiftFromBegin (beginerval 2 (4 :: Int)) (beginerval 2 10)       `shouldBe` beginerval 2 6 -- (6, 8) -    it "diffFromEnd can convert Interval Int to Interval Int"-      $          diffFromEnd (beginerval 2 (4 :: Int)) (beginerval 2 10)+    it "shiftFromEnd can convert Interval Int to Interval Int"+      $          shiftFromEnd (beginerval 2 (4 :: Int)) (beginerval 2 10)       `shouldBe` beginerval 2 4 -- (4, 6) -    it "diffFromBegin can convert Interval Day to Interval Integer"-      $          diffFromBegin (beginerval 2 (fromGregorian 2001 1 1))-                               (beginerval 2 (fromGregorian 2001 1 10))+    it "shiftFromBegin can convert Interval Day to Interval Integer"+      $          shiftFromBegin (beginerval 2 (fromGregorian 2001 1 1))+                                (beginerval 2 (fromGregorian 2001 1 10))       `shouldBe` beginerval 2 9 -- (9, 11) -    it "diffFromEnd can convert Interval Day to Interval Integer"-      $          diffFromEnd (beginerval 2 (fromGregorian 2001 1 1))-                             (beginerval 2 (fromGregorian 2001 1 10))+    it "shiftFromEnd can convert Interval Day to Interval Integer"+      $          shiftFromEnd (beginerval 2 (fromGregorian 2001 1 1))+                              (beginerval 2 (fromGregorian 2001 1 10))       `shouldBe` beginerval 2 7 -- (7, 9)      it "momentize works"