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)
29 import Data.Either (Either(..))
30 import Data.Functor (Functor(..), (<$>))
31 import Data.Maybe (Maybe(..), fromJust, fromMaybe)
32 import qualified Data.List
33 import Data.Map.Strict (Map)
34 import Prelude (($), (.), uncurry)
36 import Hcompta.Date (Date)
37 import qualified Hcompta.Date as Date
38 import qualified Hcompta.Date.Interval as Date.Interval
40 import qualified Hcompta.Lib.Interval as Interval
41 import qualified Hcompta.Lib.Interval.Sieve as Interval.Sieve
42 import qualified Hcompta.Lib.Map.Strict as Map
46 type Reduce_Date = Filter_Bool Filter_Date
49 dated :: t -> Maybe (Filter_Bool Filter_Date)
51 instance Dated Filter_Date where
53 instance Transaction t
54 => Dated (Filter_Transaction t) where
57 Filter_Transaction_Date d -> Just d
60 -- | Return a 'Reduce_Date'
62 -- for the given 'Filter_Bool' to filter.
63 bool_date :: Dated t => Filter_Bool t -> Simplified Reduce_Date
65 simplify (fromMaybe Any $ go tst)
74 (Not t) -> Not <$> go t
76 case (go t0, go t1) of
77 (Nothing, Nothing) -> Just $ Any
78 (Nothing, Just td) -> Just $ td
79 (Just td, Nothing) -> Just $ td
80 (Just td0, Just td1) -> Just $ And td0 td1
82 case (go t0, go t1) of
83 (Just td0, Just td1) -> Just $ Or td0 td1
86 -- | Return given 'Interval.Sieve.Sieve' 'Date'
87 -- with given 'Reduce_Date' applied on it.
89 -- WARNING: no reducing is done below the day level.
92 -> Interval.Sieve.Sieve Date
93 -> Interval.Sieve.Sieve Date
95 case Interval.Sieve.interval si of
97 Just bounds -> go bounds tb si
103 Interval.Sieve.complement_with bounds $
106 Interval.Sieve.intersection
115 Filter_Date_UTC to ->
116 Interval.Sieve.intersection s $
117 Interval.Sieve.singleton $
119 Filter_Ord Lt o -> fromJust $ Interval.interval (Interval.low bounds) (Interval.Limit Interval.Out o)
120 Filter_Ord Le o -> fromJust $ Interval.interval (Interval.low bounds) (Interval.Limit Interval.In o)
121 Filter_Ord Eq o -> Interval.point o
122 Filter_Ord Ge o -> fromJust $ Interval.interval (Interval.Limit Interval.In o) (Interval.high bounds)
123 Filter_Ord Gt o -> fromJust $ Interval.interval (Interval.Limit Interval.Out o) (Interval.high bounds)
124 Filter_Ord_Any -> bounds
125 Filter_Date_Year (Filter_Interval_In i) ->
126 Interval.Sieve.intersection s $
127 Interval.Sieve.singleton $
128 fromJust $ uncurry Interval.interval $
131 Interval.Unlimited_low -> Interval.low bounds
132 Interval.Limited l -> l
133 Interval.Unlimited_high -> Interval.high bounds) $
134 (fmap Interval.low *** fmap Interval.high) $
135 join (***) (fmap Date.Interval.year . Interval.limit) $
137 Filter_Date_Month (Filter_Interval_In i) ->
138 case Interval.Sieve.interval s of
141 Interval.Sieve.intersection s $
142 Interval.Sieve.from_Foldable $
152 Date.Interval.month_slice
154 Filter_Date_DoM (Filter_Interval_In i) ->
155 case Interval.Sieve.interval s of
158 Interval.Sieve.intersection s $
159 Interval.Sieve.from_Foldable $
169 Date.Interval.dom_slice
171 Filter_Date_Hour _ti -> s -- NOTE: no reducing at this level
172 Filter_Date_Minute _ti -> s -- NOTE: no reducing at this level
173 Filter_Date_Second _ti -> s -- NOTE: no reducing at this level
175 -- | Return given 'Map' with 'Map.slice' applied on it
176 -- to only get sub-'Map's filtering through given 'Reduce_Date',
177 -- also return derived 'Interval.Sieve.Sieve' used for the slicing.
178 map_date :: Simplified Reduce_Date -> Map Date x -> ([Map Date x], Interval.Sieve.Sieve Date)
181 case Map.interval m of
182 Nothing -> Interval.Sieve.empty
184 case simplified reducer of
185 Left tb -> sieve_date tb $ Interval.Sieve.singleton bounds
186 Right True -> Interval.Sieve.singleton bounds
187 Right False -> Interval.Sieve.empty in
188 (Map.slice sieve m, sieve)