module TrieMap.RadixTrie (RadixTrie) where
import Control.Applicative hiding (Alternative(..))
import Control.Monad
import Data.Foldable
import Data.Traversable
import Data.Monoid
import Data.Maybe
import Data.Ord
import Data.Sequence (Seq, (|>))
import qualified Data.Sequence as Seq
import TrieMap.MapTypes
import TrieMap.TrieAlgebraic
import TrieMap.Applicative
import Prelude hiding (null, foldr, all)
instance (Eq k, Eq v, TrieKey k m) => Eq (Edge k m v) where
Edge ks1 v1 ts1 == Edge ks2 v2 ts2 = ks1 == ks2 && v1 == v2 && assocsAlg ts1 == assocsAlg ts2
instance (Ord k, Ord v, TrieKey k m) => Ord (Edge k m v) where
Edge ks1 v1 ts1 `compare` Edge ks2 v2 ts2 =
compare ks1 ks2 `mappend` compare v1 v2 `mappend` comparing assocsAlg ts1 ts2
deriving instance (Eq k, Eq v, TrieKey k m) => Eq (RadixTrie k m v)
deriving instance (Ord k, Ord v, TrieKey k m) => Ord (RadixTrie k m v)
deriving instance (Show k, Show v, Functor m, Show (m String)) => Show (RadixTrie k m v)
instance (Show k, Show v, Functor m, Show (m String)) => Show (Edge k m v) where
show (Edge k v ts) = "Edge " ++ show k ++ " " ++ show v ++ " " ++ show (fmap show ts)
instance (Ord k, TrieKey k m) => TrieKey [k] (RadixTrie k m) where
emptyAlg = Radix Nothing
nullAlg = isNothing . unRad
getSingleAlg (Radix e) = e >>= getSingleEdge
guardNullAlg (Radix e) = do e <- guardNullEdge =<< e
return (Radix (Just e))
lookupAlg ks = unRad >=> lookupEdge (==) ks
alterLookupAlg f k = fmap Radix .
maybe (fmap (maybeSingleEdge k) $ f Nothing)
(alterLookupEdge (==) f k) . unRad
foldWithKeyAlg f z = foldr (flip (foldWithKeyEdge f)) z . unRad
mapMaybeAlg f (Radix e) = Radix (e >>= mapMaybeEdge f)
mapEitherAlg f (Radix Nothing) = (emptyAlg, emptyAlg)
mapEitherAlg f (Radix (Just e)) = (Radix e1, Radix e2)
where (e1, e2) = mapEitherEdge f e
mapAppAlg f = fmap Radix . traverse (mapAppEdge f) . unRad
unionMaybeAlg f (Radix e1) (Radix e2) = Radix (unionMaybe (unionMaybeEdge f) e1 e2)
intersectAlg f (Radix e1) (Radix e2) = Radix (intersectMaybe (intersectEdge f) e1 e2)
differenceAlg f (Radix e1) (Radix e2) = Radix (differenceMaybe (differenceEdge f) e1 e2)
getMinAlg (Radix e) = fmap (fmap Radix . getMinEdge) e
getMaxAlg (Radix e) = fmap (fmap Radix . getMaxEdge) e
fromListAlg f xs = Radix (edgeFromList f xs)
fromAscListAlg f xs = Radix (edgeFromAscList f xs)
fromDistAscListAlg = fromAscListAlg (\ _ v _ -> v)
isSubmapAlg (<=) (Radix e1) (Radix e2) = isSubmapAlg (isSubmapEdge (<=)) e1 e2
valid (Radix e) = maybe True validEdge e
splitLookupAlg _ _ (Radix Nothing) = (Radix Nothing, Nothing, Radix Nothing)
splitLookupAlg f k (Radix (Just e)) = case splitEdge f k e of
(eL, ans, eR) -> (Radix eL, ans, Radix eR)
lookupEdge :: TrieKey k m => (k -> k -> Bool) -> [k] -> Edge k m v -> Maybe v
lookupEdge (==) ks (Edge ls v ts) = procEdge ks ls where
procEdge (k:ks) (l:ls)
| k == l = procEdge ks ls
procEdge (k:ks) [] = lookupAlg k ts >>= lookupEdge (==) ks
procEdge [] [] = v
procEdge _ _ = Nothing
edgeFromList :: (Eq k, TrieKey k m) => ([k] -> v -> v -> v) -> [([k], v)] -> MEdge k m v
edgeFromList f xs = guardNullEdge $ Edge [] v0 $ mapMaybeAlg (\ k -> edgeFromList (f . (k:))) $ fromListAlg (const (flip (++))) ys
where part ([], v) (v0, ys) = (Just $ maybe v (flip (f []) v) v0, ys)
part (k:ks, v) (v0, ys) = (v0, (k, [(ks, v)]):ys)
(v0, ys) = foldr part (Nothing, []) xs
edgeFromAscList :: (Eq k, TrieKey k m) => ([k] -> v -> v -> v) -> [([k], v)] -> MEdge k m v
edgeFromAscList _ [] = Nothing
edgeFromAscList f xs = Just $ case groupHead f xs of
(Nothing, [(k, ~(Edge ks v ts))])
-> Edge (k:ks) v ts
(ans, xs') -> Edge [] ans (fromDistAscListAlg xs')
groupHead :: (Eq k, TrieKey k m) => ([k] -> v -> v -> v) -> [([k], v)] -> (Maybe v, [(k, Edge k m v)])
groupHead f (([], v):xs) = case groupHead f xs of
(v', ans) -> (Just $ maybe v (f [] v) v', ans)
groupHead f ((k:ks, v):xs) = (Nothing, groupHead' k (Seq.singleton (ks, v)) xs) where
groupHead' k0 xs ((k:ks, v):ys)
| k == k0 = groupHead' k0 (xs |> (ks, v)) ys
| otherwise = (k0, fromJust $ edgeFromAscList (f . (k0:)) (toList xs)):groupHead' k (Seq.singleton (ks, v)) ys
groupHead' k0 xs [] = [(k0, fromJust $ edgeFromAscList (f . (k0:)) (toList xs))]
groupHead' _ _ _ = error "Violation of ascending invariant!"
groupHead _ [] = (Nothing, [])
maybeSingleEdge :: TrieKey k m => [k] -> Maybe v -> MEdge k m v
maybeSingleEdge ks = fmap (\ v -> Edge ks (Just v) emptyAlg)
getSingleEdge :: (TrieKey k m) => Edge k m v -> Maybe ([k], v)
getSingleEdge (Edge ks (Just v) ts)
| nullAlg ts = Just (ks, v)
getSingleEdge (Edge ks Nothing ts) = do
(x, e') <- getSingleAlg ts
(xs, v) <- getSingleEdge e'
return (ks ++ x:xs, v)
getSingleEdge _ = Nothing
guardNullEdge :: TrieKey k m => Edge k m v -> MEdge k m v
guardNullEdge (Edge ks Nothing ts)
| nullAlg ts = Nothing
| Just (x, Edge xs v ts') <- getSingleAlg ts
= Just (Edge (ks ++ x:xs) v ts')
guardNullEdge e = Just e
alterLookupEdge :: (TrieKey k m) => (k -> k -> Bool) ->
(Maybe v -> (a, Maybe v)) -> [k] -> Edge k m v -> (a, MEdge k m v)
alterLookupEdge (==) f ks0 e@(Edge ls0 v ts) = procEdge 0 ks0 ls0 where
procEdge i _ _ | i `seq` False = undefined
procEdge i (k:ks) (l:ls)
| k == l = procEdge (i+1) ks ls
| otherwise = fmap (Just . g) $ f Nothing
where g Nothing = e
g (Just v') = Edge (take i ks0) Nothing $
fromListAlg' [(k, Edge ks (Just v') emptyAlg), (l, Edge ls v ts)]
procEdge i (k:ks) [] = proc (alterLookupAlg g k ts) where
g Nothing = maybeSingleEdge ks <$> f Nothing
g (Just e') = alterLookupEdge (==) f ks e'
proc = fmap (guardNullEdge . Edge ls0 v)
procEdge i [] (l:ls) = fmap (Just . g) $ f Nothing
where g Nothing = e
g (Just v') = Edge ks0 (Just v') $ insertAlg l (Edge ls v ts) emptyAlg
procEdge i [] [] = (ans, guardNullEdge (Edge ks0 fv ts))
where (ans, fv) = f v
foldWithKeyEdge :: TrieKey k m => ([k] -> v -> x -> x) -> x -> Edge k m v -> x
foldWithKeyEdge f z (Edge ks v ts) =
foldr (f ks) (foldWithKeyAlg (\ x -> flip (foldWithKeyEdge (\ xs -> f (ks ++ x:xs)))) z ts) v
mapMaybeEdge :: (TrieKey k m) => ([k] -> v -> Maybe w) -> Edge k m v -> MEdge k m w
mapMaybeEdge f (Edge ks v ts) = guardNullEdge $
Edge ks (join $ traverse (f ks) v) (mapMaybeAlg (\ x -> mapMaybeEdge (\ xs -> f (ks ++ x:xs))) ts)
mapEitherEdge :: TrieKey k m => ([k] -> a -> Either b c) -> Edge k m a -> (MEdge k m b, MEdge k m c)
mapEitherEdge f (Edge ks v ts) =
(guardNullEdge $ Edge ks vL tsL, guardNullEdge $ Edge ks vR tsR)
where (vL, vR) = case fmap (f ks) v of
Nothing -> (Nothing, Nothing)
Just (Left v) -> (Just v, Nothing)
Just (Right v) -> (Nothing, Just v)
ts' = mapWithKeyAlg (\ x -> mapEitherEdge (\ xs -> f (ks ++ x:xs))) ts
tsL = mapMaybeAlg (const fst) ts'
tsR = mapMaybeAlg (const snd) ts'
mapAppEdge :: (Applicative f, TrieKey k m) => ([k] -> v -> f w) -> Edge k m v -> f (Edge k m w)
mapAppEdge f (Edge ks v ts) = liftA2 (Edge ks) (traverse (f ks) v) (mapAppAlg (\ x -> mapAppEdge (\ xs -> f (ks ++ x:xs))) ts)
unionMaybeEdge :: (Eq k, TrieKey k m) => ([k] -> v -> v -> Maybe v) -> Edge k m v -> Edge k m v -> MEdge k m v
unionMaybeEdge f (Edge ks0 vK tsK) (Edge ls0 vL tsL) = procEdge 0 ks0 ls0 where
procEdge i _ _ | i `seq` False = undefined
procEdge i (k:ks) (l:ls)
| k == l = procEdge (i+1) ks ls
| otherwise = Just $ Edge (take i ks0) Nothing $ fromListAlg' [(k, Edge ks vK tsK), (l, Edge ls vL tsL)]
procEdge _ [] (l:ls) = guardNullEdge $ Edge ks0 vK $ alterAlg g l tsK
where g Nothing = Just (Edge ls vL tsL)
g (Just e') = unionMaybeEdge (\ ls' -> f (ks0 ++ l:ls')) e' (Edge ls vL tsL)
procEdge _ (k:ks) [] = guardNullEdge $ Edge ls0 vL $ alterAlg g k tsL
where g Nothing = Just $ Edge ks vK tsK
g (Just e') = unionMaybeEdge (\ ks' -> f (ls0 ++ k:ks')) (Edge ks vK tsK) e'
procEdge _ [] [] = guardNullEdge $ Edge ks0 (unionMaybe (f ks0) vK vL) $
unionMaybeAlg (\ x -> unionMaybeEdge (\ xs -> f (ks0 ++ x:xs))) tsK tsL
intersectEdge :: (Eq k, TrieKey k m) => ([k] -> a -> b -> Maybe c) -> Edge k m a -> Edge k m b -> MEdge k m c
intersectEdge f (Edge ks0 vK tsK) (Edge ls0 vL tsL) = procEdge ks0 ls0 where
procEdge (k:ks) (l:ls)
| k == l = procEdge ks ls
| otherwise = Nothing
procEdge (k:ks) [] = do
e' <- lookupAlg k tsL
Edge xs vX tsX <- intersectEdge (\ ks' -> f (ls0 ++ k:ks')) (Edge ks vK tsK) e'
return (Edge (ls0 ++ k:xs) vX tsX)
procEdge [] (l:ls) = do
e' <- lookupAlg l tsK
Edge xs vX tsX <- intersectEdge (\ ls' -> f (ks0 ++ l:ls')) e' (Edge ls vL tsL)
return (Edge (ks0 ++ l:xs) vX tsX)
procEdge [] [] = guardNullEdge $ Edge ks0 (intersectMaybe (f ks0) vK vL) $
intersectAlg (\ x -> intersectEdge (\ xs -> f (ks0 ++ x:xs))) tsK tsL
differenceEdge :: (Eq k, TrieKey k m) => ([k] -> v -> w -> Maybe v) -> Edge k m v -> Edge k m w -> MEdge k m v
differenceEdge f e@(Edge ks0 vK tsK) (Edge ls0 vL tsL) = procEdge ks0 ls0 where
procEdge (k:ks) (l:ls)
| k == l = procEdge ks ls
procEdge (k:ks) []
| Just e' <- lookupAlg k tsL
= do Edge xs vX tsX <- differenceEdge (\ ks' -> f (ls0 ++ k:ks')) (Edge ks vK tsK) e'
return (Edge (ls0 ++ k:xs) vX tsX)
procEdge [] (l:ls) = guardNullEdge $ Edge ks0 vK $ alterAlg g l tsK
where g Nothing = Nothing
g (Just e') = differenceEdge (\ ls' -> f (ks0 ++ l:ls')) e' (Edge ls vL tsL)
procEdge [] [] = guardNullEdge $ Edge ks0 (differenceMaybe (f ks0) vK vL) $
differenceAlg (\ x -> differenceEdge (\ xs -> f (ks0 ++ x:xs))) tsK tsL
procEdge _ _ = Just e
getMinEdge :: TrieKey k m => Edge k m v -> (([k], v), MEdge k m v)
getMinEdge (Edge ks (Just v) ts) = ((ks, v), guardNullEdge $ Edge ks Nothing ts)
getMinEdge (Edge ks _ ts)
| Just ((l, e), ts') <- getMinAlg ts, ((ls, v), e') <- getMinEdge e
= ((ks ++ l:ls, v), guardNullEdge $ Edge ks Nothing $ maybe ts' (\ e' -> snd $ updateMinAlg (\ _ _ -> (False, Just e')) ts) e')
getMinEdge _ = error "Uncompacted edge"
getMaxEdge :: TrieKey k m => Edge k m v -> (([k], v), MEdge k m v)
getMaxEdge (Edge ks v0 ts)
| Just ((l, e), ts') <- getMaxAlg ts, ((ls, v), e') <- getMaxEdge e
= ((ks ++ l:ls, v), guardNullEdge $ Edge ks v0 $ maybe ts' (\ e' -> snd $ updateMaxAlg (\ _ _ -> (False, Just e')) ts) e')
getMaxEdge (Edge ks (Just v) ts) = ((ks, v), guardNullEdge $ Edge ks Nothing ts)
getMaxEdge _ = error "Uncompacted edge"
updateMinEdge :: TrieKey k m => ([k] -> v -> (Bool, Maybe v)) -> Edge k m v -> (Bool, MEdge k m v)
updateMinEdge f (Edge ks (Just v) ts) = fmap (\ v' -> guardNullEdge $ Edge ks v' ts) (f ks v)
updateMinEdge f (Edge ks Nothing ts)
= fmap (guardNullEdge . Edge ks Nothing) $ updateMinAlg (\ l -> updateMinEdge (\ ls -> f (ks ++ l:ls))) ts
updateMaxEdge :: TrieKey k m => ([k] -> v -> (Bool, Maybe v)) -> Edge k m v -> (Bool, MEdge k m v)
updateMaxEdge f (Edge ks (Just v) ts)
| nullAlg ts = fmap (\ v' -> guardNullEdge $ Edge ks v' ts) (f ks v)
updateMaxEdge f (Edge ks v ts) =
fmap (guardNullEdge . Edge ks v) $ updateMaxAlg (\ l -> updateMaxEdge (\ ls -> f (ks ++ l:ls))) ts
isSubmapEdge :: TrieKey k m => (a -> b -> Bool) -> Edge k m a -> Edge k m b -> Bool
isSubmapEdge (<=) (Edge ks vK tsK) (Edge ls vL tsL) = procEdge ks ls where
procEdge (k:ks) (l:ls)
| k == l = procEdge ks ls
procEdge (k:ks) []
| Just e <- lookupAlg k tsL
= isSubmapEdge (<=) (Edge ks vK tsK) e
procEdge [] []
| Nothing <- vK = isSubmapAlg (isSubmapEdge (<=)) tsK tsL
| Just x <- vK, Just y <- vL, x <= y
= isSubmapAlg (isSubmapEdge (<=)) tsK tsL
procEdge _ _ = False
validEdge :: TrieKey k m => Edge k m v -> Bool
validEdge (Edge _ Nothing m)
| nullAlg m = False
| Just{} <- getSingleAlg m
= False
validEdge (Edge _ _ m)
= valid m && all validEdge m
splitEdge :: (Ord k, TrieKey k m) => (a -> (Maybe a, Maybe b, Maybe a)) -> [k] -> Edge k m a -> (MEdge k m a, Maybe b, MEdge k m a)
splitEdge f ks0 (Edge ls0 v ts) = procEdge ks0 ls0 where
procEdge (k:ks) (l:ls) = case compare k l of
LT -> (Nothing, Nothing, Just (Edge ls0 v ts))
EQ -> procEdge ks ls
GT -> (Just (Edge ks0 v ts), Nothing, Nothing)
procEdge (k:ks) [] = case splitLookupAlg (splitEdge f ks) k ts of
(tsL, ans, tsR) -> (guardNullEdge $ Edge ls0 Nothing tsL, ans, guardNullEdge $ Edge ls0 v tsR)
procEdge [] (l:ls) = (Nothing, Nothing, Just $ Edge ls0 v ts)
procEdge [] []
| Just v <- v, (vL, ans, vR) <- f v
= (fmap (\ v' -> Edge ls0 (Just v') emptyAlg) vL, ans,
guardNullEdge $ Edge ls0 vR ts)
| otherwise = (Nothing, Nothing, Just (Edge ls0 v ts))