1 -- | The whole point of this module is
2 -- to reach sub-linear time complexity
3 -- when filtering with 'Test_Bool'
4 -- over sorted inputs, doing this by:
6 -- 1. Deriving from a generic 'Test_Bool':
7 -- a specific 'Test_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 'Test_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 = Test_Bool Test_Date
45 dated :: t -> Maybe (Test_Bool Test_Date)
47 instance Dated Test_Date where
49 instance Transaction t
50 => Dated (Test_Transaction t) where
53 Test_Transaction_Date d -> Just d
56 -- | Return a 'Reduce_Date'
58 -- for the given 'Test_Bool' to filter.
59 bool_date :: Dated t => Test_Bool t -> Simplified Reduce_Date
61 simplify (maybe Any id $ go tst) (Nothing::Maybe Date)
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
112 Interval.Sieve.intersection s $
113 Interval.Sieve.singleton $
115 Test_Ord_Lt o -> fromJust $ Interval.interval (Interval.low bounds) (Interval.Limit Interval.Out o)
116 Test_Ord_Le o -> fromJust $ Interval.interval (Interval.low bounds) (Interval.Limit Interval.In o)
117 Test_Ord_Eq o -> Interval.point o
118 Test_Ord_Ge o -> fromJust $ Interval.interval (Interval.Limit Interval.In o) (Interval.high bounds)
119 Test_Ord_Gt o -> fromJust $ Interval.interval (Interval.Limit Interval.Out o) (Interval.high bounds)
120 Test_Ord_Any -> bounds
121 Test_Date_Year (Test_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 Test_Date_Month (Test_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 Test_Date_DoM (Test_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 Test_Date_Hour _ti -> s -- NOTE: no reducing at this level
168 Test_Date_Minute _ti -> s -- NOTE: no reducing at this level
169 Test_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)