packages feed

hgraph-1.10.0.0: src/HGraph/Directed/Generator.hs

module HGraph.Directed.Generator
       ( bidirectedCycle
       , randomAcyclicDigraph
       , randomDigraph
       , oneWayGrid
       )
where

import Control.Monad.State
import Data.List
import HGraph.Directed
import HGraph.Utils
import qualified Data.Set as S
import qualified HGraph.Undirected.AdjacencyMap as U
import qualified HGraph.Undirected              as U
import qualified HGraph.Undirected.Generator    as U
import System.Random

-- | A cycle where vertices are connected in both directions
bidirectedCycle d0 n =
  foldr addArc (foldr addVertex d0 [0..n-1]) $ 
    (zip ((n-1) : [0..n-2]) (0 : [1..n-1]))
    ++ (zip (0:[n-1,n-2..1]) ((n-1):[n-2,n-3..0]))

-- |Generate a random weakly-connected acyclic digraph with `n` vertices and `m` + `n` - 1 arcs.
randomAcyclicDigraph d0 n m' = do
  utree <- U.randomTree U.emptyGraph n
  let m = max (n - 1) (min m' (n * (n - 1) `div` 2))
      dtree = acyclicOrientation d0 utree
  if (m + n - 1) > (n * (n - 1)) `div` 4 then do
    d' <- removeRandomArcs (foldr addArc (foldr addVertex (empty d0) $ vertices dtree)
                            [ (v,u)
                            | v <- vertices dtree
                            , u <- vertices dtree
                            , v < u && (not $ arcExists dtree (v,u))
                            ]
                     )
                     (m - n + 1)
    return $ foldr addArc d' $ arcs dtree
  else
    addRandomArcsAcyclic dtree m

-- An acyclic grid where columns only go down and rows only go left.
oneWayGrid d0 w h = 
      foldr addArc (foldr addVertex (empty d0) ([0..w * h - 1])) $
                      [ (v, v + 1)
                      | r <- [0..h-1]
                      , c <- [0..w-2]
                      , let v = r*w + c
                      ]
                      ++
                      [ (v, v + w)
                      | r <- [0..h-2]
                      , c <- [0..w-1]
                      , let v = r*w + c
                      ]

acyclicOrientation d0 g = foldr addArc (foldr addVertex (empty d0) $ U.vertices g) $
  [ if u < v then (u,v) else (v,u)
  | (u,v) <- U.edges g
  ]

randomDigraph g0 n m
  | m > (n * (n - 1)) = randomDigraph g0 n (n * (n - 1))
  | m > (n * (n - 1)) `div` 2 = do -- dense graph
    let g1 = foldr addArc (foldr addVertex (empty g0) [1..n]) [(v,u) | v <- [1..n], u <- [1..n], v /= u]
    removeRandomArcs g1 m
  | otherwise = do -- sparse graph
    let g1 = foldr addVertex (empty g0) [0..n-1]
    addRandomArcs g1 m

addRandomArcs g m
  | numArcs g == m = return g
  | otherwise = do
    v <- randomN 0 (numVertices g - 1)
    u <- randomN 0 (numVertices g - 1)
    if u /= v then
      addRandomArcs (addArc (v,u) g) m
    else
      addRandomArcs g m

addRandomArcsAcyclic g m
  | numArcs g == m = return g
  | otherwise = do
    v <- randomN 0 (numVertices g - 2)
    u <- randomN (v + 1) (numVertices g - 1)
    if v < u then
      addRandomArcsAcyclic (addArc (v,u) g) m
    else
      addRandomArcsAcyclic g m

removeRandomArcs g m
  | numArcs g == m = return g
  | otherwise = do
    v <- randomN 0 (numVertices g - 1)
    u <- randomN 0 (numVertices g - 1)
    if u /= v && arcExists g (v,u) then
      removeRandomArcs (removeArc (v,u) g) m
    else
      removeRandomArcs g m