IntervalMap 0.4.0.1 → 0.4.1.0
raw patch · 14 files changed
+1536/−180 lines, 14 filesdep +SegmentTreedep +fingertreePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: SegmentTree, fingertree
API changes (from Hackage documentation)
- Data.IntervalMap.Generic.Interval: instance Ord a => Interval (Interval a) a
- Data.IntervalMap.Interval: instance Eq a => Eq (Interval a)
- Data.IntervalMap.Interval: instance Functor Interval
- Data.IntervalMap.Interval: instance NFData a => NFData (Interval a)
- Data.IntervalMap.Interval: instance Ord a => Ord (Interval a)
- Data.IntervalMap.Interval: instance Read a => Read (Interval a)
- Data.IntervalMap.Interval: instance Show a => Show (Interval a)
+ Data.IntervalMap.Generic.Interval: instance GHC.Classes.Ord a => Data.IntervalMap.Generic.Interval.Interval (Data.IntervalMap.Interval.Interval a) a
+ Data.IntervalMap.Interval: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Data.IntervalMap.Interval.Interval a)
+ Data.IntervalMap.Interval: instance GHC.Base.Functor Data.IntervalMap.Interval.Interval
+ Data.IntervalMap.Interval: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.IntervalMap.Interval.Interval a)
+ Data.IntervalMap.Interval: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.IntervalMap.Interval.Interval a)
+ Data.IntervalMap.Interval: instance GHC.Read.Read a => GHC.Read.Read (Data.IntervalMap.Interval.Interval a)
+ Data.IntervalMap.Interval: instance GHC.Show.Show a => GHC.Show.Show (Data.IntervalMap.Interval.Interval a)
+ Data.IntervalSet: (\\) :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k -> IntervalSet k
+ Data.IntervalSet: Nil :: IntervalSet k
+ Data.IntervalSet: Node :: !Color -> !k -> !k -> !(IntervalSet k) -> !(IntervalSet k) -> IntervalSet k
+ Data.IntervalSet: above :: Interval i e => e -> i -> Bool
+ Data.IntervalSet: after :: Interval i e => i -> i -> Bool
+ Data.IntervalSet: before :: Interval i e => i -> i -> Bool
+ Data.IntervalSet: below :: Interval i e => e -> i -> Bool
+ Data.IntervalSet: class Ord e => Interval i e | i -> e where leftClosed _ = True rightClosed _ = True a `before` b = upperBound a < lowerBound b || (upperBound a == lowerBound b && not (rightClosed a && leftClosed b)) a `after` b = b `before` a a `subsumes` b = (lowerBound a < lowerBound b || (lowerBound a == lowerBound b && (leftClosed a || not (leftClosed b)))) && (upperBound a > upperBound b || (upperBound a == upperBound b && (rightClosed a || not (rightClosed b)))) a `overlaps` b = (lowerBound a < upperBound b || (lowerBound a == upperBound b && leftClosed a && rightClosed b)) && (upperBound a > lowerBound b || (upperBound a == lowerBound b && rightClosed a && leftClosed b)) p `below` i = case compare p (lowerBound i) of { LT -> True EQ -> not (leftClosed i) GT -> False } p `above` i = case compare p (upperBound i) of { LT -> False EQ -> not (rightClosed i) GT -> True } p `inside` i = not ((p `above` i) || (p `below` i)) isEmpty i | leftClosed i && rightClosed i = lowerBound i > upperBound i | otherwise = lowerBound i >= upperBound i
+ Data.IntervalSet: containing :: (Interval k e) => IntervalSet k -> e -> IntervalSet k
+ Data.IntervalSet: data IntervalSet k
+ Data.IntervalSet: delete :: (Interval k e, Ord k) => k -> IntervalSet k -> IntervalSet k
+ Data.IntervalSet: deleteFindMax :: (Interval k e, Ord k) => IntervalSet k -> (k, IntervalSet k)
+ Data.IntervalSet: deleteFindMin :: (Interval k e, Ord k) => IntervalSet k -> (k, IntervalSet k)
+ Data.IntervalSet: deleteMax :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k
+ Data.IntervalSet: deleteMin :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k
+ Data.IntervalSet: difference :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k -> IntervalSet k
+ Data.IntervalSet: elems :: IntervalSet k -> [k]
+ Data.IntervalSet: empty :: IntervalSet k
+ Data.IntervalSet: filter :: (Interval k e) => (k -> Bool) -> IntervalSet k -> IntervalSet k
+ Data.IntervalSet: findLast :: (Interval k e) => IntervalSet k -> Maybe k
+ Data.IntervalSet: findMax :: IntervalSet k -> Maybe k
+ Data.IntervalSet: findMin :: IntervalSet k -> Maybe k
+ Data.IntervalSet: foldl :: (b -> k -> b) -> b -> IntervalSet k -> b
+ Data.IntervalSet: foldl' :: (b -> k -> b) -> b -> IntervalSet k -> b
+ Data.IntervalSet: foldr :: (k -> b -> b) -> b -> IntervalSet k -> b
+ Data.IntervalSet: foldr' :: (k -> b -> b) -> b -> IntervalSet k -> b
+ Data.IntervalSet: fromAscList :: (Interval k e, Eq k) => [k] -> IntervalSet k
+ Data.IntervalSet: fromDistinctAscList :: (Interval k e) => [k] -> IntervalSet k
+ Data.IntervalSet: fromList :: (Interval k e, Ord k) => [k] -> IntervalSet k
+ Data.IntervalSet: insert :: (Interval k e, Ord k) => k -> IntervalSet k -> IntervalSet k
+ Data.IntervalSet: inside :: Interval i e => e -> i -> Bool
+ Data.IntervalSet: instance (Data.IntervalMap.Generic.Interval.Interval i k, GHC.Classes.Ord i) => GHC.Base.Monoid (Data.IntervalSet.IntervalSet i)
+ Data.IntervalSet: instance (GHC.Classes.Ord k, GHC.Read.Read k, Data.IntervalMap.Generic.Interval.Interval i k, GHC.Classes.Ord i, GHC.Read.Read i) => GHC.Read.Read (Data.IntervalSet.IntervalSet i)
+ Data.IntervalSet: instance Control.DeepSeq.NFData k => Control.DeepSeq.NFData (Data.IntervalSet.IntervalSet k)
+ Data.IntervalSet: instance Data.Foldable.Foldable Data.IntervalSet.IntervalSet
+ Data.IntervalSet: instance GHC.Classes.Eq Data.IntervalSet.Color
+ Data.IntervalSet: instance GHC.Classes.Eq k => GHC.Classes.Eq (Data.IntervalSet.IntervalSet k)
+ Data.IntervalSet: instance GHC.Classes.Ord k => GHC.Classes.Ord (Data.IntervalSet.IntervalSet k)
+ Data.IntervalSet: instance GHC.Show.Show k => GHC.Show.Show (Data.IntervalSet.IntervalSet k)
+ Data.IntervalSet: intersecting :: (Interval k e) => IntervalSet k -> k -> IntervalSet k
+ Data.IntervalSet: intersection :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k -> IntervalSet k
+ Data.IntervalSet: isEmpty :: Interval i e => i -> Bool
+ Data.IntervalSet: isProperSubsetOf :: (Ord k) => IntervalSet k -> IntervalSet k -> Bool
+ Data.IntervalSet: isSubsetOf :: (Ord k) => IntervalSet k -> IntervalSet k -> Bool
+ Data.IntervalSet: leftClosed :: Interval i e => i -> Bool
+ Data.IntervalSet: lowerBound :: Interval i e => i -> e
+ Data.IntervalSet: map :: (Interval a e1, Interval b e2, Ord b) => (a -> b) -> IntervalSet a -> IntervalSet b
+ Data.IntervalSet: mapMonotonic :: (Interval k2 e, Ord k2) => (k1 -> k2) -> IntervalSet k1 -> IntervalSet k2
+ Data.IntervalSet: maxView :: (Interval k e, Ord k) => IntervalSet k -> Maybe (k, IntervalSet k)
+ Data.IntervalSet: member :: (Ord k) => k -> IntervalSet k -> Bool
+ Data.IntervalSet: minView :: (Interval k e, Ord k) => IntervalSet k -> Maybe (k, IntervalSet k)
+ Data.IntervalSet: notMember :: (Ord k) => k -> IntervalSet k -> Bool
+ Data.IntervalSet: null :: IntervalSet k -> Bool
+ Data.IntervalSet: overlaps :: Interval i e => i -> i -> Bool
+ Data.IntervalSet: partition :: (Interval k e) => (k -> Bool) -> IntervalSet k -> (IntervalSet k, IntervalSet k)
+ Data.IntervalSet: rightClosed :: Interval i e => i -> Bool
+ Data.IntervalSet: singleton :: k -> IntervalSet k
+ Data.IntervalSet: size :: IntervalSet k -> Int
+ Data.IntervalSet: split :: (Interval i k, Ord i) => i -> IntervalSet i -> (IntervalSet i, IntervalSet i)
+ Data.IntervalSet: splitMember :: (Interval i k, Ord i) => i -> IntervalSet i -> (IntervalSet i, Bool, IntervalSet i)
+ Data.IntervalSet: subsumes :: Interval i e => i -> i -> Bool
+ Data.IntervalSet: toAscList :: IntervalSet k -> [k]
+ Data.IntervalSet: toDescList :: IntervalSet k -> [k]
+ Data.IntervalSet: toList :: IntervalSet k -> [k]
+ Data.IntervalSet: union :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k -> IntervalSet k
+ Data.IntervalSet: unions :: (Interval k e, Ord k) => [IntervalSet k] -> IntervalSet k
+ Data.IntervalSet: upperBound :: Interval i e => i -> e
+ Data.IntervalSet: valid :: (Interval i k, Ord i) => IntervalSet i -> Bool
+ Data.IntervalSet: within :: (Interval k e) => IntervalSet k -> k -> IntervalSet k
- Data.IntervalMap.Generic.Interval: class Ord e => Interval i e | i -> e where leftClosed _ = True rightClosed _ = True a before b = upperBound a < lowerBound b || (upperBound a == lowerBound b && not (rightClosed a && leftClosed b)) a after b = b `before` a a subsumes b = (lowerBound a < lowerBound b || (lowerBound a == lowerBound b && (leftClosed a || not (leftClosed b)))) && (upperBound a > upperBound b || (upperBound a == upperBound b && (rightClosed a || not (rightClosed b)))) a overlaps b = (lowerBound a < upperBound b || (lowerBound a == upperBound b && leftClosed a && rightClosed b)) && (upperBound a > lowerBound b || (upperBound a == lowerBound b && rightClosed a && leftClosed b)) p below i | leftClosed i = p < lowerBound i | otherwise = p <= lowerBound i p above i | rightClosed i = p > upperBound i | otherwise = p >= upperBound i p inside i = not ((p `above` i) || (p `below` i)) isEmpty i | leftClosed i && rightClosed i = lowerBound i > upperBound i | otherwise = lowerBound i >= upperBound i
+ Data.IntervalMap.Generic.Interval: class Ord e => Interval i e | i -> e where leftClosed _ = True rightClosed _ = True a `before` b = upperBound a < lowerBound b || (upperBound a == lowerBound b && not (rightClosed a && leftClosed b)) a `after` b = b `before` a a `subsumes` b = (lowerBound a < lowerBound b || (lowerBound a == lowerBound b && (leftClosed a || not (leftClosed b)))) && (upperBound a > upperBound b || (upperBound a == upperBound b && (rightClosed a || not (rightClosed b)))) a `overlaps` b = (lowerBound a < upperBound b || (lowerBound a == upperBound b && leftClosed a && rightClosed b)) && (upperBound a > lowerBound b || (upperBound a == lowerBound b && rightClosed a && leftClosed b)) p `below` i = case compare p (lowerBound i) of { LT -> True EQ -> not (leftClosed i) GT -> False } p `above` i = case compare p (upperBound i) of { LT -> False EQ -> not (rightClosed i) GT -> True } p `inside` i = not ((p `above` i) || (p `below` i)) isEmpty i | leftClosed i && rightClosed i = lowerBound i > upperBound i | otherwise = lowerBound i >= upperBound i
- Data.IntervalMap.Generic.Lazy: class Ord e => Interval i e | i -> e where leftClosed _ = True rightClosed _ = True a before b = upperBound a < lowerBound b || (upperBound a == lowerBound b && not (rightClosed a && leftClosed b)) a after b = b `before` a a subsumes b = (lowerBound a < lowerBound b || (lowerBound a == lowerBound b && (leftClosed a || not (leftClosed b)))) && (upperBound a > upperBound b || (upperBound a == upperBound b && (rightClosed a || not (rightClosed b)))) a overlaps b = (lowerBound a < upperBound b || (lowerBound a == upperBound b && leftClosed a && rightClosed b)) && (upperBound a > lowerBound b || (upperBound a == lowerBound b && rightClosed a && leftClosed b)) p below i | leftClosed i = p < lowerBound i | otherwise = p <= lowerBound i p above i | rightClosed i = p > upperBound i | otherwise = p >= upperBound i p inside i = not ((p `above` i) || (p `below` i)) isEmpty i | leftClosed i && rightClosed i = lowerBound i > upperBound i | otherwise = lowerBound i >= upperBound i
+ Data.IntervalMap.Generic.Lazy: class Ord e => Interval i e | i -> e where leftClosed _ = True rightClosed _ = True a `before` b = upperBound a < lowerBound b || (upperBound a == lowerBound b && not (rightClosed a && leftClosed b)) a `after` b = b `before` a a `subsumes` b = (lowerBound a < lowerBound b || (lowerBound a == lowerBound b && (leftClosed a || not (leftClosed b)))) && (upperBound a > upperBound b || (upperBound a == upperBound b && (rightClosed a || not (rightClosed b)))) a `overlaps` b = (lowerBound a < upperBound b || (lowerBound a == upperBound b && leftClosed a && rightClosed b)) && (upperBound a > lowerBound b || (upperBound a == lowerBound b && rightClosed a && leftClosed b)) p `below` i = case compare p (lowerBound i) of { LT -> True EQ -> not (leftClosed i) GT -> False } p `above` i = case compare p (upperBound i) of { LT -> False EQ -> not (rightClosed i) GT -> True } p `inside` i = not ((p `above` i) || (p `below` i)) isEmpty i | leftClosed i && rightClosed i = lowerBound i > upperBound i | otherwise = lowerBound i >= upperBound i
- Data.IntervalMap.Generic.Lazy: containing :: Interval k e => IntervalMap k v -> e -> [(k, v)]
+ Data.IntervalMap.Generic.Lazy: containing :: (Interval k e) => IntervalMap k v -> e -> [(k, v)]
- Data.IntervalMap.Generic.Lazy: filter :: Interval k e => (a -> Bool) -> IntervalMap k a -> IntervalMap k a
+ Data.IntervalMap.Generic.Lazy: filter :: (Interval k e) => (a -> Bool) -> IntervalMap k a -> IntervalMap k a
- Data.IntervalMap.Generic.Lazy: filterWithKey :: Interval k e => (k -> a -> Bool) -> IntervalMap k a -> IntervalMap k a
+ Data.IntervalMap.Generic.Lazy: filterWithKey :: (Interval k e) => (k -> a -> Bool) -> IntervalMap k a -> IntervalMap k a
- Data.IntervalMap.Generic.Lazy: findLast :: Interval k e => IntervalMap k v -> (k, v)
+ Data.IntervalMap.Generic.Lazy: findLast :: (Interval k e) => IntervalMap k v -> (k, v)
- Data.IntervalMap.Generic.Lazy: fromDistinctAscList :: Interval k e => [(k, v)] -> IntervalMap k v
+ Data.IntervalMap.Generic.Lazy: fromDistinctAscList :: (Interval k e) => [(k, v)] -> IntervalMap k v
- Data.IntervalMap.Generic.Lazy: intersecting :: Interval k e => IntervalMap k v -> k -> [(k, v)]
+ Data.IntervalMap.Generic.Lazy: intersecting :: (Interval k e) => IntervalMap k v -> k -> [(k, v)]
- Data.IntervalMap.Generic.Lazy: keysSet :: Ord k => IntervalMap k v -> Set k
+ Data.IntervalMap.Generic.Lazy: keysSet :: (Ord k) => IntervalMap k v -> Set k
- Data.IntervalMap.Generic.Lazy: lookup :: Ord k => k -> IntervalMap k v -> Maybe v
+ Data.IntervalMap.Generic.Lazy: lookup :: (Ord k) => k -> IntervalMap k v -> Maybe v
- Data.IntervalMap.Generic.Lazy: mapEither :: Interval k e => (a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
+ Data.IntervalMap.Generic.Lazy: mapEither :: (Interval k e) => (a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
- Data.IntervalMap.Generic.Lazy: mapEitherWithKey :: Interval i k => (i -> a -> Either b c) -> IntervalMap i a -> (IntervalMap i b, IntervalMap i c)
+ Data.IntervalMap.Generic.Lazy: mapEitherWithKey :: (Interval i k) => (i -> a -> Either b c) -> IntervalMap i a -> (IntervalMap i b, IntervalMap i c)
- Data.IntervalMap.Generic.Lazy: mapMaybe :: Interval k e => (a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
+ Data.IntervalMap.Generic.Lazy: mapMaybe :: (Interval k e) => (a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
- Data.IntervalMap.Generic.Lazy: mapMaybeWithKey :: Interval k e => (k -> a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
+ Data.IntervalMap.Generic.Lazy: mapMaybeWithKey :: (Interval k e) => (k -> a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
- Data.IntervalMap.Generic.Lazy: member :: Ord k => k -> IntervalMap k v -> Bool
+ Data.IntervalMap.Generic.Lazy: member :: (Ord k) => k -> IntervalMap k v -> Bool
- Data.IntervalMap.Generic.Lazy: notMember :: Ord k => k -> IntervalMap k v -> Bool
+ Data.IntervalMap.Generic.Lazy: notMember :: (Ord k) => k -> IntervalMap k v -> Bool
- Data.IntervalMap.Generic.Lazy: partition :: Interval k e => (a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
+ Data.IntervalMap.Generic.Lazy: partition :: (Interval k e) => (a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
- Data.IntervalMap.Generic.Lazy: partitionWithKey :: Interval k e => (k -> a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
+ Data.IntervalMap.Generic.Lazy: partitionWithKey :: (Interval k e) => (k -> a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
- Data.IntervalMap.Generic.Lazy: within :: Interval k e => IntervalMap k v -> k -> [(k, v)]
+ Data.IntervalMap.Generic.Lazy: within :: (Interval k e) => IntervalMap k v -> k -> [(k, v)]
- Data.IntervalMap.Generic.Strict: class Ord e => Interval i e | i -> e where leftClosed _ = True rightClosed _ = True a before b = upperBound a < lowerBound b || (upperBound a == lowerBound b && not (rightClosed a && leftClosed b)) a after b = b `before` a a subsumes b = (lowerBound a < lowerBound b || (lowerBound a == lowerBound b && (leftClosed a || not (leftClosed b)))) && (upperBound a > upperBound b || (upperBound a == upperBound b && (rightClosed a || not (rightClosed b)))) a overlaps b = (lowerBound a < upperBound b || (lowerBound a == upperBound b && leftClosed a && rightClosed b)) && (upperBound a > lowerBound b || (upperBound a == lowerBound b && rightClosed a && leftClosed b)) p below i | leftClosed i = p < lowerBound i | otherwise = p <= lowerBound i p above i | rightClosed i = p > upperBound i | otherwise = p >= upperBound i p inside i = not ((p `above` i) || (p `below` i)) isEmpty i | leftClosed i && rightClosed i = lowerBound i > upperBound i | otherwise = lowerBound i >= upperBound i
+ Data.IntervalMap.Generic.Strict: class Ord e => Interval i e | i -> e where leftClosed _ = True rightClosed _ = True a `before` b = upperBound a < lowerBound b || (upperBound a == lowerBound b && not (rightClosed a && leftClosed b)) a `after` b = b `before` a a `subsumes` b = (lowerBound a < lowerBound b || (lowerBound a == lowerBound b && (leftClosed a || not (leftClosed b)))) && (upperBound a > upperBound b || (upperBound a == upperBound b && (rightClosed a || not (rightClosed b)))) a `overlaps` b = (lowerBound a < upperBound b || (lowerBound a == upperBound b && leftClosed a && rightClosed b)) && (upperBound a > lowerBound b || (upperBound a == lowerBound b && rightClosed a && leftClosed b)) p `below` i = case compare p (lowerBound i) of { LT -> True EQ -> not (leftClosed i) GT -> False } p `above` i = case compare p (upperBound i) of { LT -> False EQ -> not (rightClosed i) GT -> True } p `inside` i = not ((p `above` i) || (p `below` i)) isEmpty i | leftClosed i && rightClosed i = lowerBound i > upperBound i | otherwise = lowerBound i >= upperBound i
- Data.IntervalMap.Generic.Strict: containing :: Interval k e => IntervalMap k v -> e -> [(k, v)]
+ Data.IntervalMap.Generic.Strict: containing :: (Interval k e) => IntervalMap k v -> e -> [(k, v)]
- Data.IntervalMap.Generic.Strict: filter :: Interval k e => (a -> Bool) -> IntervalMap k a -> IntervalMap k a
+ Data.IntervalMap.Generic.Strict: filter :: (Interval k e) => (a -> Bool) -> IntervalMap k a -> IntervalMap k a
- Data.IntervalMap.Generic.Strict: filterWithKey :: Interval k e => (k -> a -> Bool) -> IntervalMap k a -> IntervalMap k a
+ Data.IntervalMap.Generic.Strict: filterWithKey :: (Interval k e) => (k -> a -> Bool) -> IntervalMap k a -> IntervalMap k a
- Data.IntervalMap.Generic.Strict: findLast :: Interval k e => IntervalMap k v -> (k, v)
+ Data.IntervalMap.Generic.Strict: findLast :: (Interval k e) => IntervalMap k v -> (k, v)
- Data.IntervalMap.Generic.Strict: fromDistinctAscList :: Interval k e => [(k, v)] -> IntervalMap k v
+ Data.IntervalMap.Generic.Strict: fromDistinctAscList :: (Interval k e) => [(k, v)] -> IntervalMap k v
- Data.IntervalMap.Generic.Strict: intersecting :: Interval k e => IntervalMap k v -> k -> [(k, v)]
+ Data.IntervalMap.Generic.Strict: intersecting :: (Interval k e) => IntervalMap k v -> k -> [(k, v)]
- Data.IntervalMap.Generic.Strict: keysSet :: Ord k => IntervalMap k v -> Set k
+ Data.IntervalMap.Generic.Strict: keysSet :: (Ord k) => IntervalMap k v -> Set k
- Data.IntervalMap.Generic.Strict: lookup :: Ord k => k -> IntervalMap k v -> Maybe v
+ Data.IntervalMap.Generic.Strict: lookup :: (Ord k) => k -> IntervalMap k v -> Maybe v
- Data.IntervalMap.Generic.Strict: mapEither :: Interval k e => (a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
+ Data.IntervalMap.Generic.Strict: mapEither :: (Interval k e) => (a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
- Data.IntervalMap.Generic.Strict: mapEitherWithKey :: Interval k e => (k -> a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
+ Data.IntervalMap.Generic.Strict: mapEitherWithKey :: (Interval k e) => (k -> a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
- Data.IntervalMap.Generic.Strict: mapMaybe :: Interval k e => (a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
+ Data.IntervalMap.Generic.Strict: mapMaybe :: (Interval k e) => (a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
- Data.IntervalMap.Generic.Strict: mapMaybeWithKey :: Interval k e => (k -> a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
+ Data.IntervalMap.Generic.Strict: mapMaybeWithKey :: (Interval k e) => (k -> a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
- Data.IntervalMap.Generic.Strict: member :: Ord k => k -> IntervalMap k v -> Bool
+ Data.IntervalMap.Generic.Strict: member :: (Ord k) => k -> IntervalMap k v -> Bool
- Data.IntervalMap.Generic.Strict: notMember :: Ord k => k -> IntervalMap k v -> Bool
+ Data.IntervalMap.Generic.Strict: notMember :: (Ord k) => k -> IntervalMap k v -> Bool
- Data.IntervalMap.Generic.Strict: partition :: Interval k e => (a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
+ Data.IntervalMap.Generic.Strict: partition :: (Interval k e) => (a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
- Data.IntervalMap.Generic.Strict: partitionWithKey :: Interval k e => (k -> a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
+ Data.IntervalMap.Generic.Strict: partitionWithKey :: (Interval k e) => (k -> a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
- Data.IntervalMap.Generic.Strict: within :: Interval k e => IntervalMap k v -> k -> [(k, v)]
+ Data.IntervalMap.Generic.Strict: within :: (Interval k e) => IntervalMap k v -> k -> [(k, v)]
- Data.IntervalMap.Interval: above :: Ord a => a -> Interval a -> Bool
+ Data.IntervalMap.Interval: above :: (Ord a) => a -> Interval a -> Bool
- Data.IntervalMap.Interval: below :: Ord a => a -> Interval a -> Bool
+ Data.IntervalMap.Interval: below :: (Ord a) => a -> Interval a -> Bool
- Data.IntervalMap.Interval: inside :: Ord a => a -> Interval a -> Bool
+ Data.IntervalMap.Interval: inside :: (Ord a) => a -> Interval a -> Bool
- Data.IntervalMap.Interval: isEmpty :: Ord a => Interval a -> Bool
+ Data.IntervalMap.Interval: isEmpty :: (Ord a) => Interval a -> Bool
- Data.IntervalMap.Interval: overlaps :: Ord a => Interval a -> Interval a -> Bool
+ Data.IntervalMap.Interval: overlaps :: (Ord a) => Interval a -> Interval a -> Bool
- Data.IntervalMap.Interval: subsumes :: Ord a => Interval a -> Interval a -> Bool
+ Data.IntervalMap.Interval: subsumes :: (Ord a) => Interval a -> Interval a -> Bool
- Data.IntervalMap.Lazy: containing :: Interval k e => IntervalMap k v -> e -> [(k, v)]
+ Data.IntervalMap.Lazy: containing :: (Interval k e) => IntervalMap k v -> e -> [(k, v)]
- Data.IntervalMap.Lazy: filter :: Interval k e => (a -> Bool) -> IntervalMap k a -> IntervalMap k a
+ Data.IntervalMap.Lazy: filter :: (Interval k e) => (a -> Bool) -> IntervalMap k a -> IntervalMap k a
- Data.IntervalMap.Lazy: filterWithKey :: Interval k e => (k -> a -> Bool) -> IntervalMap k a -> IntervalMap k a
+ Data.IntervalMap.Lazy: filterWithKey :: (Interval k e) => (k -> a -> Bool) -> IntervalMap k a -> IntervalMap k a
- Data.IntervalMap.Lazy: findLast :: Interval k e => IntervalMap k v -> (k, v)
+ Data.IntervalMap.Lazy: findLast :: (Interval k e) => IntervalMap k v -> (k, v)
- Data.IntervalMap.Lazy: fromDistinctAscList :: Interval k e => [(k, v)] -> IntervalMap k v
+ Data.IntervalMap.Lazy: fromDistinctAscList :: (Interval k e) => [(k, v)] -> IntervalMap k v
- Data.IntervalMap.Lazy: intersecting :: Interval k e => IntervalMap k v -> k -> [(k, v)]
+ Data.IntervalMap.Lazy: intersecting :: (Interval k e) => IntervalMap k v -> k -> [(k, v)]
- Data.IntervalMap.Lazy: keysSet :: Ord k => IntervalMap k v -> Set k
+ Data.IntervalMap.Lazy: keysSet :: (Ord k) => IntervalMap k v -> Set k
- Data.IntervalMap.Lazy: lookup :: Ord k => k -> IntervalMap k v -> Maybe v
+ Data.IntervalMap.Lazy: lookup :: (Ord k) => k -> IntervalMap k v -> Maybe v
- Data.IntervalMap.Lazy: mapEither :: Interval k e => (a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
+ Data.IntervalMap.Lazy: mapEither :: (Interval k e) => (a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
- Data.IntervalMap.Lazy: mapEitherWithKey :: Interval i k => (i -> a -> Either b c) -> IntervalMap i a -> (IntervalMap i b, IntervalMap i c)
+ Data.IntervalMap.Lazy: mapEitherWithKey :: (Interval i k) => (i -> a -> Either b c) -> IntervalMap i a -> (IntervalMap i b, IntervalMap i c)
- Data.IntervalMap.Lazy: mapMaybe :: Interval k e => (a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
+ Data.IntervalMap.Lazy: mapMaybe :: (Interval k e) => (a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
- Data.IntervalMap.Lazy: mapMaybeWithKey :: Interval k e => (k -> a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
+ Data.IntervalMap.Lazy: mapMaybeWithKey :: (Interval k e) => (k -> a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
- Data.IntervalMap.Lazy: member :: Ord k => k -> IntervalMap k v -> Bool
+ Data.IntervalMap.Lazy: member :: (Ord k) => k -> IntervalMap k v -> Bool
- Data.IntervalMap.Lazy: notMember :: Ord k => k -> IntervalMap k v -> Bool
+ Data.IntervalMap.Lazy: notMember :: (Ord k) => k -> IntervalMap k v -> Bool
- Data.IntervalMap.Lazy: partition :: Interval k e => (a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
+ Data.IntervalMap.Lazy: partition :: (Interval k e) => (a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
- Data.IntervalMap.Lazy: partitionWithKey :: Interval k e => (k -> a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
+ Data.IntervalMap.Lazy: partitionWithKey :: (Interval k e) => (k -> a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
- Data.IntervalMap.Lazy: within :: Interval k e => IntervalMap k v -> k -> [(k, v)]
+ Data.IntervalMap.Lazy: within :: (Interval k e) => IntervalMap k v -> k -> [(k, v)]
- Data.IntervalMap.Strict: containing :: Interval k e => IntervalMap k v -> e -> [(k, v)]
+ Data.IntervalMap.Strict: containing :: (Interval k e) => IntervalMap k v -> e -> [(k, v)]
- Data.IntervalMap.Strict: filterWithKey :: Interval k e => (k -> a -> Bool) -> IntervalMap k a -> IntervalMap k a
+ Data.IntervalMap.Strict: filterWithKey :: (Interval k e) => (k -> a -> Bool) -> IntervalMap k a -> IntervalMap k a
- Data.IntervalMap.Strict: findLast :: Interval k e => IntervalMap k v -> (k, v)
+ Data.IntervalMap.Strict: findLast :: (Interval k e) => IntervalMap k v -> (k, v)
- Data.IntervalMap.Strict: foldl :: (a -> b -> a) -> a -> [b] -> a
+ Data.IntervalMap.Strict: foldl :: Foldable t => forall b a. (b -> a -> b) -> b -> t a -> b
- Data.IntervalMap.Strict: foldr :: (a -> b -> b) -> b -> [a] -> b
+ Data.IntervalMap.Strict: foldr :: Foldable t => forall a b. (a -> b -> b) -> b -> t a -> b
- Data.IntervalMap.Strict: fromDistinctAscList :: Interval k e => [(k, v)] -> IntervalMap k v
+ Data.IntervalMap.Strict: fromDistinctAscList :: (Interval k e) => [(k, v)] -> IntervalMap k v
- Data.IntervalMap.Strict: intersecting :: Interval k e => IntervalMap k v -> k -> [(k, v)]
+ Data.IntervalMap.Strict: intersecting :: (Interval k e) => IntervalMap k v -> k -> [(k, v)]
- Data.IntervalMap.Strict: keysSet :: Ord k => IntervalMap k v -> Set k
+ Data.IntervalMap.Strict: keysSet :: (Ord k) => IntervalMap k v -> Set k
- Data.IntervalMap.Strict: mapEither :: Interval k e => (a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
+ Data.IntervalMap.Strict: mapEither :: (Interval k e) => (a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
- Data.IntervalMap.Strict: mapEitherWithKey :: Interval k e => (k -> a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
+ Data.IntervalMap.Strict: mapEitherWithKey :: (Interval k e) => (k -> a -> Either b c) -> IntervalMap k a -> (IntervalMap k b, IntervalMap k c)
- Data.IntervalMap.Strict: mapMaybe :: Interval k e => (a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
+ Data.IntervalMap.Strict: mapMaybe :: (Interval k e) => (a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
- Data.IntervalMap.Strict: mapMaybeWithKey :: Interval k e => (k -> a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
+ Data.IntervalMap.Strict: mapMaybeWithKey :: (Interval k e) => (k -> a -> Maybe b) -> IntervalMap k a -> IntervalMap k b
- Data.IntervalMap.Strict: member :: Ord k => k -> IntervalMap k v -> Bool
+ Data.IntervalMap.Strict: member :: (Ord k) => k -> IntervalMap k v -> Bool
- Data.IntervalMap.Strict: notMember :: Ord k => k -> IntervalMap k v -> Bool
+ Data.IntervalMap.Strict: notMember :: (Ord k) => k -> IntervalMap k v -> Bool
- Data.IntervalMap.Strict: null :: [a] -> Bool
+ Data.IntervalMap.Strict: null :: Foldable t => forall a. t a -> Bool
- Data.IntervalMap.Strict: partition :: Interval k e => (a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
+ Data.IntervalMap.Strict: partition :: (Interval k e) => (a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
- Data.IntervalMap.Strict: partitionWithKey :: Interval k e => (k -> a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
+ Data.IntervalMap.Strict: partitionWithKey :: (Interval k e) => (k -> a -> Bool) -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a)
- Data.IntervalMap.Strict: within :: Interval k e => IntervalMap k v -> k -> [(k, v)]
+ Data.IntervalMap.Strict: within :: (Interval k e) => IntervalMap k v -> k -> [(k, v)]
Files
- Data/IntervalMap/Generic/Base.hs +27/−25
- Data/IntervalMap/Generic/Interval.hs +15/−4
- Data/IntervalMap/Generic/Lazy.hs +1/−1
- Data/IntervalSet.hs +769/−0
- IntervalMap.cabal +55/−8
- LICENSE +1/−1
- README.md +3/−9
- bench/CompareRBImpl.hs +98/−0
- bench/CompareTypes.hs +196/−0
- bench/GenericLazyVsStrict.hs +1/−1
- changelog +18/−0
- examples/GenericExample.lhs +0/−3
- test/IntervalMapTests.hs +140/−128
- test/IntervalSetTests.hs +212/−0
Data/IntervalMap/Generic/Base.hs view
@@ -198,7 +198,7 @@ import qualified Data.Foldable as Foldable import qualified Data.List as L import qualified Data.Set as Set-import Control.DeepSeq (NFData(rnf))+import Control.DeepSeq import Data.IntervalMap.Generic.Interval @@ -208,6 +208,9 @@ infixl 9 !,\\ -- -- | /O(log n)/. Lookup value for given key. Calls 'error' if the key is not in the map.+--+-- Use 'lookup' or 'findWithDefault' instead of this function, unless you are absolutely+-- sure that the key is present in the map. (!) :: (Interval k e, Ord k) => IntervalMap k v -> k -> v tree ! key = case lookup key tree of Just v -> v@@ -258,7 +261,7 @@ instance (NFData k, NFData a) => NFData (IntervalMap k a) where rnf Nil = ()- rnf (Node _ kx _ x l r) = rnf kx `seq` rnf x `seq` rnf l `seq` rnf r+ rnf (Node _ kx _ x l r) = kx `deepseq` x `deepseq` l `deepseq` r `deepseq` () instance (Ord k, Read k, Read e, Interval i k, Ord i, Read i) => Read (IntervalMap i e) where readsPrec p = readParen (p > 10) $ \ r -> do@@ -366,10 +369,6 @@ -- | /O(log n)/. The expression @('findWithDefault' def k map)@ returns -- the value at key @k@ or returns default value @def@ -- when the key is not in the map.------ > findWithDefault 'x' 1 (fromList [(5,'a'), (3,'b')]) == 'x'--- > findWithDefault 'x' 5 (fromList [(5,'a'), (3,'b')]) == 'a'- findWithDefault :: Ord k => a -> k -> IntervalMap k a -> a findWithDefault def k m = case lookup k m of Nothing -> def@@ -500,19 +499,17 @@ findMax (Node _ _ _ _ _ r) = findMax r findMax Nil = error "IntervalMap.findMin: empty map" --- | Returns the interval with the largest endpoint.--- If there is more than one interval with that endpoint,--- return the rightmost.+-- | Returns the key with the largest endpoint and its associated value.+-- If there is more than one key with that endpoint, return the rightmost. -- -- /O(n)/, since all keys could have the same endpoint. -- /O(log n)/ average case. findLast :: (Interval k e) => IntervalMap k v -> (k, v) findLast Nil = error "IntervalMap.findLast: empty map"-findLast t@(Node _ _ mx _ _ _) = lastMax+findLast t@(Node _ _ mx _ _ _) = head (go t) where- (lastMax : _) = go t go Nil = []- go (Node _ k m v l r) | sameU m mx = if sameU k m then go r ++ ((k,v) : go l)+ go (Node _ k m v l r) | sameU m mx = if sameU k m then go r ++ [(k,v)] else go r ++ go l | otherwise = [] sameU a b = upperBound a == upperBound b && rightClosed a == rightClosed b@@ -824,12 +821,20 @@ -- | The union of a list of maps: -- (@'unions' == 'Prelude.foldl' 'union' 'empty'@). unions :: (Interval k e, Ord k) => [IntervalMap k a] -> IntervalMap k a-unions = L.foldl union empty+unions ms = unionsWith const ms -- | The union of a list of maps, with a combining operation: -- (@'unionsWith' f == 'Prelude.foldl' ('unionWith' f) 'empty'@). unionsWith :: (Interval k e, Ord k) => (a -> a -> a) -> [IntervalMap k a] -> IntervalMap k a-unionsWith f = L.foldl (unionWith f) empty+unionsWith _ [] = empty+unionsWith _ [m] = m+unionsWith f ms = fromDistinctAscList (head (go (L.map toAscList ms)))+ where+ f' _ l r = f l r+ merge m1 m2 = ascListUnion f' m1 m2+ go [] = []+ go xs@[_] = xs+ go (x:y:xs) = go (merge x y : go xs) -- | /O(n+m)/. Difference of two maps. -- Return elements of the first map not existing in the second map.@@ -1029,17 +1034,11 @@ -- | /O(n)/. The function 'mapAccum' threads an accumulating -- argument through the map in ascending order of keys.------ > let f a b = (a ++ b, b ++ "X")--- > mapAccum f "Everything: " (fromList [(5,"a"), (3,"b")]) == ("Everything: ba", fromList [(3, "bX"), (5, "aX")]) mapAccum :: (a -> b -> (a,c)) -> a -> IntervalMap k b -> (a, IntervalMap k c) mapAccum f a m = mapAccumWithKey (\a' _ x' -> f a' x') a m -- | /O(n)/. The function 'mapAccumWithKey' threads an accumulating -- argument through the map in ascending order of keys.------ > let f a k b = (a ++ " " ++ (show k) ++ "-" ++ b, b ++ "X")--- > mapAccumWithKey f "Everything:" (fromList [(5,"a"), (3,"b")]) == ("Everything: 3-b 5-a", fromList [(3, "bX"), (5, "aX")]) mapAccumWithKey :: (a -> k -> b -> (a,c)) -> a -> IntervalMap k b -> (a, IntervalMap k c) mapAccumWithKey f = go where@@ -1079,7 +1078,7 @@ mapKeysWith :: (Interval k2 e, Ord k2) => (a -> a -> a) -> (k1 -> k2) -> IntervalMap k1 a -> IntervalMap k2 a mapKeysWith c f m = fromListWith c [ (f k, v) | (k, v) <- toAscList m ] --- | /O(n log n)/. @'mapKeysMonotonic' f s == 'mapKeys' f s@, but works only when @f@+-- | /O(n)/. @'mapKeysMonotonic' f s == 'mapKeys' f s@, but works only when @f@ -- is strictly monotonic. -- That is, for any values @x@ and @y@, if @x@ < @y@ then @f x@ < @f y@. -- /The precondition is not checked./@@ -1149,10 +1148,13 @@ -- | /O(n)/. The expression (@'splitLookup' k map@) splits a map just -- like 'split' but also returns @'lookup' k map@. splitLookup :: (Interval i k, Ord i) => i -> IntervalMap i a -> (IntervalMap i a, Maybe a, IntervalMap i a)-splitLookup x m = (fromDistinctAscList less, lookup x m, fromDistinctAscList greater)- where- less = [e | e@(k,_) <- toAscList m, k < x]- greater = [e | e@(k,_) <- toAscList m, k > x]+splitLookup x m = case span (\(k,_) -> k < x) (toAscList m) of+ ([], []) -> (empty, Nothing, empty)+ ([], ((k,v):_)) | k == x -> (empty, Just v, deleteMin m)+ | otherwise -> (empty, Nothing, m)+ (_, []) -> (m, Nothing, empty)+ (lt, ge@((k,v):gt)) | k == x -> (fromDistinctAscList lt, Just v, fromDistinctAscList gt)+ | otherwise -> (fromDistinctAscList lt, Nothing, fromDistinctAscList ge) -- submaps
Data/IntervalMap/Generic/Interval.hs view
@@ -11,6 +11,13 @@ -- As there is no sensible default, no instances for prelude types -- are provided (E.g. you might want to have tuples as closed -- intervals in one case, and open in another).+--+-- Empty intervals, i.e. intervals where 'lowerBound >= upperBound' should be avoided+-- if possible. If you must use empty intervals, you need to provide implementations+-- for all operations, as the default implementations do not necessarily work correctly.+-- for example, the default implementation of 'inside' returns 'True' if the point+-- is equal to the lowerBound of a left-closed interval even if it is larger than+-- the upper bound. {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE FlexibleInstances #-}@@ -70,13 +77,17 @@ -- | Is a point strictly less than lower bound? below :: e -> i -> Bool- p `below` i | leftClosed i = p < lowerBound i- | otherwise = p <= lowerBound i+ p `below` i = case compare p (lowerBound i) of+ LT -> True+ EQ -> not (leftClosed i)+ GT -> False -- | Is a point strictly greater than upper bound? above :: e -> i -> Bool- p `above` i | rightClosed i = p > upperBound i- | otherwise = p >= upperBound i+ p `above` i = case compare p (upperBound i) of+ LT -> False+ EQ -> not (rightClosed i)+ GT -> True -- | Does the interval contain a given point? inside :: e -> i -> Bool
Data/IntervalMap/Generic/Lazy.hs view
@@ -1,5 +1,5 @@ {- |-Module : Data.IntervalMap.Lazy+Module : Data.IntervalMap.Generic.Lazy Copyright : (c) Christoph Breitkopf 2014 License : BSD-style Maintainer : chbreitkopf@gmail.com
+ Data/IntervalSet.hs view
@@ -0,0 +1,769 @@+-- |+-- Module : Data.IntervalSet+-- Copyright : (c) Christoph Breitkopf 2015+-- License : BSD-style+-- Maintainer : chbreitkopf@gmail.com+-- Stability : experimental+-- Portability : non-portable (MPTC with FD)+--+-- An implementation of sets of intervals. The intervals may+-- overlap, and the implementation contains efficient search functions+-- for all intervals containing a point or overlapping a given interval.+-- Closed, open, and half-open intervals can be contained in the same set.+--+-- It is an error to insert an empty interval into a set. This precondition is not+-- checked by the various construction functions.+--+-- Since many function names (but not the type name) clash with+-- /Prelude/ names, this module is usually imported @qualified@, e.g.+--+-- > import Data.IntervalSet.Strict (IntervalSet)+-- > import qualified Data.IntervalSet.Strict as IS+--+-- It offers most of the same functions as 'Data.Set', but the member type must be an+-- instance of 'Interval'. The 'findMin' and 'findMax' functions deviate from their+-- set counterparts in being total and returning a 'Maybe' value.+-- Some functions differ in asymptotic performance (for example 'size') or have not+-- been tuned for efficiency as much as their equivalents in 'Data.Set'.+--+-- In addition, there are functions specific to sets of intervals, for example to search+-- for all intervals containing a given point or contained in a given interval.+--+-- The implementation is a red-black tree augmented with the maximum upper bound+-- of all keys.+--+-- Parts of this implementation are based on code from the 'Data.Map' implementation,+-- (c) Daan Leijen 2002, (c) Andriy Palamarchuk 2008.+-- The red-black tree deletion is based on code from llrbtree by Kazu Yamamoto.+-- Of course, any errors are mine.+--+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE FlexibleContexts #-}+module Data.IntervalSet (+ -- * re-export+ Interval(..)+ -- * Set type+ , IntervalSet(..) -- instance Eq,Show,Read++ -- * Operators+ , (\\)++ -- * Query+ , null+ , size+ , member+ , notMember++ -- ** Interval query+ , containing+ , intersecting+ , within+ + -- * Construction+ , empty+ , singleton++ -- ** Insertion+ , insert+ + -- ** Delete\/Update+ , delete++ -- * Combine+ , union+ , unions+ , difference+ , intersection++ -- * Traversal+ -- ** Map+ , map+ , mapMonotonic++ -- ** Fold+ , foldr, foldl+ , foldl', foldr'++ -- * Conversion+ , elems++ -- ** Lists+ , toList+ , fromList++ -- ** Ordered lists+ , toAscList+ , toDescList+ , fromAscList+ , fromDistinctAscList++ -- * Filter+ , filter+ , partition++ , split+ , splitMember++ -- * Subset+ , isSubsetOf, isProperSubsetOf++ -- * Min\/Max+ , findMin+ , findMax+ , findLast+ , deleteMin+ , deleteMax+ , deleteFindMin+ , deleteFindMax+ , minView+ , maxView++ -- * Debugging+ , valid++ ) where++import Prelude hiding (null, lookup, map, filter, foldr, foldl)+import Data.Bits (shiftR, (.&.))+import Data.Monoid (Monoid(..))+import qualified Data.Foldable as Foldable+import qualified Data.List as L+import Control.DeepSeq+import qualified Data.Foldable as Foldable++import Data.IntervalMap.Generic.Interval++{--------------------------------------------------------------------+ Operators+--------------------------------------------------------------------}+infixl 9 \\ --++-- | Same as 'difference'.+(\\) :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k -> IntervalSet k+m1 \\ m2 = difference m1 m2+++data Color = R | B deriving (Eq)++-- | A set of intervals of type @k@.+data IntervalSet k = Nil+ | Node !Color+ !k -- key+ !k -- interval with maximum upper in tree+ !(IntervalSet k) -- left subtree+ !(IntervalSet k) -- right subtree++instance (Eq k) => Eq (IntervalSet k) where+ a == b = toAscList a == toAscList b++instance (Ord k) => Ord (IntervalSet k) where+ compare a b = compare (toAscList a) (toAscList b)++instance (Interval i k, Ord i) => Monoid (IntervalSet i) where+ mempty = empty+ mappend = union+ mconcat = unions+ +instance Foldable.Foldable IntervalSet where+ fold t = go t+ where go Nil = mempty+ go (Node _ k _ l r) = go l `mappend` (k `mappend` go r)+ foldr = foldr+ foldl = foldl+ foldMap f t = go t+ where go Nil = mempty+ go (Node _ k _ l r) = go l `mappend` (f k `mappend` go r)++instance (NFData k) => NFData (IntervalSet k) where+ rnf Nil = ()+ rnf (Node _ kx _ l r) = kx `deepseq` l `deepseq` r `deepseq` ()++instance (Ord k, Read k, Interval i k, Ord i, Read i) => Read (IntervalSet i) where+ readsPrec p = readParen (p > 10) $ \ r -> do+ ("fromList",s) <- lex r+ (xs,t) <- reads s+ return (fromList xs,t)++instance (Show k) => Show (IntervalSet k) where+ showsPrec d m = showParen (d > 10) $+ showString "fromList " . shows (toList m)+++isRed :: IntervalSet k -> Bool+isRed (Node R _ _ _ _) = True+isRed _ = False++turnBlack :: IntervalSet k -> IntervalSet k+turnBlack (Node R k m l r) = Node B k m l r+turnBlack t = t++turnRed :: IntervalSet k -> IntervalSet k+turnRed Nil = error "turnRed: Leaf"+turnRed (Node B k m l r) = Node R k m l r+turnRed t = t++-- construct node, recomputing the upper key bound.+mNode :: (Interval k e) => Color -> k -> IntervalSet k -> IntervalSet k -> IntervalSet k+mNode c k l r = Node c k (maxUpper k l r) l r++maxUpper :: (Interval i k) => i -> IntervalSet i -> IntervalSet i -> i+maxUpper k Nil Nil = k `seq` k+maxUpper k Nil (Node _ _ m _ _) = maxByUpper k m+maxUpper k (Node _ _ m _ _) Nil = maxByUpper k m+maxUpper k (Node _ _ l _ _) (Node _ _ r _ _) = maxByUpper k (maxByUpper l r)++-- interval with the greatest upper bound. The lower bound is ignored!+maxByUpper :: (Interval i e) => i -> i -> i+maxByUpper a b | rightClosed a = if upperBound a >= upperBound b then a else b+ | otherwise = if upperBound a > upperBound b then a else b++-- ---------------------------------------------------------++-- | /O(1)/. The empty set.+empty :: IntervalSet k+empty = Nil++-- | /O(1)/. A set with one entry.+singleton :: k -> IntervalSet k+singleton k = Node B k k Nil Nil+++-- | /O(1)/. Is the set empty?+null :: IntervalSet k -> Bool+null Nil = True+null _ = False++-- | /O(n)/. Number of keys in the set.+--+-- Caution: unlike 'Data.Set.size', this takes linear time!+size :: IntervalSet k -> Int+size t = h 0 t+ where+ h n s = n `seq` case s of+ Nil -> n+ Node _ _ _ l r -> h (h n l + 1) r++-- | /O(log n)/. Does the set contain the given value? See also 'notMember'.+member :: (Ord k) => k -> IntervalSet k -> Bool+member k Nil = k `seq` False+member k (Node _ key _ l r) = case compare k key of+ LT -> member k l+ GT -> member k r+ EQ -> True++-- | /O(log n)/. Does the set not contain the given value? See also 'member'.+notMember :: (Ord k) => k -> IntervalSet k -> Bool+notMember key tree = not (member key tree)++-- | Return the set of all intervals containing the given point.+--+-- /O(n)/, since potentially all intervals could contain the point.+-- /O(log n)/ average case. This is also the worst case for sets containing no overlapping intervals.+containing :: (Interval k e) => IntervalSet k -> e -> IntervalSet k+t `containing` pt = fromDistinctAscList (go [] pt t)+ where+ go xs p Nil = p `seq` xs+ go xs p (Node _ k m l r)+ | p `above` m = xs -- above all intervals in the tree: no result+ | p `below` k = go xs p l -- to the left of the lower bound: can't be in right subtree+ | p `inside` k = go (k : go xs p r) p l+ | otherwise = go (go xs p r) p l++-- | Return the set of all intervals overlapping (intersecting) the given interval.+--+-- /O(n)/, since potentially all values could intersect the interval.+-- /O(log n)/ average case, if few values intersect the interval.+intersecting :: (Interval k e) => IntervalSet k -> k -> IntervalSet k+t `intersecting` iv = fromDistinctAscList (go [] iv t)+ where+ go xs i Nil = i `seq` xs+ go xs i (Node _ k m l r)+ | i `after` m = xs+ | i `before` k = go xs i l+ | i `overlaps` k = go (k : go xs i r) i l+ | otherwise = go (go xs i r) i l++-- | Return the set of all intervals which are completely inside the given interval.+--+-- /O(n)/, since potentially all values could be inside the interval.+-- /O(log n)/ average case, if few keys are inside the interval.+within :: (Interval k e) => IntervalSet k -> k -> IntervalSet k+t `within` iv = fromDistinctAscList (go [] iv t)+ where+ go xs i Nil = i `seq` xs+ go xs i (Node _ k m l r)+ | i `after` m = xs+ | i `before` k = go xs i l+ | i `subsumes` k = go (k : go xs i r) i l+ | otherwise = go (go xs i r) i l+++-- | /O(log n)/. Insert a new value. If the set already contains an element equal to the value,+-- it is replaced by the new value.+insert :: (Interval k e, Ord k) => k -> IntervalSet k -> IntervalSet k+insert v s = v `seq` turnBlack (ins s)+ where+ singletonR k = Node R k k Nil Nil+ ins Nil = singletonR v+ ins (Node color k m l r) =+ case compare v k of+ LT -> balanceL color k (ins l) r+ GT -> balanceR color k l (ins r)+ EQ -> Node color v m l r++balanceL :: (Interval k e) => Color -> k -> IntervalSet k -> IntervalSet k -> IntervalSet k+balanceL B zk (Node R yk _ (Node R xk _ a b) c) d =+ mNode R yk (mNode B xk a b) (mNode B zk c d)+balanceL B zk (Node R xk _ a (Node R yk _ b c)) d =+ mNode R yk (mNode B xk a b) (mNode B zk c d)+balanceL c xk l r = mNode c xk l r++balanceR :: (Interval k e) => Color -> k -> IntervalSet k -> IntervalSet k -> IntervalSet k+balanceR B xk a (Node R yk _ b (Node R zk _ c d)) =+ mNode R yk (mNode B xk a b) (mNode B zk c d)+balanceR B xk a (Node R zk _ (Node R yk _ b c) d) =+ mNode R yk (mNode B xk a b) (mNode B zk c d)+balanceR c xk l r = mNode c xk l r+++-- min/max++-- | /O(log n)/. Returns the least interval in the set.+findMin :: IntervalSet k -> Maybe k+findMin (Node _ k _ Nil _) = Just k+findMin (Node _ _ _ l _) = findMin l+findMin Nil = Nothing++-- | /O(log n)/. Returns the largest interval in the set.+findMax :: IntervalSet k -> Maybe k+findMax (Node _ k _ _ Nil) = Just k+findMax (Node _ _ _ _ r) = findMax r+findMax Nil = Nothing++-- | Returns the interval with the largest endpoint.+-- If there is more than one interval with that endpoint,+-- return the rightmost.+--+-- /O(n)/, since all intervals could have the same endpoint.+-- /O(log n)/ average case.+findLast :: (Interval k e) => IntervalSet k -> Maybe k+findLast Nil = Nothing+findLast t@(Node _ _ mx _ _) = go t+ where+ go (Node _ k m l r) | sameU m mx = if sameU k m then go r `or` Just k+ else go r `or` go l+ | otherwise = Nothing+ go Nil = Nothing+ sameU a b = upperBound a == upperBound b && rightClosed a == rightClosed b+ Nothing `or` x = x+ x `or` _ = x+++-- Type to indicate whether the number of black nodes changed or stayed the same.+data DeleteResult k = U !(IntervalSet k) -- Unchanged+ | S !(IntervalSet k) -- Shrunk++unwrap :: DeleteResult k -> IntervalSet k+unwrap (U m) = m+unwrap (S m) = m++-- DeleteResult with value+data DeleteResult' k a = U' !(IntervalSet k) a+ | S' !(IntervalSet k) a++unwrap' :: DeleteResult' k a -> IntervalSet k+unwrap' (U' m _) = m+unwrap' (S' m _) = m++-- annotate DeleteResult with value+annotate :: DeleteResult k -> a -> DeleteResult' k a+annotate (U m) x = U' m x+annotate (S m) x = S' m x+++-- | /O(log n)/. Remove the smallest element from the set. Return the empty set if the set is empty.+deleteMin :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k+deleteMin Nil = Nil+deleteMin m = turnBlack (unwrap' (deleteMin' m))++deleteMin' :: (Interval k e, Ord k) => IntervalSet k -> DeleteResult' k k+deleteMin' Nil = error "deleteMin': Nil"+deleteMin' (Node B k _ Nil Nil) = S' Nil k+deleteMin' (Node B k _ Nil r@(Node R _ _ _ _)) = U' (turnBlack r) k+deleteMin' (Node R k _ Nil r) = U' r k+deleteMin' (Node c k _ l r) =+ case deleteMin' l of+ (U' l' kv) -> U' (mNode c k l' r) kv+ (S' l' kv) -> annotate (unbalancedR c k l' r) kv++deleteMax' :: (Interval k e, Ord k) => IntervalSet k -> DeleteResult' k k+deleteMax' Nil = error "deleteMax': Nil"+deleteMax' (Node B k _ Nil Nil) = S' Nil k+deleteMax' (Node B k _ l@(Node R _ _ _ _) Nil) = U' (turnBlack l) k+deleteMax' (Node R k _ l Nil) = U' l k+deleteMax' (Node c k _ l r) =+ case deleteMax' r of+ (U' r' kv) -> U' (mNode c k l r') kv+ (S' r' kv) -> annotate (unbalancedL c k l r') kv++-- The left tree lacks one Black node+unbalancedR :: (Interval k e, Ord k) => Color -> k -> IntervalSet k -> IntervalSet k -> DeleteResult k+-- Decreasing one Black node in the right+unbalancedR B k l r@(Node B _ _ _ _) = S (balanceR B k l (turnRed r))+unbalancedR R k l r@(Node B _ _ _ _) = U (balanceR B k l (turnRed r))+-- Taking one Red node from the right and adding it to the right as Black+unbalancedR B k l (Node R rk _ rl@(Node B _ _ _ _) rr)+ = U (mNode B rk (balanceR B k l (turnRed rl)) rr)+unbalancedR _ _ _ _ = error "unbalancedR"++unbalancedL :: (Interval k e, Ord k) => Color -> k -> IntervalSet k -> IntervalSet k -> DeleteResult k+unbalancedL R k l@(Node B _ _ _ _) r = U (balanceL B k (turnRed l) r)+unbalancedL B k l@(Node B _ _ _ _) r = S (balanceL B k (turnRed l) r)+unbalancedL B k (Node R lk _ ll lr@(Node B _ _ _ _)) r+ = U (mNode B lk ll (balanceL B k (turnRed lr) r))+unbalancedL _ _ _ _ = error "unbalancedL"+++-- | /O(log n)/. Remove the largest element from the set. Return the empty set if the set is empty.+deleteMax :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k+deleteMax Nil = Nil+deleteMax m = turnBlack (unwrap' (deleteMax' m))++-- | /O(log n)/. Delete and return the smallest element.+deleteFindMin :: (Interval k e, Ord k) => IntervalSet k -> (k, IntervalSet k)+deleteFindMin mp = case deleteMin' mp of+ (U' r v) -> (v, turnBlack r)+ (S' r v) -> (v, turnBlack r)++-- | /O(log n)/. Delete and return the largest element.+deleteFindMax :: (Interval k e, Ord k) => IntervalSet k -> (k, IntervalSet k)+deleteFindMax mp = case deleteMax' mp of+ (U' r v) -> (v, turnBlack r)+ (S' r v) -> (v, turnBlack r)++-- | /O(log n)/. Retrieves the minimal element of the set, and+-- the set stripped of that element, or 'Nothing' if passed an empty set.+minView :: (Interval k e, Ord k) => IntervalSet k -> Maybe (k, IntervalSet k)+minView Nil = Nothing+minView x = Just (deleteFindMin x)++-- | /O(log n)/. Retrieves the maximal element of the set, and+-- the set stripped of that element, or 'Nothing' if passed an empty set.+maxView :: (Interval k e, Ord k) => IntervalSet k -> Maybe (k, IntervalSet k)+maxView Nil = Nothing+maxView x = Just (deleteFindMax x)+++-- folding++-- | /O(n)/. Fold the values in the set using the given right-associative+-- binary operator, such that @'foldr' f z == 'Prelude.foldr' f z . 'elems'@.+foldr :: (k -> b -> b) -> b -> IntervalSet k -> b+foldr _ z Nil = z+foldr f z (Node _ k _ l r) = foldr f (f k (foldr f z r)) l++-- | /O(n)/. A strict version of 'foldr'. Each application of the operator is+-- evaluated before using the result in the next application. This+-- function is strict in the starting value.+foldr' :: (k -> b -> b) -> b -> IntervalSet k -> b+foldr' f z s = z `seq` case s of+ Nil -> z+ Node _ k _ l r -> foldr' f (f k (foldr' f z r)) l++-- | /O(n)/. Fold the values in the set using the given left-associative+-- binary operator, such that @'foldl' f z == 'Prelude.foldl' f z . 'elems'@.+foldl :: (b -> k -> b) -> b -> IntervalSet k -> b+foldl _ z Nil = z+foldl f z (Node _ k _ l r) = foldl f (f (foldl f z l) k) r++-- | /O(n)/. A strict version of 'foldl'. Each application of the operator is+-- evaluated before using the result in the next application. This+-- function is strict in the starting value.+foldl' :: (b -> k -> b) -> b -> IntervalSet k -> b+foldl' f z s = z `seq` case s of+ Nil -> z+ Node _ k _ l r -> foldl' f (f (foldl' f z l) k) r++-- delete++-- | /O(log n)/. Delete an element from the set. If the set does not contain the value,+-- it is returned unchanged.+delete :: (Interval k e, Ord k) => k -> IntervalSet k -> IntervalSet k+delete key mp = turnBlack (unwrap (delete' key mp))++delete' :: (Interval k e, Ord k) => k -> IntervalSet k -> DeleteResult k+delete' x Nil = x `seq` U Nil+delete' x (Node c k _ l r) =+ case compare x k of+ LT -> case delete' x l of+ (U l') -> U (mNode c k l' r)+ (S l') -> unbalancedR c k l' r+ GT -> case delete' x r of+ (U r') -> U (mNode c k l r')+ (S r') -> unbalancedL c k l r'+ EQ -> case r of+ Nil -> if c == B then blackify l else U l+ _ -> case deleteMin' r of+ (U' r' rk) -> U (mNode c rk l r')+ (S' r' rk) -> unbalancedL c rk l r'++blackify :: IntervalSet k -> DeleteResult k+blackify (Node R k m l r) = U (Node B k m l r)+blackify s = S s+++-- | /O(n+m)/. The expression (@'union' t1 t2@) takes the left-biased union of @t1@ and @t2@. +-- It prefers @t1@ when duplicate elements are encountered.+union :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k -> IntervalSet k+union m1 m2 = fromDistinctAscList (ascListUnion (toAscList m1) (toAscList m2))++-- | The union of a list of sets:+-- (@'unions' == 'Prelude.foldl' 'union' 'empty'@).+unions :: (Interval k e, Ord k) => [IntervalSet k] -> IntervalSet k+unions [] = empty+unions [s] = s+unions iss = fromDistinctAscList (head (go (L.map toAscList iss)))+ where+ go [] = []+ go xs@[_] = xs+ go (x:y:xs) = go (ascListUnion x y : go xs)++-- | /O(n+m)/. Difference of two sets.+-- Return elements of the first set not existing in the second set.+difference :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k -> IntervalSet k+difference m1 m2 = fromDistinctAscList (ascListDifference (toAscList m1) (toAscList m2))++-- | /O(n+m)/. Intersection of two sets.+-- Return elements in the first set also existing in the second set.+intersection :: (Interval k e, Ord k) => IntervalSet k -> IntervalSet k -> IntervalSet k+intersection m1 m2 = fromDistinctAscList (ascListIntersection (toAscList m1) (toAscList m2))++ascListUnion :: Ord k => [k] -> [k] -> [k]+ascListUnion [] [] = []+ascListUnion [] ys = ys+ascListUnion xs [] = xs+ascListUnion xs@(x:xs') ys@(y:ys') =+ case compare x y of+ LT -> x : ascListUnion xs' ys+ GT -> y : ascListUnion xs ys'+ EQ -> x : ascListUnion xs' ys'++ascListDifference :: Ord k => [k] -> [k] -> [k]+ascListDifference [] _ = []+ascListDifference xs [] = xs+ascListDifference xs@(xk:xs') ys@(yk:ys') =+ case compare xk yk of+ LT -> xk : ascListDifference xs' ys+ GT -> ascListDifference xs ys'+ EQ -> ascListDifference xs' ys'++ascListIntersection :: Ord k => [k] -> [k] -> [k]+ascListIntersection [] _ = []+ascListIntersection _ [] = []+ascListIntersection xs@(xk:xs') ys@(yk:ys') =+ case compare xk yk of+ LT -> ascListIntersection xs' ys+ GT -> ascListIntersection xs ys'+ EQ -> xk : ascListIntersection xs' ys'+++-- --- Conversion ---++-- | /O(n)/. The list of all values contained in the set, in ascending order.+toAscList :: IntervalSet k -> [k]+toAscList m = foldr (\k r -> k : r) [] m++-- | /O(n)/. The list of all values in the set, in no particular order.+toList :: IntervalSet k -> [k]+toList s = go s []+ where+ go Nil xs = xs+ go (Node _ k _ l r) xs = k : go l (go r xs)++-- | /O(n)/. The list of all values in the set, in descending order.+toDescList :: IntervalSet k -> [k]+toDescList m = foldl (\r k -> k : r) [] m++-- | /O(n log n)/. Build a set from a list of elements. See also 'fromAscList'.+-- If the list contains duplicate values, the last value is retained.+fromList :: (Interval k e, Ord k) => [k] -> IntervalSet k+fromList xs = L.foldl' (\m k -> insert k m) empty xs++-- | /O(n)/. Build a set from an ascending list in linear time.+-- /The precondition (input list is ascending) is not checked./+fromAscList :: (Interval k e, Eq k) => [k] -> IntervalSet k+fromAscList xs = fromDistinctAscList (uniq xs)++uniq :: Eq k => [k] -> [k]+uniq [] = []+uniq (x:xs) = go x xs+ where+ go v [] = [v]+ go v (y:ys) | v == y = go v ys+ | otherwise = v : go y ys+ +-- Strict tuple+data T2 a b = T2 !a !b+++-- | /O(n)/. Build a set from an ascending list of distinct elements in linear time.+-- /The precondition is not checked./+fromDistinctAscList :: (Interval k e) => [k] -> IntervalSet k+-- exactly 2^n-1 items have height n. They can be all black+-- from 2^n - 2^n-2 items have height n+1. The lowest "row" should be red.+fromDistinctAscList lyst = case h (length lyst) lyst of+ (T2 result []) -> result+ _ -> error "fromDistinctAscList: list not fully consumed"+ where+ h n xs | n == 0 = T2 Nil xs+ | isPerfect n = buildB n xs+ | otherwise = buildR n (log2 n) xs++ buildB n xs | xs `seq` n <= 0 = error "fromDictinctAscList: buildB 0"+ | n == 1 = case xs of (k:xs') -> T2 (Node B k k Nil Nil) xs'+ _ -> error "fromDictinctAscList: buildB 1"+ | otherwise =+ case n `quot` 2 of { n' ->+ case buildB n' xs of { (T2 _ []) -> error "fromDictinctAscList: buildB n";+ (T2 l (k:xs')) ->+ case buildB n' xs' of { (T2 r xs'') ->+ T2 (mNode B k l r) xs'' }}}++ buildR n d xs | d `seq` xs `seq` n == 0 = T2 Nil xs+ | n == 1 = case xs of (k:xs') -> T2 (Node (if d==0 then R else B) k k Nil Nil) xs'+ _ -> error "fromDistinctAscList: buildR 1"+ | otherwise =+ case n `quot` 2 of { n' ->+ case buildR n' (d-1) xs of { (T2 _ []) -> error "fromDistinctAscList: buildR n";+ (T2 l (k:xs')) ->+ case buildR (n - (n' + 1)) (d-1) xs' of { (T2 r xs'') ->+ T2 (mNode B k l r) xs'' }}}+++-- is n a perfect binary tree size (2^m-1)?+isPerfect :: Int -> Bool+isPerfect n = (n .&. (n + 1)) == 0++log2 :: Int -> Int+log2 m = h (-1) m+ where+ h r n | r `seq` n <= 0 = r+ | otherwise = h (r + 1) (n `shiftR` 1)+++-- | /O(n)/. List of all values in the set, in ascending order.+elems :: IntervalSet k -> [k]+elems s = toAscList s++-- --- Mapping ---++-- | /O(n log n)/. Map a function over all values in the set.+--+-- The size of the result may be smaller if @f@ maps two or more distinct+-- elements to the same value.+map :: (Interval a e1, Interval b e2, Ord b) => (a -> b) -> IntervalSet a -> IntervalSet b+map f s = fromList [f x | x <- toList s]++-- | /O(n)/. @'mapMonotonic' f s == 'map' f s@, but works only when @f@+-- is strictly monotonic.+-- That is, for any values @x@ and @y@, if @x@ < @y@ then @f x@ < @f y@.+-- /The precondition is not checked./+mapMonotonic :: (Interval k2 e, Ord k2) => (k1 -> k2) -> IntervalSet k1 -> IntervalSet k2+mapMonotonic _ Nil = Nil+mapMonotonic f (Node c k _ l r) =+ mNode c (f k) (mapMonotonic f l) (mapMonotonic f r)++-- | /O(n)/. Filter values satisfying a predicate.+filter :: (Interval k e) => (k -> Bool) -> IntervalSet k -> IntervalSet k+filter p s = fromDistinctAscList (L.filter p (toAscList s))++-- | /O(n)/. Partition the set according to a predicate. The first+-- set contains all elements that satisfy the predicate, the second all+-- elements that fail the predicate. See also 'split'.+partition :: (Interval k e) => (k -> Bool) -> IntervalSet k -> (IntervalSet k, IntervalSet k)+partition p s = let (xs,ys) = L.partition p (toAscList s)+ in (fromDistinctAscList xs, fromDistinctAscList ys)++-- | /O(n)/. The expression (@'split' k set@) is a pair @(set1,set2)@ where+-- the elements in @set1@ are smaller than @k@ and the elements in @set2@ larger than @k@.+-- Any key equal to @k@ is found in neither @set1@ nor @set2@.+split :: (Interval i k, Ord i) => i -> IntervalSet i -> (IntervalSet i, IntervalSet i)+split x m = (l, r)+ where (l, _, r) = splitMember x m+ +-- | /O(n)/. The expression (@'splitMember' k set@) splits a set just+-- like 'split' but also returns @'member' k set@.+splitMember :: (Interval i k, Ord i) => i -> IntervalSet i -> (IntervalSet i, Bool, IntervalSet i)+splitMember x s = case span (< x) (toAscList s) of+ ([], []) -> (empty, False, empty)+ ([], (y:_)) | y == x -> (empty, True, deleteMin s)+ | otherwise -> (empty, False, s)+ (_, []) -> (s, False, empty)+ (lt, ge@(y:gt)) | y == x -> (fromDistinctAscList lt, True, fromDistinctAscList gt)+ | otherwise -> (fromDistinctAscList lt, False, fromDistinctAscList ge)++-- subsets++-- | /O(n+m)/.+isSubsetOf :: (Ord k) => IntervalSet k -> IntervalSet k -> Bool+isSubsetOf m1 m2 = go (toAscList m1) (toAscList m2)+ where+ go [] _ = True+ go (_:_) [] = False+ go s1@(k1:r1) (k2:r2) =+ case compare k1 k2 of+ GT -> go s1 r2+ EQ -> go r1 r2+ LT -> False++-- | /O(n+m)/. Is this a proper subset? (ie. a subset but not equal). +isProperSubsetOf :: (Ord k) => IntervalSet k -> IntervalSet k -> Bool+isProperSubsetOf m1 m2 = size m1 < size m2 && isSubsetOf m1 m2++-- debugging+++-- | The height of the tree. For testing/debugging only.+height :: IntervalSet k -> Int+height Nil = 0+height (Node _ _ _ l r) = 1 + max (height l) (height r)++-- | The maximum height of a red-black tree with the given number of nodes.+-- For testing/debugging only.+maxHeight :: Int -> Int+maxHeight nodes = 2 * log2 (nodes + 1)+++-- | Check red-black-tree and interval search augmentation invariants.+-- For testing/debugging only.+valid :: (Interval i k, Ord i) => IntervalSet i -> Bool+valid mp = test mp && height mp <= maxHeight (size mp) && validColor mp+ where+ test Nil = True+ test n@(Node _ _ _ l r) = validOrder n && validMax n && test l && test r+ validMax (Node _ k m lo hi) = m == maxUpper k lo hi+ validMax Nil = True++ validOrder (Node _ _ _ Nil Nil) = True+ validOrder (Node _ k1 _ Nil (Node _ k2 _ _ _)) = k1 < k2+ validOrder (Node _ k2 _ (Node _ k1 _ _ _) Nil) = k1 < k2+ validOrder (Node _ k2 _ (Node _ k1 _ _ _) (Node _ k3 _ _ _)) = k1 < k2 && k2 < k3+ validOrder Nil = True++ -- validColor parentColor blackCount tree+ validColor n = blackDepth n >= 0++ -- return -1 if subtrees have diffrent black depths or two consecutive red nodes are encountered+ blackDepth :: IntervalSet k -> Int+ blackDepth Nil = 0+ blackDepth (Node c _ _ l r) = case blackDepth l of+ ld -> if ld < 0 then ld+ else+ case blackDepth r of+ rd -> if rd < 0 then rd+ else if rd /= ld then -1+ else if c == R && (isRed l || isRed r) then -1+ else if c == B then rd + 1+ else rd+
IntervalMap.cabal view
@@ -1,5 +1,5 @@ Name: IntervalMap-Version: 0.4.0.1+Version: 0.4.1.0 Stability: experimental Synopsis: Maps from Intervals to values, with efficient search. Homepage: http://www.chr-breitkopf.de/comp/IntervalMap@@ -8,27 +8,33 @@ Author: Christoph Breitkopf Maintainer: Christoph Breitkopf <chbreitkopf@gmail.com> bug-reports: mailto:chbreitkopf@gmail.com-Copyright: 2011-2014 Christoph Breitkopf+Copyright: 2011-2015 Christoph Breitkopf Category: Data Build-type: Simple Cabal-version: >= 1.8-Tested-With: GHC==7.8.3+Tested-With: GHC ==7.4.2, GHC ==7.6.3, GHC ==7.8.4, GHC ==7.10.2 Description:- A map from intervals to values, with efficient search+ Ordered containers of intervals, with efficient search for all keys containing a point or overlapping an interval. See the example code on the home page for a quick introduction. extra-source-files: README.md+ changelog test/*.hs examples/*.lhs +Flag HPC+ Description: Enable HPC test coverage support+ Default: False+ Library Exposed-modules: Data.IntervalMap, Data.IntervalMap.Lazy, Data.IntervalMap.Strict, Data.IntervalMap.Interval, Data.IntervalMap.Generic.Interval, Data.IntervalMap.Generic.Lazy,- Data.IntervalMap.Generic.Strict+ Data.IntervalMap.Generic.Strict,+ Data.IntervalSet other-modules: Data.IntervalMap.Generic.Base Build-depends: base >= 4 && < 5, containers, deepseq ghc-options: -Wall@@ -41,7 +47,11 @@ hs-source-dirs: . test build-depends: base >= 4 && < 5, containers, deepseq, QuickCheck, Cabal >= 1.9.2-+ if flag(HPC)+ ghc-options: -with-rtsopts=-K1K -fhpc+ else+ ghc-options: -with-rtsopts=-K1K+ Test-Suite TestGenericInterval type: exitcode-stdio-1.0@@ -49,6 +59,10 @@ hs-source-dirs: . test build-depends: base >= 4 && < 5, containers, deepseq, QuickCheck, Cabal >= 1.9.2+ if flag(HPC)+ ghc-options: -with-rtsopts=-K1K -fhpc+ else+ ghc-options: -with-rtsopts=-K1K Test-Suite TestIntervalMap type: exitcode-stdio-1.0@@ -56,7 +70,22 @@ hs-source-dirs: . test build-depends: base >= 4 && < 5, containers, deepseq, QuickCheck, Cabal >= 1.9.2+ if flag(HPC)+ ghc-options: -with-rtsopts=-K1K -fhpc+ else+ ghc-options: -with-rtsopts=-K1K +Test-Suite TestIntervalSet+ type: exitcode-stdio-1.0+ main-is: IntervalSetTests.hs+ hs-source-dirs: . test+ build-depends: base >= 4 && < 5, containers, deepseq,+ QuickCheck, Cabal >= 1.9.2+ if flag(HPC)+ ghc-options: -with-rtsopts=-K1K -fhpc+ else+ ghc-options: -with-rtsopts=-K1K+ benchmark bench-all type: exitcode-stdio-1.0 hs-source-dirs: . bench@@ -73,8 +102,26 @@ Build-depends: base >= 4 && < 5, containers, random, deepseq, criterion >= 1.0+ ghc-options: -Wall -with-rtsopts=-K1K++benchmark bench-compare-types+ type: exitcode-stdio-1.0+ hs-source-dirs: . bench+ main-is: CompareTypes.hs+ Build-depends: base >= 4 && < 5,+ containers, random, deepseq, fingertree >= 0.1, SegmentTree,+ criterion >= 1.0 ghc-options: -Wall +benchmark bench-rb-impl+ type: exitcode-stdio-1.0+ hs-source-dirs: . bench+ main-is: CompareRBImpl.hs+ Build-depends: base >= 4 && < 5,+ containers, random, deepseq,+ criterion >= 1.0+ ghc-options: -Wall -with-rtsopts=-K1K+ source-repository head- type: darcs- location: http://hub.darcs.net/bokesan/IntervalMap+ type: git+ location: https://github.com/bokesan/IntervalMap
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2011-2014, Christoph Breitkopf+Copyright (c) 2011-2015, Christoph Breitkopf All rights reserved.
README.md view
@@ -1,20 +1,14 @@-# IntervalMap+# IntervalMap [](https://travis-ci.org/bokesan/IntervalMap) -Maps with intervals as keys offering efficient search.+Containers for intervals offering efficient search. Home page and documentation: [http://www.chr-breitkopf.de/comp/IntervalMap/index.html](http://www.chr-breitkopf.de/comp/IntervalMap/index.html) Install from hackage with cabal install. -To run the tests, do extract the archive, and do+To run the tests, extract the archive, and do $ cabal configure --enable-tests $ cabal build $ cabal test-----------Christoph Breitkopf <chbreitkopf@gmail.com>--Last edit: 2014-07-30
+ bench/CompareRBImpl.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++import Criterion.Main+import Criterion.Types (Config(..))++import Control.DeepSeq+import Prelude hiding (lookup, max, foldr)+import System.Random+import Data.List (sort)++import Data.IntervalMap.Generic.Interval+import qualified Data.IntervalMap.Generic.Strict as S+import qualified RBColorInt as L+import qualified RBColorNode as N++seed :: Int+seed = 54321++ensure :: NFData a => a -> IO a+ensure xs = xs `deepseq` return xs++forceRange :: Int -> Int -> Int -> Int+forceRange lo hi n | n >= lo && n <= hi = n+ | n < 0 = forceRange lo hi (0 - n)+ | otherwise = lo + (n `rem` (1 + hi - lo))++genRandomInts :: Int -> Int -> Int -> [Int]+genRandomInts lo hi n = Prelude.map (forceRange lo hi) . take n . randoms . mkStdGen $ seed++genRandomIntervals :: Int -> Int -> Int -> [(Int,Int)]+genRandomIntervals max lap n = genIvs . take (2*n) . randoms . mkStdGen $ seed+ where+ genIvs [] = []+ genIvs [_] = []+ genIvs (x:y:xs) = let lo = forceRange 1 max x+ sz = forceRange 0 lap y+ in (lo, lo + sz) : genIvs xs+++benchConfig :: Config+benchConfig = defaultConfig { reportFile = Just "bench-rb-impl.html" }++cDATA_SIZE :: Int+cDATA_SIZE = 500000++cTEST_SIZE :: Int+cTEST_SIZE = 25000++data IV = IV {-# UNPACK #-} !Int {-# UNPACK #-} !Int+ deriving (Eq, Ord)++instance NFData IV where+ rnf a = a `seq` ()++instance Interval IV Int where+ lowerBound (IV l _) = l+ upperBound (IV _ u) = u+++main :: IO ()+main =+ do+ let ivs = genRandomIntervals cDATA_SIZE 20 cDATA_SIZE+ ivsP <- ensure $ [(IV lo hi, lo) | (lo,hi) <- ivs]+ oIvsP <- ensure $ sort ivsP+ lookupKeys <- ensure $ take cTEST_SIZE [i | (i,_) <- ivsP]+ sMap <- ensure $ S.fromAscList oIvsP+ lMap <- ensure $ L.fromAscList oIvsP+ nMap <- ensure $ N.fromAscList oIvsP+ rndInts <- ensure (genRandomInts 1 cDATA_SIZE cTEST_SIZE)+ defaultMainWith benchConfig [+ bgroup "fromAscList" [+ bench "regular" $ nf S.fromAscList oIvsP,+ bench "int" $ nf L.fromAscList oIvsP,+ bench "node" $ nf N.fromAscList oIvsP+ ],+ bgroup "lookup" [+ bench "reg" $ nf (\m -> [S.lookup i m | i <- lookupKeys]) sMap,+ bench "int" $ nf (\m -> [L.lookup i m | i <- lookupKeys]) lMap,+ bench "node" $ nf (\m -> [N.lookup i m | i <- lookupKeys]) nMap+ ],+ bgroup "containing" [+ bench "reg" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `S.containing` p]) sMap,+ bench "int" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `L.containing` p]) lMap,+ bench "node" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `N.containing` p]) nMap+ ],+ bgroup "intersecting" [+ bench "reg" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `S.intersecting` (IV p (p+15))]) sMap,+ bench "int" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `L.intersecting` (IV p (p+15))]) lMap,+ bench "node" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `N.intersecting` (IV p (p+15))]) nMap+ ],+ bgroup "within" [+ bench "reg" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `S.within` (IV p (p+15))]) sMap,+ bench "int" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `L.within` (IV p (p+15))]) lMap,+ bench "node" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `N.within` (IV p (p+15))]) nMap+ ]+ ]
+ bench/CompareTypes.hs view
@@ -0,0 +1,196 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++import Criterion.Main+import Criterion.Types (Config(..), Verbosity(..))++import Control.DeepSeq+import Prelude hiding (lookup, max, foldr)+import System.Random+import Data.List (nub)+import Data.Foldable (foldr)+import Data.Maybe++import IntRange+import qualified Data.IntervalMap.Generic.Strict as RB+import qualified IvMapSortedList as SL+import qualified Data.IntervalMap.FingerTree as FT+import qualified Data.SegmentTree as ST+++instance Ord a => Interval (FT.Interval a) a where+ lowerBound = FT.low+ upperBound = FT.high++instance Ord a => Interval (ST.Interval a) a where+ lowerBound (ST.Interval _ (ST.R a) _ _) = a+ lowerBound _ = error "interval lower"+ upperBound (ST.Interval _ _ (ST.R a) _) = a+ upperBound _ = error "interval upper"+++instance NFData a => NFData (FT.Interval a) where+ rnf (FT.Interval a b) = a `deepseq` b `deepseq` ()++instance NFData a => NFData (ST.Interval a) where+ rnf (ST.Interval _ (ST.R a) (ST.R b) _) = a `deepseq` b `deepseq` ()+ rnf a = a `seq` ()++instance (NFData k, NFData v) => NFData (FT.IntervalMap k v) where+ -- FIXME+ rnf a = a `seq` ()++instance NFData v => NFData (ST.STree v Int) where+ rnf (ST.Leaf a b) = a `deepseq` b `deepseq`()+ rnf (ST.Branch a b c d) = a `deepseq` b `deepseq` c `deepseq` d `deepseq` ()++ftFromList :: Ord k => [(FT.Interval k, v)] -> FT.IntervalMap k v+ftFromList = foldr (\(k,v) m -> FT.insert k v m) FT.empty++stFromList :: [(Int,Int)] -> ST.STree [ST.Interval Int] Int+stFromList = ST.fromList++stLoBound :: ST.Interval Int -> Int+stLoBound (ST.Interval{ST.low=(ST.R v)}) = v+stLoBound _ = error "stLoBound"++cSEED, cSEED2 :: Int+cSEED = 54321+cSEED2 = 12345++forceRange :: Int -> Int -> Int -> Int+forceRange lo hi n | n >= lo && n <= hi = n+ | n < 0 = forceRange lo hi (0 - n)+ | otherwise = lo + (n `rem` (1 + hi - lo))++genRandomIntervals :: Int -> Int -> Int -> [IntRange]+genRandomIntervals = genRandomIntervalsWithSeed cSEED++genRandomIntervalsWithSeed :: Int -> Int -> Int -> Int -> [IntRange]+genRandomIntervalsWithSeed seed max lap n = genIvs . take (2*n) . randoms . mkStdGen $ seed+ where+ genIvs [] = []+ genIvs [_] = []+ genIvs (x:y:xs) = let lo = forceRange 1 max x+ sz = forceRange 0 lap y+ in IntRange lo (lo + sz) : genIvs xs+++benchConfig :: Config+benchConfig = defaultConfig { reportFile = Just "bench-compare-types.html", verbosity = Verbose }++cNUM_KEYS :: Int+cNUM_KEYS = 10++mkKeys :: Int -> [IntRange]+mkKeys n = genRandomIntervalsWithSeed cSEED2 n 18 cNUM_KEYS ++ [IntRange 0 1, IntRange (n+1) (n+2)]++slEnv :: Int -> IO ([IntRange], SL.IVS IntRange Int)+slEnv n = do+ let ivs = genRandomIntervals n 20 n+ return (mkKeys n, SL.fromList [(iv, lowerBound iv) | iv <- ivs])++rbEnv :: Int -> IO ([IntRange], RB.IntervalMap IntRange Int)+rbEnv n = do+ let ivs = genRandomIntervals n 20 n+ return (mkKeys n, RB.fromList [(iv, lowerBound iv) | iv <- ivs])++ftEnv :: Int -> IO ([FT.Interval Int], FT.IntervalMap Int Int)+ftEnv n = do+ let ivs = genRandomIntervals n 20 n+ let ivsFt = [(FT.Interval lo hi, lo) | (IntRange lo hi) <- nub ivs]+ return (map toIv (mkKeys n), ftFromList ivsFt)+ where+ toIv (IntRange a b) = FT.Interval a b++stEnv :: Int -> IO ([ST.Interval Int], ST.STree [ST.Interval Int] Int)+stEnv n = do+ let ivs = genRandomIntervals n 20 n+ let ivsFt = [(lo,hi) | (IntRange lo hi) <- nub ivs]+ return (map toIv (mkKeys n), stFromList ivsFt)+ where+ toIv (IntRange a b) = ST.Interval ST.Closed (ST.R a) (ST.R b) ST.Closed+++runInsert :: Interval k a => (k -> a -> m -> m) -> m -> [k] -> m+runInsert ins m keys = foldr (\k mp -> ins k (lowerBound k) mp) m keys++runLookup :: (k -> m -> Maybe Int) -> m -> [k] -> Int+runLookup f m keys = sum $ catMaybes $ map (\k -> f k m) keys++runContains :: (Interval i e) => (t -> e -> [(t1, Int)]) -> t -> [i] -> Int+runContains f m keys = sum [v | k <- keys, (_,v) <- f m (lowerBound k)]++benchIV name ins look cont ~(keys,m) = bgroup name [+ bench "insert" $ whnf (runInsert ins m) keys,+ bench "lookup" $ nf (runLookup look m) keys,+ bench "containing" $ nf (runContains cont m) keys+ ]++benchSL :: ([IntRange], SL.IVS IntRange Int) -> Benchmark+benchSL = benchIV "SortedList" SL.insert SL.lookup SL.containing++benchRB :: ([IntRange], RB.IntervalMap IntRange Int) -> Benchmark+benchRB = benchIV "RedBlackTree" RB.insert RB.lookup RB.containing++benchFT :: ([FT.Interval Int], FT.IntervalMap Int Int) -> Benchmark+benchFT ~(keys,m) = bgroup "FingerTree" [+ bench "insert" $ whnf (runInsert FT.insert m) keys,+ bench "containing" $ nf (\ks -> sum [v | k <- ks, (_,v) <- FT.search (FT.low k) m]) keys+ ]++benchST :: ([ST.Interval Int], ST.STree [ST.Interval Int] Int) -> Benchmark+benchST ~(keys,m) = bgroup "SegmentTree" [+ bench "insert" $ whnf (runInsert (\k _ mp -> ST.insert mp k) m) keys,+ bench "containing" $ nf (\ks -> sum [stLoBound v | k <- ks, v <- ST.stabbingQuery m (stLoBound k)]) keys+ ]++++main :: IO ()+main = defaultMainWith benchConfig [+ bgroup "10" [+ env (slEnv 10) benchSL,+ env (rbEnv 10) benchRB,+ env (ftEnv 10) benchFT,+ env (stEnv 10) benchST+ ],+ bgroup "100" [+ env (slEnv 100) benchSL,+ env (rbEnv 100) benchRB,+ env (ftEnv 100) benchFT,+ env (stEnv 100) benchST+ ],+ bgroup "1000" [+ env (slEnv 1000) benchSL,+ env (rbEnv 1000) benchRB,+ env (ftEnv 1000) benchFT,+ env (stEnv 1000) benchST+ ],+ bgroup "2500" [+ env (slEnv 2500) benchSL,+ env (rbEnv 2500) benchRB,+ env (ftEnv 2500) benchFT,+ env (stEnv 2500) benchST+ ],+ bgroup "10000" [+ env (rbEnv 10000) benchRB,+ env (ftEnv 10000) benchFT,+ env (stEnv 10000) benchST+ ],+ bgroup "20000" [+ env (rbEnv 20000) benchRB,+ env (ftEnv 20000) benchFT,+ env (stEnv 20000) benchST+ ],+ bgroup "50000" [+ env (rbEnv 50000) benchRB,+ env (ftEnv 50000) benchFT,+ env (stEnv 50000) benchST+ ],+ bgroup "100000" [+ env (rbEnv 100000) benchRB,+ env (ftEnv 100000) benchFT,+ env (stEnv 100000) benchST+ ]+ ]
bench/GenericLazyVsStrict.hs view
@@ -12,7 +12,7 @@ import Data.IntervalMap.Generic.Interval import qualified Data.IntervalMap.Generic.Lazy as L-import qualified Data.IntervalMap.Generic.Lazy as S+import qualified Data.IntervalMap.Generic.Strict as S seed :: Int
+ changelog view
@@ -0,0 +1,18 @@+0.4.1.0 Add IntervalSet.+ Minor performance tweaks.+ Documentation updates.+ Moved to GitHub.++0.4.0.1 Documentation update. Wrong portability info fixed.++0.4.0.0 Major update adding support for user-defined key intervals.++0.3.0.3 Updated benchmark to use Criterion 1.0. Tested with ghc 7.8.3.++0.3.0.2 Dropped upper constraint on criterion. Tested with ghc 7.6.3.+ Migrated repo to Darcs Hub.++0.3.0.1 Bugfixes: Lazy was too strict, Strict too lazy.++0.3.0.0 Split into Lazy and Strict modules, following containers.+
examples/GenericExample.lhs view
@@ -52,9 +52,6 @@ > type Appointments = IntervalMap TimeSpan [(Person, Details)] -Not that the key type is *Time*, not *TimeSpan*. That is, you specify the type of the-endpoints, not the type of the interval itself.- Now I can define some helper functions. A set containing no appointments:
test/IntervalMapTests.hs view
@@ -16,20 +16,20 @@ instance Arbitrary II where arbitrary = do x <- arbitrary- liftM II (interval (abs x))+ liftM II (interval (abs x)) interval :: Int -> Gen (Interval Int) interval x = do- y <- sized (\n -> choose (x, x + abs n))- if x == y then return (ClosedInterval x y)- else oneof [return (ClosedInterval x y),- return (OpenInterval x y),- return (IntervalCO x y),- return (IntervalOC x y)]+ y <- sized (\n -> choose (x, x + abs n))+ if x == y then return (ClosedInterval x y)+ else oneof [return (ClosedInterval x y),+ return (OpenInterval x y),+ return (IntervalCO x y),+ return (IntervalOC x y)] instance Arbitrary IMI where arbitrary = do xs <- orderedList- return (IMI (fromAscList [(v, lowerBound v) | (II v) <- xs]))+ return (IMI (fromAscList [(v, lowerBound v) | (II v) <- xs])) emptyM, single46 :: M.IntervalMap Int String@@ -51,11 +51,11 @@ bal3 :: M.IntervalMap Int String bal3 = let m1 = M.insert (ClosedInterval 1 4) "14" single46- in M.insert (ClosedInterval 5 8) "58" m1+ in M.insert (ClosedInterval 5 8) "58" m1 bal3' :: M.IntervalMap Int String bal3' = let m1 = M.insert (ClosedInterval 1 4) "14" single46- in M.insert (OpenInterval 5 8) "o58" m1+ in M.insert (OpenInterval 5 8) "o58" m1 prop_tests2 = 3 == M.size bal3 &&@@ -82,12 +82,12 @@ deep100L :: M.IntervalMap Int Int deep100L = construct 100 M.empty where construct n m | n <= 0 = m- | otherwise = construct (n - 1) (M.insert (ClosedInterval n n) n m)+ | otherwise = construct (n - 1) (M.insert (ClosedInterval n n) n m) deep100R :: M.IntervalMap Int Int deep100R = construct 1 M.empty where construct n m | n > 100 = m- | otherwise = construct (n + 1) (M.insert (ClosedInterval n n) n m)+ | otherwise = construct (n + 1) (M.insert (ClosedInterval n n) n m) prop_tests3 =@@ -107,48 +107,51 @@ M.valid (M.delete (ClosedInterval 23 23) deep100R) prop_mapKeys =- equalMap ["foo"] (M.mapKeys lower (M.insert (ClosedInterval 4 5) "foo" single46)) &&- equalMap ["single46"] (M.mapKeys lower (M.insert (ClosedInterval 4 7) "foo" single46))+ equalMap ["foo"] (M.mapKeys lower (M.insert (ClosedInterval 4 5) "foo" single46)) &&+ equalMap ["single46"] (M.mapKeys lower (M.insert (ClosedInterval 4 7) "foo" single46)) where lower k = ClosedInterval (lowerBound k) (lowerBound k) prop_mapKeysWith (IMI m) = M.valid m' && all correct (M.keys m) where lower k = ClosedInterval (lowerBound k) (lowerBound k)- m' = M.mapKeysWith (+) lower m- correct x = let mps = sum [v | (k,v) <- M.toList m, lowerBound k == lowerBound x]- in case M.lookup (lower x) m' of- Nothing -> False- Just v' -> v' == mps- - + m' = M.mapKeysWith (+) lower m+ correct x = let mps = sum [v | (k,v) <- M.toList m, lowerBound k == lowerBound x]+ in case M.lookup (lower x) m' of+ Nothing -> False+ Just v' -> v' == mps+ + -- check that our generator yields valid maps. prop_valid (IMI m) = M.valid m +prop_singleton (II k) = let m = singleton k 'a' in+ m!k == 'a' && size m == 1+ prop_delete (IMI m) (II k) = let m' = M.delete k m in- M.valid m' &&- notMember k m' &&- if M.null m then M.null m'- else if M.member k m then M.size m' == M.size m - 1- else M.size m' == M.size m+ M.valid m' &&+ notMember k m' &&+ if M.null m then M.null m'+ else if M.member k m then M.size m' == M.size m - 1+ else M.size m' == M.size m prop_insert (IMI m) (II k) = let m' = M.insert k 4711 m in M.valid m' &&- M.lookup k m' == Just 4711 &&- if M.member k m then M.size m' == M.size m- else M.size m' == M.size m + 1+ M.lookup k m' == Just 4711 &&+ if M.member k m then M.size m' == M.size m+ else M.size m' == M.size m + 1 prop_min (IMI m) = if M.null m then M.null (M.deleteMin m) else let (k,v) = findMin m- m' = deleteMin m- in notMember k m' && M.size m == M.size m' + 1- && k == minimum (M.keys m) && valid m'+ m' = deleteMin m+ in notMember k m' && M.size m == M.size m' + 1+ && k == minimum (M.keys m) && valid m' prop_max (IMI m) = if M.null m then M.null (M.deleteMax m) else let (k,v) = findMax m- m' = deleteMax m- in notMember k m' && M.size m == M.size m' + 1- && k == maximum (M.keys m) && valid m'+ m' = deleteMax m+ in notMember k m' && M.size m == M.size m' + 1+ && k == maximum (M.keys m) && valid m' prop_updateMin_u (IMI m) = let m' = M.updateMin (\v -> Just (v+1)) m in@@ -207,26 +210,26 @@ [e | e@(k,_) <- M.toList m, p `inside` k] prop_searchInterval (IMI m) (II i) = sameElements (m `intersecting` i)- [e | e@(k,_) <- M.toList m, k `overlaps` i]+ [e | e@(k,_) <- M.toList m, k `overlaps` i] prop_within (IMI m) (II i) = sameElements (m `M.within` i) [e | e@(k,_) <- M.toList m, i `subsumes` k] prop_findMin (IMI m) = not (M.null m) ==> let x = minimum (M.toList m)- (y,m') = M.deleteFindMin m- in M.findMin m == x &&- y == x &&- M.valid m' &&- sameElements (M.toList m Data.List.\\ [x]) (M.toList m') &&- sameElements (M.toList m Data.List.\\ [x]) (M.toList (M.deleteMin m))+ (y,m') = M.deleteFindMin m+ in M.findMin m == x &&+ y == x &&+ M.valid m' &&+ sameElements (M.toList m Data.List.\\ [x]) (M.toList m') &&+ sameElements (M.toList m Data.List.\\ [x]) (M.toList (M.deleteMin m)) prop_findMax (IMI m) = not (M.null m) ==> let x = maximum (M.toList m)- (y,m') = M.deleteFindMax m- in M.findMax m == x &&- y == x &&- M.valid m' &&- sameElements (M.toList m Data.List.\\ [x]) (M.toList m') &&- sameElements (M.toList m Data.List.\\ [x]) (M.toList (M.deleteMax m))+ (y,m') = M.deleteFindMax m+ in M.findMax m == x &&+ y == x &&+ M.valid m' &&+ sameElements (M.toList m Data.List.\\ [x]) (M.toList m') &&+ sameElements (M.toList m Data.List.\\ [x]) (M.toList (M.deleteMax m)) prop_findLast (IMI m) = not (M.null m) ==> M.findLast m == head (sortBy cmp (M.toList m))@@ -239,14 +242,14 @@ prop_insertWith (IMI m) (II i) v = let m' = M.insertWith (\new old -> new + old) i v m in if M.member i m then M.valid m' && m' M.! i == m M.! i + v && M.size m' == M.size m- else- M.valid m' && m' M.! i == v && M.size m' == M.size m + 1+ else+ M.valid m' && m' M.! i == v && M.size m' == M.size m + 1 prop_insertWith' (IMI m) (II i) v = let m' = M.insertWith' (\new old -> new + old) i v m in if M.member i m then M.valid m' && m' M.! i == m M.! i + v && M.size m' == M.size m- else- M.valid m' && m' M.! i == v && M.size m' == M.size m + 1+ else+ M.valid m' && m' M.! i == v && M.size m' == M.size m + 1 prop_insertLookupWithKey (IMI m) (II i) v = case M.insertLookupWithKey (\k new old -> upperBound k + new + old) i v m of@@ -261,25 +264,25 @@ prop_foldr (IMI m) = M.foldr f z m == Prelude.foldr f z [ v | (_,v) <- M.toAscList m ] where z = []- f = (:)+ f = (:) prop_adjust (II i) (IMI m) = let m' = M.adjust (13*) i m in- M.valid m' &&+ M.valid m' && case M.lookup i m of Nothing -> m == m'- Just v -> case M.lookup i m' of- Nothing -> False- Just v' -> v' == v * 13+ Just v -> case M.lookup i m' of+ Nothing -> False+ Just v' -> v' == v * 13 prop_update (II i) (IMI m) = let f n = if n `rem` 2 == 0 then Nothing else Just (13 * n)- m' = M.update f i m- in- M.valid m' &&- case M.lookup i m of- Nothing -> m == m'- Just v -> case M.lookup i m' of- Nothing -> v `rem` 2 == 0- Just v' -> v' == 13 * v+ m' = M.update f i m+ in+ M.valid m' &&+ case M.lookup i m of+ Nothing -> m == m'+ Just v -> case M.lookup i m' of+ Nothing -> v `rem` 2 == 0+ Just v' -> v' == 13 * v prop_alter (IMI m) (II k) = delete && insert where@@ -289,49 +292,51 @@ prop_union (IMI m1) (IMI m2) = M.size m' == M.size m1 + numNotInM1 0 (M.keys m2) -- size && valsM1 (M.assocs m1) -- m1 entries unchanged- && valsM2 (M.assocs m2) -- m2 entries not in m1 unchanged- && M.valid m'+ && valsM2 (M.assocs m2) -- m2 entries not in m1 unchanged+ && M.valid m' where m' = m1 `M.union` m2 valsM1 [] = True valsM1 ((k,v):xs) = case M.lookup k m' of- Nothing -> False- Just v' -> v' == v && valsM1 xs+ Nothing -> False+ Just v' -> v' == v && valsM1 xs valsM2 [] = True valsM2 ((k,v):xs) | M.member k m1 = valsM2 xs- | otherwise = case M.lookup k m' of- Nothing -> False- Just v' -> v' == v && valsM2 xs+ | otherwise = case M.lookup k m' of+ Nothing -> False+ Just v' -> v' == v && valsM2 xs numNotInM1 n [] = n numNotInM1 n (k:ks) | M.member k m1 = numNotInM1 n ks- | otherwise = numNotInM1 (n+1) ks+ | otherwise = numNotInM1 (n+1) ks prop_unionWithKey (IMI m1) (IMI m2) = M.size m' == M.size m1 + numNotInM1 0 (M.keys m2) -- size && valuesCorrect (M.assocs m')- && M.valid m'+ && M.valid m' where f k a b = 7 * upperBound k + 3 * b + b m' = M.unionWithKey f m1 m2 valuesCorrect [] = True valuesCorrect ((k,v):xs) = case M.lookup k m1 of- Nothing -> case M.lookup k m2 of- Nothing -> False- Just v2 -> v2 == v && valuesCorrect xs- Just v1 -> case M.lookup k m2 of- Nothing -> v1 == v && valuesCorrect xs- Just v2 -> v == f k v1 v2 && valuesCorrect xs+ Nothing -> case M.lookup k m2 of+ Nothing -> False+ Just v2 -> v2 == v && valuesCorrect xs+ Just v1 -> case M.lookup k m2 of+ Nothing -> v1 == v && valuesCorrect xs+ Just v2 -> v == f k v1 v2 && valuesCorrect xs numNotInM1 n [] = n numNotInM1 n (k:ks) | M.member k m1 = numNotInM1 n ks- | otherwise = numNotInM1 (n+1) ks+ | otherwise = numNotInM1 (n+1) ks -prop_unions (IMI m1) (IMI m2) (IMI m3) = M.unions [m1,m2,m3] == (m1 `M.union` m2 `M.union` m3)+prop_unions ims = M.unions ms == Prelude.foldl M.union empty ms+ where ms = [m | IMI m <- ims] + prop_difference (IMI m1) (IMI m2) = M.valid m' && m' == Prelude.foldr M.delete m1 (M.keys m2) where m' = m1 M.\\ m2 @@ -353,7 +358,7 @@ assoc :: Eq k => k -> [(k,a)] -> Maybe a assoc _ [] = Nothing assoc k ((x,v):xs) | x == k = Just v- | otherwise = assoc k xs+ | otherwise = assoc k xs prop_mapAccum (IMI m) = M.valid m' && acc == sum (M.elems m) && sum (M.elems m') == 2 * acc where (acc, m') = M.mapAccum (\a v -> (a+v, 2*v)) 0 m@@ -375,33 +380,35 @@ odds = length [x | x <- M.elems m, odd x] prop_partition (IMI m) = M.valid m1 && M.valid m2 && all odd (M.elems m1) && all even (M.elems m2)- && M.size m == M.size m1 + M.size m2+ && M.size m == M.size m1 + M.size m2 where (m1,m2) = M.partition odd m prop_splitLookup (IMI m) (II x) = M.valid l && M.valid r- && all (< x) (M.keys l) && all (> x) (M.keys r)- && value == M.lookup x m- && M.size m == M.size l + M.size r + (if M.member x m then 1 else 0)+ && all (< x) (M.keys l) && all (> x) (M.keys r)+ && value == M.lookup x m+ && M.size m == M.size l + M.size r + (if M.member x m then 1 else 0) where (l, value, r) = splitLookup x m +prop_readShow (IMI m) = m == read (show m) + checkElems :: Int -> Int -> [(Interval Int, Int)] -> Bool checkElems n len lyst = h n (n + len) lyst where h i n xs | i > n = True | otherwise = case xs of ((iv,v):xs') -> if v == i && lowerBound iv == i && upperBound iv == i- then h (i+1) n xs'- else False+ then h (i+1) n xs'+ else False check p name = do r <- quickCheckWithResult (stdArgs { maxSuccess = 500 }) p- if isSuccess r- then return r- else do putStrLn ("error: " ++ name ++ ": " ++ show r)- exitFailure+ if isSuccess r+ then return r+ else do putStrLn ("error: " ++ name ++ ": " ++ show r)+ exitFailure main :: IO ()@@ -410,43 +417,48 @@ check prop_tests2 "tests2" check prop_tests3 "tests3" check prop_mapKeys "mapKeys"- check prop_valid "valid"- check prop_delete "delete"- check prop_insert "insert"- check prop_min "min"- check prop_max "max"- check prop_findWithDefault "findWithDefault"- check prop_searchPoint "searchPoint"- check prop_searchInterval "searchInterval"+ check prop_valid "valid"+ check prop_singleton "singleton"+ check prop_delete "delete"+ check prop_insert "insert"+ check prop_min "min"+ check prop_max "max"+ check prop_findWithDefault "findWithDefault"+ check prop_searchPoint "searchPoint"+ check prop_searchInterval "searchInterval" check prop_within "within"- check prop_findMin "findMin"- check prop_findMax "findMax"+ check prop_findMin "findMin"+ check prop_findMax "findMax"+ check prop_findLast "findLast" check prop_updateMin_u "updateMin update" check prop_updateMin_d "updateMin delete" check prop_updateMax_u "updateMax update" check prop_updateMax_d "updateMax delete"- check prop_insertWith "insertWith"+ check prop_insertWith "insertWith" check prop_insertWith' "insertWith'"- check prop_insertLookupWithKey "insertLookupWithKey"- check prop_insertLookupWithKey' "insertLookupWithKey'"- check prop_map "map"- check prop_foldr "foldr"- check prop_fromAscList "fromAscList"- check prop_adjust "adjust"- check prop_update "update"- check prop_union "union"- check prop_unionWithKey "unionWithKey"- check prop_unions "unions"- check prop_difference "difference"- check prop_intersection "intersection"- check prop_filter "filter"- check prop_partition "partition"- check prop_splitLookup "splitLookup"- check prop_mapKeysWith "mapKeysWith"+ check prop_insertLookupWithKey "insertLookupWithKey"+ check prop_insertLookupWithKey' "insertLookupWithKey'"+ check prop_map "map"+ check prop_mapAccum "mapAccum"+ check prop_foldr "foldr"+ check prop_fromAscList "fromAscList"+ check prop_adjust "adjust"+ check prop_update "update"+ check prop_alter "alter"+ check prop_union "union"+ check prop_unionWithKey "unionWithKey"+ check prop_unions "unions"+ check prop_difference "difference"+ check prop_intersection "intersection"+ check prop_filter "filter"+ check prop_partition "partition"+ check prop_splitLookup "splitLookup"+ check prop_mapKeysWith "mapKeysWith" check prop_submap "submap"- putStrLn ("deep100L: " ++ show (M.showStats deep100L))- putStrLn ("deep100R: " ++ show (M.showStats deep100R))- exitSuccess+ check prop_readShow "read/show"+ putStrLn ("deep100L: " ++ show (M.showStats deep100L))+ putStrLn ("deep100R: " ++ show (M.showStats deep100R))+ exitSuccess -- Utils ----------------- @@ -457,11 +469,11 @@ sameElements [] [] = True sameElements [] (_:_) = False sameElements (x:xs) ys = case tryRemove x ys of- Nothing -> False- Just ys' -> sameElements xs ys'+ Nothing -> False+ Just ys' -> sameElements xs ys' where tryRemove _ [] = Nothing tryRemove x (y:ys) | x == y = Just ys- | otherwise = case tryRemove x ys of- Nothing -> Nothing- Just ys' -> Just (y : ys')+ | otherwise = case tryRemove x ys of+ Nothing -> Nothing+ Just ys' -> Just (y : ys')
+ test/IntervalSetTests.hs view
@@ -0,0 +1,212 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++-- module IntervalSetTests (main) where++import System.Exit (exitSuccess, exitFailure)++import Test.QuickCheck hiding (within)+import Test.QuickCheck.Test (isSuccess)+import Control.Monad (liftM)+import Prelude hiding (null, map, filter, foldr, foldl)+import qualified Data.List as L++import Data.IntervalSet+++data II = II !Int !Int deriving (Eq, Ord, Show, Read)++bump :: Int -> II -> II+bump n (II a b) = II (a+n) (b+n)++contains :: II -> Int -> Bool+contains (II a b) n = a <= n && n <= b++instance Interval II Int where+ lowerBound (II a _) = a+ upperBound (II _ b) = b++instance Arbitrary II where+ arbitrary = do x <- arbitrary+ iv <- interval (abs x)+ return iv++interval :: Int -> Gen II+interval x = do y <- sized (\n -> choose (x, x + abs n))+ return (II x y)++newtype IS = IS (IntervalSet II) deriving (Show)+ +instance Arbitrary IS where+ arbitrary = do xs <- orderedList+ return (IS (fromAscList xs))++prop_valid (IS s) = valid s++prop_null (IS s) = null s == (size s == 0)++prop_size (IS s) = size s == length (toList s)++prop_singleton :: II -> Bool+prop_singleton iv = size (singleton iv) == 1+ +prop_insert_member (IS s) iv = member iv (insert iv s)++prop_notMember (IS s) iv = notMember iv s == not (member iv s)++prop_isSubsetOf (IS s1) (IS s2) = (s1 `isSubsetOf` s2) == L.null (toList s1 L.\\ toList s2)++prop_isProperSubsetOf (IS s1) (IS s2)+ = (s1 `isProperSubsetOf` s2) ==+ (L.null (toList s1 L.\\ toList s2) && s1 /= s2)+ +prop_insert_size (IS s) iv =+ let s' = insert iv s in+ if member iv s+ then size s' == size s+ else size s' == size s + 1++prop_delete (IS s) iv = let s' = delete iv s in+ valid s' &&+ if notMember iv s then s' == s+ else all (\e -> e `member` s' || e == iv) (toList s)++prop_list (IS s) = s == fromList (toList s)+prop_asclist (IS s) = s == fromAscList (toAscList s)+prop_desclist (IS s) = toDescList s == reverse (toAscList s)+prop_elems (IS s) = elems s == toAscList s++prop_union (IS s1) (IS s2) = union s1 s2 == foldr insert s2 s1++prop_unions xs = unions iss == L.foldl union empty iss+ where iss = [is | IS is <- xs]++prop_difference (IS s1) (IS s2) = (s1 \\ s2) == foldr delete s1 s2+ +prop_intersection (IS s1) (IS s2) =+ let i = intersection s1 s2 in+ all (\e -> member e s1 && member e s2) (toList i)+ +prop_minView (IS s) = case minView s of+ Nothing -> null s+ Just (min, s') -> all (min <) (toList s')+ +prop_maxView (IS s) = case maxView s of+ Nothing -> null s+ Just (max, s') -> all (max >) (toList s')+ +prop_findMin (IS s) = case findMin s of+ Nothing -> null s+ Just min -> all (min <=) (toList s)++prop_findMax (IS s) = case findMax s of+ Nothing -> null s+ Just max -> all (max >=) (toList s)++prop_findLast (IS s) = case findLast s of+ Nothing -> null s+ Just x@(II _ end) ->+ all (\e -> upperBound e < end || (upperBound e == end && e <= x)) (toList s)+ +prop_deleteMin (IS s) = let s' = deleteMin s in+ case findMin s of+ Nothing -> null s'+ Just min -> s' == delete min s++prop_deleteMax (IS s) = let s' = deleteMax s in+ case findMax s of+ Nothing -> null s'+ Just max -> s' == delete max s+ +prop_map (IS s) n = s == map (bump n) (map (bump (-n)) s)+prop_mapMonotonic (IS s) n = s == mapMonotonic (bump n) (mapMonotonic (bump (-n)) s)++prop_filter (IS s) iv = filter (iv /=) s == delete iv s++prop_partition (IS s) iv = let (lo,hi) = partition (<= iv) s in+ valid lo && valid hi &&+ all (<= iv) (toList lo) &&+ all (> iv) (toList hi) &&+ union lo hi == s++prop_split (IS s) iv = let (lo,hi) = split iv s in+ all (< iv) (toList lo) &&+ all (> iv) (toList hi) &&+ union lo hi == if member iv s then delete iv s else s++prop_splitMember (IS s) iv = let (lo,m,hi) = splitMember iv s in+ valid lo && valid hi &&+ m == member iv s &&+ all (< iv) (toList lo) &&+ all (> iv) (toList hi) &&+ union lo hi == if m then delete iv s else s++prop_readShow (IS s) = s == read (show s)+++prop_containing :: IS -> Int -> Bool+prop_containing (IS s) n = let s' = s `containing` n in+ all (\e -> if e `contains` n then e `member` s' else e `notMember` s') (toList s)++prop_intersecting :: IS -> II -> Bool+prop_intersecting (IS s) iv = let s' = s `intersecting` iv in+ all (\e -> if e `overlaps` iv then e `member` s' else e `notMember` s') (toList s)+ +prop_within :: IS -> II -> Bool+prop_within (IS s) iv = let s' = s `within` iv in+ all (\e -> if iv `subsumes` e then e `member` s' else e `notMember` s') (toList s)+ +prop_foldr (IS s) iv = Just (foldr (\v r -> min v r) iv s) == findMin (insert iv s)+prop_foldr' (IS s) iv = Just (foldr' (\v r -> min v r) iv s) == findMin (insert iv s)+prop_foldl (IS s) iv = Just (foldl (\r v -> min v r) iv s) == findMin (insert iv s)+prop_foldl' (IS s) iv = Just (foldl' (\r v -> min v r) iv s) == findMin (insert iv s)++check p name = do putStrLn ("Testing " ++ name ++ ":")+ r <- quickCheckWithResult (stdArgs { maxSuccess = 500 }) p+ if isSuccess r+ then return r+ else do putStrLn ("error: " ++ name ++ ": " ++ show r)+ exitFailure+++main = do+ check prop_valid "valid"+ check prop_null "null"+ check prop_size "size"+ check prop_notMember "notMember"+ check prop_singleton "singleton"+ check prop_isSubsetOf "subsetOf"+ check prop_isProperSubsetOf "properSubsetOf"+ check prop_insert_member "insert -> member"+ check prop_insert_size "insert + size"+ check prop_delete "delete"+ check prop_list "toList/fromList"+ check prop_asclist "toAscList/fromAscList"+ check prop_desclist "toDescList"+ check prop_elems "elems"+ check prop_union "union"+ check prop_unions "unions"+ check prop_difference "difference"+ check prop_intersection "intersection"+ check prop_findMin "findMin"+ check prop_findMax "findMax"+ check prop_findLast "findLast"+ check prop_deleteMin "deleteMin"+ check prop_deleteMax "deleteMax"+ check prop_minView "minView"+ check prop_maxView "maxView"+ check prop_foldr "foldr"+ check prop_foldr' "foldr'"+ check prop_foldl "foldl"+ check prop_foldl' "foldl'"+ check prop_map "map"+ check prop_mapMonotonic "mapMonotonic"+ check prop_filter "filter"+ check prop_partition "partition"+ check prop_split "split"+ check prop_splitMember "splitMember"+ check prop_containing "containing"+ check prop_intersecting "intersecting"+ check prop_within "within"+ check prop_readShow "read/show"+ exitSuccess