module Dodge.DoubleTree where import Dodge.Data.DoubleTree import qualified Data.IntMap.Strict as IM import Control.Lens import Data.Bifunctor import Data.Monoid singleDT :: a -> DoubleTree a singleDT x = DT x [] [] singleLDT :: a -> LabelDoubleTree b a singleLDT x = LDT x [] [] ldtToDT :: LabelDoubleTree b a -> DoubleTree a ldtToDT (LDT x l r) = DT x (map (ldtToDT . snd) l) (map (ldtToDT . snd) r) -- propagate two functions down the links of an LDT tree -- which function is chosen depends on whether it is a left or right branch ldtPropagate :: (c -> b -> c) -> (c -> b -> c) -> c -> LabelDoubleTree b a -> LabelDoubleTree c a ldtPropagate lf rf = ildtPropagate (const lf) (const rf) -- Propgates a value (of type c) down the branches of the LDT. -- The value is updated according a "left" or "right" function (lf or rf), -- that acts on the parent value, the link, and the child value. -- For each node, the updated value is used to update a final value (of type d). ldtPropagateFold :: (c -> a -> b -> a -> c) -> (c -> a -> b -> a -> c) -> (c -> a -> d -> d) -> c -> LabelDoubleTree b a -> d -> d ldtPropagateFold lf rf up x (LDT v l r) = alaf Endo foldMap (\(s,y) -> ldtPropagateFold lf rf up (rf x v s (_ldtValue y)) y) r . alaf Endo foldMap (\(s,y) -> ldtPropagateFold lf rf up (lf x v s (_ldtValue y)) y) l . up x v -- Propgates a value (of type c) down the branches of the LDT. -- The value is updated according a "left" or "right" function (lf or rf), -- that acts on the parent value, the link, and the child value. -- For each node-tree, the updated value is used to update a final value (of type d). ldtPropagateFoldTree :: (c -> a -> b -> a -> c) -> (c -> a -> b -> a -> c) -> (c -> LabelDoubleTree b a -> d -> d) -> c -> LabelDoubleTree b a -> d -> d ldtPropagateFoldTree lf rf up x t@(LDT v l r) = alaf Endo foldMap (\(s,y) -> ldtPropagateFoldTree lf rf up (rf x v s (_ldtValue y)) y) r . alaf Endo foldMap (\(s,y) -> ldtPropagateFoldTree lf rf up (lf x v s (_ldtValue y)) y) l . up x t ildtPropagate :: (Int -> c -> b -> c) -> (Int -> c -> b -> c) -> c -> LabelDoubleTree b a -> LabelDoubleTree c a ildtPropagate lf rf x (LDT v l r) = LDT v (imap (go lf x) l) (imap (go rf x) r) where go f y i (z,t) = (f i y z, ildtPropagate lf rf (f i y z) t) ldtPropagateIndices :: LabelDoubleTree b a -> LabelDoubleTree b (a, [Either Int Int]) ldtPropagateIndices (LDT x l r) = LDT (x,[]) (imap (f Left) l) (imap (f Right) r) where f e i (y,t) = (y, second (e i:) <$> ldtPropagateIndices t) -- conceptually, in a tree growing from left to right, -- bottom -> top is equated with left -> right. -- this does not match with thinking of a list as top -> bottom, so take care doubleTreeToIndentList :: DoubleTree a -> [(a,Int,DoubleTreeNodeType)] doubleTreeToIndentList = dtIL DTRootNode dtIL :: DoubleTreeNodeType -> DoubleTree a -> [(a,Int,DoubleTreeNodeType)] dtIL nt (DT x l r) = map doindent (concat (headMap (dtIL DTBottomNode) (dtIL DTMidBelowNode) l)) ++ [(x,0,nt)] ++ map doindent (concat (lastMap (dtIL DTTopNode) (dtIL DTMidAboveNode) r)) where doindent (a,b,c) = (a,b+1,c) dtToAdjacency :: (a -> Int) -> DoubleTree a -> IM.IntMap [Int] dtToAdjacency f (DT x l r) = IM.insert (f x) (map g l <> map g r) . IM.unions $ map (dtToAdjacency f) $ l <> r where g = f . _dtValue dtToIntMapWithRoot :: (a -> Int) -> DoubleTree a -> IM.IntMap (Maybe Int, DoubleTree a) dtToIntMapWithRoot f t@(DT x l r) = IM.insert (f x) (Nothing, t) $ foldMap (dtToRootIntMap' (f x) f) $ l <> r dtToRootIntMap' :: Int -> (a -> Int) -> DoubleTree a -> IM.IntMap (Maybe Int, DoubleTree a) dtToRootIntMap' root f t@(DT x l r) = IM.insert (f x) (Just root, t) $ foldMap (dtToRootIntMap' root f) $ l <> r dtToUpDownAdj :: (a -> Int) -> DoubleTree a -> IM.IntMap ([Int],[Int]) dtToUpDownAdj f (DT x l r) = IM.insert (f x) (map g l , map g r) . IM.unions $ map (dtToUpDownAdj f) $ l <> r where g = f . _dtValue -- returns an adjacency map with oldest ancestor and direct parent if they exist -- and any left and right children dtToLRAdj :: (a -> Int) -> DoubleTree a -> IM.IntMap (Maybe (Int,Int),[Int],[Int]) dtToLRAdj f (DT x l r) = IM.insert i (Nothing,map g l , map g r) . IM.unions $ map (dtToAdjRootParent i i f) $ l <> r where i = f x g = f . _dtValue -- returns an adjacency map with oldest ancestor and direct parent if they exist -- and any left and right children -- allows to propagate failure in the index discovery dtToLRAdjEither :: (a -> Either String Int) -> DoubleTree a -> Either String (IM.IntMap (Maybe (Int,Int),[Int],[Int])) dtToLRAdjEither f (DT x l r) = do i <- f x l' <- mapM g l r' <- mapM g r childrenasnodes <- mapM (dtToAdjRootParentEither i i f) $ l <> r return $ IM.insert i (Nothing,l' , r') $ IM.unions childrenasnodes where g = f . _dtValue dtToAdjRootParent :: Int -> Int -> (a -> Int) -> DoubleTree a -> IM.IntMap (Maybe (Int,Int),[Int],[Int]) dtToAdjRootParent root par f (DT x l r) = IM.insert (f x) (Just (root,par),map g l , map g r) . IM.unions $ map (dtToAdjRootParent root (f x) f) $ l <> r where g = f . _dtValue dtToAdjRootParentEither :: Int -> Int -> (a -> Either String Int) -> DoubleTree a -> Either String (IM.IntMap (Maybe (Int,Int),[Int],[Int])) dtToAdjRootParentEither root par f (DT x l r) = do i <- f x l' <- mapM g l r' <- mapM g r childrenasnodes <- mapM (dtToAdjRootParentEither root i f) $ l <> r return $ IM.insert i (Just (root,par),l' , r') $ IM.unions childrenasnodes where g = f . _dtValue ldtToIM :: (a -> Int) -> LabelDoubleTree b a -> IM.IntMap (LabelDoubleTree b a) ldtToIM f t@(LDT x l r) = IM.insert (f x) t $ IM.unions $ map (ldtToIM f . snd) $ l <> r ldtToIndentList :: LabelDoubleTree b a -> [(a,Int,LabelDoubleTreeNodeType b)] ldtToIndentList = ldtIL LDTRootNode ldtIL :: LabelDoubleTreeNodeType b -> LabelDoubleTree b a -> [(a,Int,LabelDoubleTreeNodeType b)] ldtIL nt (LDT x l r) = map doindent (concat (headMap (\(lab,c) -> ldtIL (LDTBottomNode lab) c) (\(lab,c) -> ldtIL (LDTMidBelowNode lab) c) l ) ) ++ [(x,0,nt)] ++ map doindent (concat (lastMap (\(lab,c) -> ldtIL (LDTTopNode lab) c) (\(lab,c) -> ldtIL (LDTMidAboveNode lab) c) r ) ) where doindent (a,b,c) = (a,b+1,c) headMap :: (a -> b) -> (a -> b) -> [a] -> [b] headMap f g (x:xs) = f x : map g xs headMap _ _ [] = [] lastMap :: (a -> b) -> (a -> b) -> [a] -> [b] lastMap _ _ [] = [] lastMap f _ [x] = [f x] lastMap f g (x:xs) = g x : lastMap f g xs prettyDT :: (a -> String) -> DoubleTree a -> [String] prettyDT f (DT x l r) = concatMap (map ('/':) . prettyDT f) r ++ (f x : concatMap (map ('\\':) . prettyDT f) l) prettyLDT :: (a -> String) -> LabelDoubleTree b a -> [String] prettyLDT f (LDT x l r) = concatMap (map ('/':) . prettyLDT f . snd) r ++ (f x : concatMap (map ('\\':) . prettyLDT f . snd) l) ldtToLoc :: LabelDoubleTree b a -> LocationLDT b a ldtToLoc = LocLDT TopLDT -- should probably do tests for these locUp :: LocationLDT b a -> Maybe (LocationLDT b a) locUp (LocLDT TopLDT _) = Nothing locUp (LocLDT c@LeftwardLDT{} t) = Just $ LocLDT (_cldtUp c) (LDT (_cldtParent c) (_cldtCloseLeft c ++ ((_cldtLink c,t):_cldtCloseRight c)) (_cldtFarRight c)) locUp (LocLDT c@RightwardLDT{} t) = Just $ LocLDT (_cldtUp c) (LDT (_cldtParent c) (_cldtFarLeft c) (_cldtCloseLeft c ++ ((_cldtLink c,t):_cldtCloseRight c))) locToTop :: LocationLDT b a -> LocationLDT b a locToTop loc = maybe loc locToTop $ locUp loc --locToTop = fix $ \x -> fromMaybe x $ locUp x locLeftmost :: LocationLDT b a -> LocationLDT b a locLeftmost loc = maybe loc locLeftmost $ alaf Last foldMap Just $ locGoLeft loc locRightmost :: LocationLDT b a -> LocationLDT b a locRightmost loc = maybe loc locRightmost $ alaf First foldMap Just $ locGoRight loc -- should probably do tests for these locGoLeft :: LocationLDT b a -> [LocationLDT b a] locGoLeft (LocLDT c (LDT v l r)) = [ LocLDT (LeftwardLDT c closel v link closer r) t | (closel,(link,t),closer) <- locGoHelp id l] -- should probably do tests for these locGoRight :: LocationLDT b a -> [LocationLDT b a] locGoRight (LocLDT c (LDT v l r)) = [ LocLDT (RightwardLDT c l closel v link closer) t | (closel,(link,t),closer) <- locGoHelp id r] -- this seems like it might be very inefficient for large lists -- difference lists? locGoHelp :: (a -> b) -> [a] -> [([a],b,[a])] locGoHelp f = go [] where go cleft (y:ys) = (cleft,f y, ys) : go (cleft <> [y]) ys go _ [] = [] -- Propgates a value (of type c) down the branches of the ContextLDT. -- The value is updated according a "left" or "right" function (lf or rf), -- that acts on the parent value, the link, and the child value. -- For each context node, the updated value is used to update a final value (of type d). cldtPropagateFold :: (c -> a -> b -> a -> c) -> (c -> a -> b -> a -> c) -> (c -> LocationLDT b a -> d -> d) -> c -> LocationLDT b a -> d -> d cldtPropagateFold lf rf up x loc = alaf Endo foldMap (\(LocLDT con' t') -> cldtPropagateFold lf rf up (lf x (_cldtParent con') (_cldtLink con') (_ldtValue t')) (LocLDT con' t')) (locGoLeft loc) . alaf Endo foldMap (\(LocLDT con' t') -> cldtPropagateFold lf rf up (rf x (_cldtParent con') (_cldtLink con') (_ldtValue t')) (LocLDT con' t')) (locGoRight loc) . up x loc