1 -- | The whole point of this module is
2 -- to reach sub-linear time complexity
3 -- when filtering with 'Filter_Bool'
4 -- over sorted inputs, doing this by:
6 -- 1. Deriving from a generic 'Filter_Bool':
7 -- a specific 'Filter_Bool' only testing
8 -- on the input's sorting key, such that
9 -- it forms a necessary (obviously not sufficient) filter
10 -- to pass for an input's sorting key to let it filter-in (eg. 'bool_date').
11 -- 2. Deriving from this specific 'Filter_Bool':
12 -- a 'Sieve' uniquely uniting 'Interval's
13 -- spanning over sorting keys of inputs
14 -- which can filter-in (eg. 'sieve_date').
15 -- 3. Slicing the input according to this 'Sieve':
16 -- to filter-out inputs which cannot possibly filter-in
19 -- In the end, this module potentially gives less time complexity, but:
21 -- * this is only sensible on large inputs;
22 -- * this significantly increases the code complexity
23 -- of the filtering algorithm, hence its reliability.
24 module Hcompta.Filter.Reduce where
26 import Control.Arrow ((***))
27 import Control.Monad (join)
28 import Data.Maybe (fromJust)
29 import qualified Data.List
30 import Data.Map.Strict (Map)
32 import Hcompta.Date (Date)
33 import qualified Hcompta.Date as Date
34 import qualified Hcompta.Date.Interval as Date.Interval
36 import qualified Hcompta.Lib.Interval as Interval
37 import qualified Hcompta.Lib.Interval.Sieve as Interval.Sieve
38 import qualified Hcompta.Lib.Map.Strict as Map
42 type Reduce_Date = Filter_Bool Filter_Date
45 dated :: t -> Maybe (Filter_Bool Filter_Date)
47 instance Dated Filter_Date where
49 instance Transaction t
50 => Dated (Filter_Transaction t) where
53 Filter_Transaction_Date d -> Just d
56 -- | Return a 'Reduce_Date'
58 -- for the given 'Filter_Bool' to filter.
59 bool_date :: Dated t => Filter_Bool t -> Simplified Reduce_Date
61 simplify (maybe Any id $ go tst)
70 (Not t) -> Not <$> go t
72 case (go t0, go t1) of
73 (Nothing, Nothing) -> Just $ Any
74 (Nothing, Just td) -> Just $ td
75 (Just td, Nothing) -> Just $ td
76 (Just td0, Just td1) -> Just $ And td0 td1
78 case (go t0, go t1) of
79 (Just td0, Just td1) -> Just $ Or td0 td1
82 -- | Return given 'Interval.Sieve.Sieve' 'Date'
83 -- with given 'Reduce_Date' applied on it.
85 -- WARNING: no reducing is done below the day level.
88 -> Interval.Sieve.Sieve Date
89 -> Interval.Sieve.Sieve Date
91 case Interval.Sieve.interval si of
93 Just bounds -> go bounds tb si
99 Interval.Sieve.complement_with bounds $
102 Interval.Sieve.intersection
111 Filter_Date_UTC to ->
112 Interval.Sieve.intersection s $
113 Interval.Sieve.singleton $
115 Filter_Ord_Lt o -> fromJust $ Interval.interval (Interval.low bounds) (Interval.Limit Interval.Out o)
116 Filter_Ord_Le o -> fromJust $ Interval.interval (Interval.low bounds) (Interval.Limit Interval.In o)
117 Filter_Ord_Eq o -> Interval.point o
118 Filter_Ord_Ge o -> fromJust $ Interval.interval (Interval.Limit Interval.In o) (Interval.high bounds)
119 Filter_Ord_Gt o -> fromJust $ Interval.interval (Interval.Limit Interval.Out o) (Interval.high bounds)
120 Filter_Ord_Any -> bounds
121 Filter_Date_Year (Filter_Interval_In i) ->
122 Interval.Sieve.intersection s $
123 Interval.Sieve.singleton $
124 fromJust $ uncurry Interval.interval $
127 Interval.Unlimited_low -> Interval.low bounds
128 Interval.Limited l -> l
129 Interval.Unlimited_high -> Interval.high bounds) $
130 (fmap Interval.low *** fmap Interval.high) $
131 join (***) (fmap Date.Interval.year . Interval.limit) $
133 Filter_Date_Month (Filter_Interval_In i) ->
134 case Interval.Sieve.interval s of
137 Interval.Sieve.intersection s $
138 Interval.Sieve.from_Foldable $
148 Date.Interval.month_slice
150 Filter_Date_DoM (Filter_Interval_In i) ->
151 case Interval.Sieve.interval s of
154 Interval.Sieve.intersection s $
155 Interval.Sieve.from_Foldable $
165 Date.Interval.dom_slice
167 Filter_Date_Hour _ti -> s -- NOTE: no reducing at this level
168 Filter_Date_Minute _ti -> s -- NOTE: no reducing at this level
169 Filter_Date_Second _ti -> s -- NOTE: no reducing at this level
171 -- | Return given 'Map' with 'Map.slice' applied on it
172 -- to only get sub-'Map's filtering through given 'Reduce_Date',
173 -- also return derived 'Interval.Sieve.Sieve' used for the slicing.
174 map_date :: Simplified Reduce_Date -> Map Date x -> ([Map Date x], Interval.Sieve.Sieve Date)
177 case Map.interval m of
178 Nothing -> Interval.Sieve.empty
180 case simplified reducer of
181 Left tb -> sieve_date tb $ Interval.Sieve.singleton bounds
182 Right True -> Interval.Sieve.singleton bounds
183 Right False -> Interval.Sieve.empty in
184 (Map.slice sieve m, sieve)