如何在Haskell的FGL中实现“匹配”为O(1)?

时间:2013-08-03 15:49:08

标签: haskell functional-programming graph-algorithm

在Haskell的功能图库(FGL)中,大多数图算法都依赖于'匹配'函数,给定Node nGraph g,返回c & g',其中cContext的{​​{1}},n是图表的其余部分(不包含对g'的引用)。

我能看到这样做的唯一方法是检查n中的每个上下文,并删除任何引用g的边并将它们添加到上下文n。我相信这需要线性时间。

撰写该图书馆的Martin Erwig在this论文中建议,这种转变可以在恒定或至少亚线性时间内完成。任何人都可以向我解释这是如何实现的吗?

1 个答案:

答案 0 :(得分:7)

matchGraph类型类中定义,因此该函数的实现取决于实现类型类的数据类型。

该软件包附带两个实现,one using Patricia treesone using regular trees。您可以自己查看来源。

例如,Patricia树实现:

import           Data.Graph.Inductive.Graph
import           Data.IntMap (IntMap)
import qualified Data.IntMap as IM
import           Data.List
import           Data.Maybe
import           Control.Arrow(second)


newtype Gr a b = Gr (GraphRep a b)

type GraphRep a b = IntMap (Context' a b)
type Context' a b = (IntMap [b], a, IntMap [b])

type UGr = Gr () ()


instance Graph Gr where
    -- ...
    match           = matchGr
    -- ...

matchGr :: Node -> Gr a b -> Decomp Gr a b
matchGr node (Gr g)
    = case IM.lookup node g of
        Nothing
            -> (Nothing, Gr g)

        Just (p, label, s)
            -> let !g1 = IM.delete node g
                   !p' = IM.delete node p
                   !s' = IM.delete node s
                   !g2 = clearPred g1 node (IM.keys s')
                   !g3 = clearSucc g2 node (IM.keys p')
               in
                 (Just (toAdj p', node, label, toAdj s), Gr g3)

lookup and delete on IntMaps have O(min(n,W)) runtime,它在给定机器上实际上是常量,具有设置的整数宽度(W)。

这样只留下clearPredclearSucctoAdj

clearSucc :: GraphRep a b -> Node -> [Node] -> GraphRep a b
clearSucc g _ []       = g
clearSucc g v (p:rest) = clearSucc g' v rest
    where
      g' = IM.adjust f p g
      f (ps, l, ss) = (ps, l, IM.delete v ss)


clearPred :: GraphRep a b -> Node -> [Node] -> GraphRep a b
clearPred g _ []       = g
clearPred g v (s:rest) = clearPred g' v rest
    where
      g' = IM.adjust f s g
      f (ps, l, ss) = (IM.delete v ps, l, ss)

adjust也是O(min(n,W)),因此我们无需担心。 clearSuccclearPred都通过邻接列表中的每个元素递归,因此O(度)合并。

toAdj :: IntMap [b] -> Adj b
toAdj = concatMap expand . IM.toList
  where
    expand (n,ls) = map (flip (,) n) ls

toAdj创建一个新的边列表,即O(max(| V |,| E |)),但这是懒惰构造的,所以除非使用它,否则我们不需要担心。