Advertisement
levkin

find loops in graph

Oct 31st, 2011
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haskell 10.35 KB | None | 0 0
  1. {-# LANGUAGE DisambiguateRecordFields,ViewPatterns #-}
  2. import Data.List
  3. import Control.Monad
  4. import Control.Monad.State
  5. import Debug.Trace
  6. import qualified Data.IntMap as IntMap
  7. {-
  8.  
  9.   Input : List of int
  10.           Predicate : a->b->Bool
  11.  
  12.   Output  : type G a = (a, [G a]) : result = [G a] such that
  13.     for each m in result (snd m) == filter (fst m) result
  14.            
  15.   Additional question : How to "show" cyclic structures . Deriving Show will print indefinetly
  16.   show structure should start marking already visited nodes . This internal info may possibly be not shown
  17.  
  18. -}
  19.  
  20. -- Need to build instance of show , since this is cyclic structure
  21. data LoopDetect  = LD {  visited :: [Int] , isLoop :: Bool } deriving (Show)
  22. data (Show a,Eq a) => G a = G {val :: (a, [G a]) , idx :: Int , foundLoops :: [Int] } deriving (Eq)
  23. type Pred a = a -> a -> Bool
  24.  
  25. type StMon a = State LoopDetect (G a)
  26. type St a = ((G a),LoopDetect)
  27.  
  28. -- Build list , by tying the knot
  29. -- There is a problem of printing cyclic structure
  30. -- List (first argument) should be unique
  31.  
  32. func :: (Show a,Eq a) => [a] -> Pred a -> [G a]
  33. func lst pred = res_lst_with_loops where
  34.   tmp_lst =  zip lst j
  35.   ap2' f x y = f x y
  36.  ap3' f x y z = f x y z
  37.  
  38.   -- Build lazy infinite list of LD
  39.   initLDlst = zipWith3 ap2' (repeat LD)  (repeat []) (repeat False)
  40.  res_lst = zipWith4 ap3' (repeat G) tmp_lst [0..] (repeat [])-- Convert tuple to G datatype
  41.  
  42.   -- k list of func (a->Bool)
  43.   -- where each function has it's first argument injected
  44.   j = helper [] res_lst lst  
  45.  
  46.  
  47.  
  48.  
  49.   helper acc _ [] = reverse acc -- Termination condition
  50.   helper acc glist lst@(x:xs) = helper (subList:acc) glist xs where
  51.     subList = filter ((pred x) . fst . val) glist
  52.     -- Here update list of loops
  53.     --stateUpdate = detectLoops x -- Will update visited
  54.      
  55.  
  56.   --res_lst_with_loops = seq res_lst (findLoops res_lst)
  57.   --res_lst_with_loops = findLoops res_lst
  58.   res_lst_with_loops = trace ((++) "Initial res_lst = " $! seq res_lst show res_lst ) $! findLoops res_lst
  59.  
  60. -- End of func :: [a] -> Pred a -> [G a]
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67. --currNodeUpd :: (Show a , Eq a) => (G a) -> (LoopDetect -> (G a,LoopDetect))
  68. currNodeUpd :: (Show a , Eq a) => (G a) -> State LoopDetect (G a)
  69. currNodeUpd entry = state resFunc where
  70.   _idx = idx entry
  71.   resFunc st' = (entry,newSt) where
  72.    --newSt = LD (_idx : visited st') (loops st') -- First version --> Don't remove state of loops
  73.     -- Adding one node can only close one loop . -- Looks reasonable , but need to prove
  74.     -- But every node can be part of multiple loops . Thus foundLoops field is a list
  75.     newSt = LD (_idx : visited st') (isLoop st') -- Loops should be empty . Possible refactoring --> Convert to boolean
  76.  
  77. nextNodeJoinVis :: (Show a , Eq a) => LoopDetect -> (G a) -> State LoopDetect (G a)
  78. nextNodeJoinVis currSt entry = state resFunc where
  79.   _idx = idx entry
  80.   resFunc st' = (entry,newSt) where
  81.    --newSt = LD (_idx : visited st') (loops st') -- First version --> Don't remove state of loops
  82.     -- Adding one node can only close one loop . -- Looks reasonable , but need to prove
  83.     -- But every node can be part of multiple loops . Thus foundLoops field is a list
  84.     newSt = LD (union  (visited st') (visited currSt)) (isLoop st')
  85. -- Update state of the next node --> Check for loop
  86. --
  87. --nextNodeUpd :: (Show a , Eq a) => (G a) -> (LoopDetect -> (G a,LoopDetect))
  88. nextNodeUpd :: (Show a , Eq a) => (G a) -> State LoopDetect (G a)
  89. nextNodeUpd entry = state resFunc where
  90.   _idx = idx entry
  91.   resFunc st' = (newEntry,newSt) where
  92.    _vis = visited st'
  93.     _loopFound = _idx `elem` _vis
  94.     _newLoops = if (_loopFound) then (_idx:foundLoops entry) else foundLoops entry
  95.     newEntry = G { val = val entry , idx = idx entry , foundLoops = _newLoops }
  96.     newSt = LD (_vis) (_idx `elem` _vis)
  97.  
  98. -- Problem :
  99. -- Given no defined root --> Not a tree . I may traverse nodes twice
  100. -- Once when iterating through list of nodes
  101. -- and second time , when walking through links
  102. -- Given I am 'tying the knot' I should not return for second pass
  103.  
  104. -- Assumption :
  105. --  Every node should be visited at least once
  106. --  even in presence of loops . Thus we may pass all nodes and mark as visited              
  107.  
  108.  
  109.  
  110.  
  111.  
  112. findLoops :: (Show a,Eq a) => [G a] -> [G a]
  113. findLoops lst = newLst where
  114.   -- Build auxillary map to remove already visited
  115.  
  116.   --nodeMap = IntMap.fromList $ zip (map idx lst) lst -- Build map of unvisited nodes
  117.   nodeMap = trace "Print nodeMap in findLoops " $! IntMap.fromList $! seq lst zip (map idx lst) lst -- Build map of unvisited nodes
  118.   initSTvals = trace "Init st vals = " $! IntMap.fromList $! zip (map idx $! lst) (map (\x -> (x,(LD [] False)) ) $! lst) -- Build default state map
  119.  
  120.   --newLst = map (fst . snd ) $! IntMap.toList $! snd $! seq nodeMap fl' nodeMap $! initSTvals -- Map of State monad to traverse . Key is node idx
  121.   newLst = map (fst . snd ) $! IntMap.toList $! snd $! (seq nodeMap  fl' $! trace "Node map is " $! nodeMap) $! initSTvals -- Map of State monad to traverse . Key is node idx
  122.  
  123.  
  124.  
  125.  --fl' :: (Show a,Eq a) => IntMap.IntMap (G a) -> [G a] -> IntMap.IntMap (State LoopDetect (G a)) -> IntMap.IntMap (G a)
  126.   -- fl' ::
  127.   --fl' :: (Show a,Eq a) => IntMap.IntMap (G a) -> IntMap.IntMap (St a) -> (IntMap.IntMap (G a),IntMap.IntMap (St a))
  128.   fl' :: (Show a,Eq a) => IntMap.IntMap (G a) -> IntMap.IntMap (St a) -> (IntMap.IntMap (G a),IntMap.IntMap (St a))
  129.  
  130.  -- Termination case : All nodes are already traversed
  131.  fl' not_visited  stateMap | IntMap.null not_visited = result
  132.                             | otherwise = (newStateMap,new_not_visited) where
  133.       -- Run state
  134.       initSt = LD [] False
  135.       -- Apply runState for a map and get last value
  136.       -- For each entry result is already visited
  137.       result = (IntMap.empty,stateMap)
  138.     -- General case : At least one node to traverse
  139.      
  140.       pair = head $ IntMap.toList not_visited
  141.       key = fst pair
  142.       --x = snd pair
  143.       x = trace "Current x = " $ seq pair snd pair
  144.  
  145.       -- How to build state transformer
  146.       _idx = idx x  
  147.       _chLst = (snd . val) x
  148.  
  149.       (_newStateMap,_new_not_visited) = fl'' x stateMap not_visited -- Process single node
  150.       (newStateMap,new_not_visited) = fl' _new_not_visited _newStateMap -- Process remainder
  151.  
  152.        
  153.  
  154.  
  155.      -- Process children . Perform depth next step
  156.      -- Check state of children
  157.    
  158.  
  159.   -- Update state of a sub graph , taking as a first node some node
  160.  fl'' :: (Eq a, Show a) => (G a) -> IntMap.IntMap (St a) -> IntMap.IntMap (G a) -> (IntMap.IntMap (St a),IntMap.IntMap (G a))
  161.    
  162.   -- Update due to a single state
  163.  fl'' x stateMap (IntMap.null -> True) = (stateMap,IntMap.empty) -- Process empty not visited map
  164.  fl'' x stateMap nonVisited = (newStateMap,newNonVisited) where
  165.      
  166.      --_idx = idx x
  167.      _idx = trace "_idx = " $ seq x idx x
  168.      _children = map idx  ((snd . val) x)
  169.      (currVal,currSt) =  (IntMap.!) stateMap _idx
  170.  
  171.      -- Set update state as visited
  172.      (currVal_1,currSt_1) =  (flip runState currSt $ (return currVal) >>= currNodeUpd)
  173.  
  174.      -- Check every child to be a loop
  175.      -- first I apply runState on state of child + and value of node . I apply it for
  176.      
  177.      --(currVal_2,currSt_2) = flip runState currSt_2 $ foldl' gg (return currVal_2) $ map (\x -> (IntMap.!) stateMap x) $ _children where
  178.  
  179.       (currVal_2,currSt_2) = flip runState currSt_1 $ foldl' gg (return currVal_1)  _children where
  180.          gg :: (Eq a,Show a) => StMon a -> Int -> StMon a
  181.          gg _jj _idx1 = result where
  182.            (_,chSt) =  (IntMap.!) stateMap _idx1
  183.            result = return $ fst $ flip runState chSt $ _jj >>= nextNodeUpd  
  184.  
  185.      -- notLoopChildrenIdx =  filter (\j -> notElem j $ foundLoops currVal_2 )   _children
  186.      notLoopChildrenIdx =  filter (\j -> notElem j $ foundLoops currVal_2 ) $ seq _children $ trace "\nPrint _children\n"  _children
  187.      notLoopChildren =  map (fst . ((IntMap.!) _newStateMap_2)) $ trace "\nPrint not loop index " notLoopChildrenIdx
  188.  
  189.  
  190.       -- Update StateMap with current entry
  191.      _newStateMap_1 = IntMap.adjust (\_ -> (currVal_2,currSt_2)) _idx stateMap
  192.  
  193.  
  194.      -- Update state of each non loop child with visited node
  195.      _newStateMap_2 = foldl' hh _newStateMap_1 notLoopChildrenIdx where
  196.         --hh :: IntMap.IntMap (St a) -> Int -> IntMap.IntMap (St a)
  197.         hh _map _idx = _newMap where
  198.           (prevVal,prevSt) = _map IntMap.! _idx  -- Fetch previous value
  199.           (tmpVal,tmpSt) = flip runState prevSt $ return prevVal >>= (nextNodeJoinVis currSt_2)  
  200.           _newMap = IntMap.adjust (\_ -> (tmpVal,tmpSt)) _idx stateMap
  201.            
  202.        
  203.        
  204.        
  205.        
  206.  
  207.        -- Remove current entry from not visited
  208.       _newNonVisited = IntMap.delete _idx nonVisited
  209.  
  210.       -- Apply this only to children not creating loops
  211.       (newStateMap,newNonVisited) = foldl' kk ((trace ("Print new state map" ++ show _newStateMap_2 ++ "\n\n") _newStateMap_2),_newNonVisited) notLoopChildren where
  212.        kk y x  = fl'' x (fst y) (snd y)
  213.  
  214.       -- Recursive call of fl'' to a children
  215.  
  216. -- Print graph
  217. printGraph :: (Show a,Eq a) => G a -> String
  218. printGraph entry
  219.  | (snd . val) entry == [] =
  220.    prefix ++ suffix
  221.  | otherwise = result where
  222.    result = prefix ++ body ++ suffix
  223.    index_ :: Int
  224.    index_ = idx entry
  225.    prefix = "G {" ++ "val = " ++ "(" ++  (show $ (fst . val) entry) ++ "," ++ "["
  226.    suffix = "])," ++ "idx = " ++ (show $ index_ ) ++ ",foundLoops = " ++ (show $ foundLoops entry) ++  " }"
  227.  
  228.    
  229.    -- For each step of traversal
  230.    {-
  231.     - Loops detection is created once
  232.     - Thus , show should operate on ready foundLoops field  
  233.     - for now check for each element of sons' list whether it's
  234.     - already visited . Then body should reflect G a and word LOOP = <loop entry index>
  235.     -}
  236.    
  237.    -- Print all children
  238. --    chLst = (snd . val) entry
  239. --    body = foldl' kk "" chLst where
  240. --      kk acc ch | ((idx ch) `elem` (foundLoops entry) ) == True  = acc ++ " Loop = " ++ show (idx ch) ++ " "
  241. --                | otherwise = printGraph ch
  242.     -- DEBUG_444
  243.     body = " children "                
  244.     -- END DEBUG_444
  245.  
  246.  
  247. my_lst = [1,2]
  248. _pred = \x y -> x * 1 /= y
  249. test1 = func my_lst _pred
  250.  
  251. my_lst2 = [1,2,3]
  252. test2 = func my_lst2 _pred
  253.  
  254. instance (Show a,Eq a) => Show (G a) where
  255.   show = printGraph
  256.  
  257.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement