1 {-# LANGUAGE FlexibleContexts #-}
2 {-# LANGUAGE FlexibleInstances #-}
3 {-# LANGUAGE MultiParamTypeClasses #-}
4 {-# LANGUAGE TupleSections #-}
5 {-# LANGUAGE TypeFamilies #-}
6 {-# OPTIONS_GHC -fno-warn-orphans #-}
7 module Hcompta.Lib.Interval.Sieve where
9 import Control.Exception (assert)
10 -- import Data.Monoid (Monoid(..))
11 import qualified Data.List
12 import Data.Maybe (fromMaybe)
13 import qualified Data.Foldable as Foldable
14 import qualified Data.FingerTree as FT
15 import Data.FingerTree (FingerTree, ViewL(..), ViewR(..), (><), (<|), (|>))
16 import Prelude hiding (null)
18 import qualified Hcompta.Lib.Interval as Interval
19 import Hcompta.Lib.Interval (Interval(..), low, high, (..<..), (..<<..), Position(..), position, flip_limit, Pretty(..))
24 -- | '..<<..'-ordered union of 'Interval's.
28 -- * Ralf Hinze and Ross Paterson,
29 -- \"Finger trees: a simple general-purpose data structure\",
30 -- /Journal of Functional Programming/ 16:2 (2006) pp 197-217.
31 -- <http://staff.city.ac.uk/~ross/papers/FingerTree.html>
32 -- * <https://hackage.haskell.org/package/fingertree/docs/Data-IntervalMap-FingerTree.html>
34 Sieve { unSieve :: FingerTree (Measure x) (Interval x) }
36 instance (Ord x, Show x) => Show (Pretty (Sieve x)) where
37 show (Pretty s) | null s = "empty"
38 show (Pretty s) = Data.List.intercalate " u " $ map (show . Pretty) $ intervals s
40 -- | Like 'Data.Functor.fmap' but working on 'Interval's.
43 => (Interval x -> Interval y) -> Sieve x -> Sieve y
44 fmap_interval f (Sieve ft) = Sieve (FT.fmap' f ft)
46 -- | Like 'Data.Functor.fmap' but working on 'Interval's,
47 -- and safe only if 'Measure' is preserved.
50 => (Interval x -> Interval x)
52 fmap_interval_unsafe f (Sieve ft) = Sieve (FT.unsafeFmap f ft)
54 -- | Like 'Data.Traversable.traverse' but working on 'Interval's.
56 :: (Ord x, Ord y, Applicative f)
57 => (Interval x -> f (Interval y))
58 -> Sieve x -> f (Sieve y)
59 traverse_interval f (Sieve ft) = Sieve <$> (FT.traverse' f ft)
61 -- | Like 'Data.Traversable.traverse' but working on 'Interval's,
62 -- and safe only if 'Measure' is preserved.
63 traverse_interval_unsafe
64 :: (Ord x, Applicative f)
65 => (Interval x -> f (Interval x))
66 -> Sieve x -> f (Sieve x)
67 traverse_interval_unsafe f (Sieve ft) = Sieve <$> (FT.unsafeTraverse f ft)
69 -- | 'FT.Measure' of each leaf or node of the 'Sieve' 'FingerTree'.
71 = Measure_Empty -- ^ Measure of 'FT.empty' 'Fingertree'.
73 { max_high_of_max_low :: Interval x
74 -- ^ An __'Interval' with the max 'high' 'Limit'__
75 -- __amongst those having the max 'low' 'Limit'__
76 -- (which is the 'max' 'Interval'
77 -- because of lexicographical ordering).
78 {- NOTE: not useful in the particular case of '..<..'-ordered 'Interval's
79 , max_high :: Interval x
80 -- ^ An __'Interval' with the max 'high' 'Limit'__
81 -- (which may be a different 'Interval'
82 -- as it can have a lower 'low' 'Limit',
83 -- and thus not be the 'max' 'Interval').
86 instance Ord x => Monoid (Measure x) where
87 mempty = Measure_Empty
89 Measure_Empty `mappend` i = i
90 i `mappend` Measure_Empty = i
91 _i `mappend` j = Measure (max_high_of_max_low j)
92 {- NOTE: not useful in the particular case of '..<..'-ordered 'Interval's
94 Measure (max_high_of_max_low j) $
95 case compare_without_adherence (high (max_high i)) (high (max_high j)) of
98 case (adherence (high (max_high i)), adherence (high (max_high j))) of
99 (In , In) -> max_high i
100 (In , Out) -> max_high i
101 (Out, In) -> max_high j
102 (Out, Out) -> max_high i
105 instance Ord x => FT.Measured (Measure x) (Interval x) where
108 empty :: Ord x => Sieve x
109 empty = Sieve $ FT.empty
111 -- | Return the 'True' iif. the given 'Sieve' is 'empty'.
112 null :: Ord x => Sieve x -> Bool
113 null (Sieve ft) = FT.null ft
115 singleton :: Ord x => Interval x -> Sieve x
116 singleton = Sieve . FT.singleton
118 -- | Return an 'Interval' with:
120 -- * the 'Interval.low' 'Interval.Limit' of the 'min' 'Interval',
121 -- * the 'Interval.high' 'Interval.Limit' of the 'max' 'Interval'.
122 interval :: Ord x => Sieve x -> Maybe (Interval x)
123 interval (Sieve ft) =
126 -- l :< ls | FT.null ls -> Just l
130 _ :> r -> Just $ Interval (low l, high r)
132 -- | All the 'Interval's of the 'Sieve' in '..<<..' order.
133 intervals :: Ord x => Sieve x -> [Interval x]
134 intervals (Sieve t) = Foldable.toList t
138 -- | Return a 'Sieve' merging the given 'Sieve's with 'Interval.union'.
139 union :: Ord x => Sieve x -> Sieve x -> Sieve x
140 union (Sieve s0) (Sieve s1) =
147 let (js_not_away_lt_i, js_away_gt_i ) = FT.split ( (i ..<<..) . max_high_of_max_low) js in
148 let (js_away_lt_i , js_not_away_i) = FT.split (not . (..<<.. i) . max_high_of_max_low) js_not_away_lt_i in
150 -- NOTE: flip merge when possible
151 -- (i.e. when high i is majoring high-s of intersecting Interval-s)
152 -- to preserve complexity over commutativity.
153 case FT.viewl js_not_away_i of
154 FT.EmptyL -> i <| merge js_away_gt_i gt_i
160 (Adjacent, LT) -> merge gt_i (Interval (low i, high u) <| js_away_gt_i) -- flip: NO
161 (Overlap , LT) -> merge gt_i (Interval (low i, high u) <| js_away_gt_i) -- flip: NO
162 (Prefix , LT) -> merge gt_i (Interval (low i, high u) <| js_away_gt_i) -- flip: NO
163 (Include , GT) -> merge gt_i (u <| js_away_gt_i) -- flip: NO
164 (Suffixed, LT) -> i <| merge js_away_gt_i gt_i -- flip: YES
165 (Include , LT) -> i <| merge js_away_gt_i gt_i -- flip: YES
166 (Equal , _ ) -> i <| merge js_away_gt_i gt_i -- flip: YES
167 (Adjacent, GT) -> Interval (low u, high i) <| merge js_away_gt_i gt_i -- flip: YES
168 (Overlap , GT) -> Interval (low u, high i) <| merge js_away_gt_i gt_i -- flip: YES
169 (Prefix , GT) -> Interval (low u, high i) <| merge js_away_gt_i gt_i -- flip: YES
170 (Suffixed, GT) -> Interval (low u, high i) <| merge js_away_gt_i gt_i -- flip: YES
171 _ -> assert False undefined
174 case position i lu of
180 case position i hu of
181 (Adjacent, LT) -> merge gt_i (Interval (l, high hu) <| js_away_gt_i) -- flip: NO
182 (Overlap , LT) -> merge gt_i (Interval (l, high hu) <| js_away_gt_i) -- flip: NO
183 (Prefix , LT) -> merge gt_i (Interval (l, high hu) <| js_away_gt_i) -- flip: NO
184 _ -> Interval (l, high i) <| merge js_away_gt_i gt_i -- flip: YES
186 -- | Return a 'Sieve' merging the 'Interval's in the given 'Foldable' with 'Interval.union'.
187 from_Foldable :: (Foldable f, Ord x) => f (Interval x) -> Sieve x
188 from_Foldable = Foldable.foldr (union . singleton) empty
192 -- | Return a 'Sieve' merging the given 'Sieve's with 'Interval.intersection'.
193 intersection :: Ord x => Sieve x -> Sieve x -> Sieve x
194 intersection (Sieve s0) (Sieve s1) =
197 intersect i j = fromMaybe (assert False undefined) $ Interval.intersection i j
200 FT.EmptyL -> FT.empty
202 let (_, js_not_lt_i) = FT.split (not . (..<.. i) . max_high_of_max_low) js in
203 let (js_intersecting_i, _) = FT.split ( (i ..<..) . max_high_of_max_low) js_not_lt_i in
204 case FT.viewl js_intersecting_i of
208 hi' :> hi -> hi' |> intersect i hi
210 >< merge js_not_lt_i gt_i
211 _ -> merge js_not_lt_i gt_i
212 -- NOTE: swap merging to preserve complexity over commutativity
214 -- | All 'Interval's having a non-'Nothing' 'Interval.intersection' with the given 'Interval',
215 -- in '..<<..' order.
216 intersecting :: Ord x => Interval x -> Sieve x -> [Interval x]
217 intersecting i = Foldable.toList . unSieve . intersection (singleton i)
221 -- | Return the 'Sieve' spanning over all the values not within the given 'Sieve'.
222 complement :: (Ord x, Bounded (Interval.Limit x)) => Sieve x -> Sieve x
223 complement = complement_with (Interval (minBound, maxBound))
225 -- | Return the 'Sieve' spanning over all the values not within the given 'Sieve',
226 -- but within the given 'Interval' which MUST be 'Interval.onto' every 'Interval' inside the 'Sieve'.
227 complement_with :: Ord x => Interval x -> Sieve x -> Sieve x
228 complement_with b (Sieve s) =
231 (\i (previous_low, ft) ->
233 , if (Interval.HH $ high i) < (Interval.HH $ high b)
234 then Interval (flip_limit $ high i, flip_limit previous_low) <| ft
237 (flip_limit $ high b, FT.empty) s in
239 case compare (Interval.LL $ low b) (Interval.LL $ last_low) of
240 LT -> Interval (low b, flip_limit last_low) <| c
241 EQ | low b == high b && FT.null s -> FT.singleton b