packages feed

hgeometry-combinatorial-0.14: src/Algorithms/Graph/BFS.hs

{-# LANGUAGE ScopedTypeVariables #-}
--------------------------------------------------------------------------------
-- |
-- Module      :  Algorithms.Graph.BFS
-- Copyright   :  (C) Frank Staals
-- License     :  see the LICENSE file
-- Maintainer  :  Frank Staals
--------------------------------------------------------------------------------
module Algorithms.Graph.BFS
  ( bfs
  , bfs'
  ) where

import           Control.Monad.ST.Strict
import qualified Data.Foldable as F
import           Data.Sequence (Seq(..))
import qualified Data.Sequence as Seq
import           Data.Tree
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as MV
import qualified Data.Vector.Unboxed.Mutable as UMV
import           Witherable

--------------------------------------------------------------------------------

-- | Runs a BFS from the first vertex in the graph. The graph is given
-- in adjacency list representation.
--
-- running time: \(O(V + E)\)
bfs      :: Foldable f => Int -> V.Vector (v, f Int) -> Tree v
bfs s gr = fmap (fst . (gr V.!)) . bfs' s . fmap snd $ gr

-- | Runs a BFS from the first vertex in the graph. The graph is given
-- in adjacency list representation.
--
-- running time: \(O(V + E)\)
bfs'      :: Foldable f => Int -> V.Vector (f Int) -> Tree Int
bfs' s gr = extract s $ V.create
         $ do st  <- UMV.replicate n False
              out <- MV.new n
              go0 st out (s :<| mempty)
              pure out
  where
    n = V.length gr
    go0        :: forall s. UMV.MVector s Bool -> MV.MVector s [Int]
               -> Seq Int -> ST s ()
    go0 st out = go
      where
        visit i = do b <- UMV.read st i
                     UMV.write st i True -- mark i as visited
                     pure $ if b then Nothing else Just i

        go :: Seq Int -> ST s ()
        go = \case
          Empty       -> pure ()
          (u:<|queue) -> do ns <- wither visit . F.toList $ gr V.! u
                            MV.write out u ns -- write that u's children are ns
                            go (queue <> Seq.fromList ns)


-- | Give na root index and a vector s.t. v[i] lists the children of
-- node i, builds the acutal tree.
extract     :: Int -> V.Vector [Int] -> Tree Int
extract s v = go s
  where
    go i = Node i (map go $ v V.! i)