{-# LANGUAGE ScopedTypeVariables #-}

module Data.Graph.Generation where

import Control.Monad (replicateM)
import Data.List     (foldl')
import System.Random

import Data.Graph.DGraph
import Data.Graph.Types
import Data.Graph.UGraph

-- | Generate a random Erdős–Rényi G(n, p) model graph of /n/ vertices with a
-- | /p/ connection probability
erdosRenyi :: Graph g => Int -> Float -> IO (g Int ())
erdosRenyi n p = go [1..n] (probability p) empty
    where
        go :: Graph g => [Int] -> Float -> g Int () -> IO (g Int ())
        go [] _ g = return g
        go (v:vs) pv g = do
            rnds <- replicateM (length vs + 1) $ randomRIO (0.0, 1.0)
            flipDir <- randomRIO (True, False)
            let vs' = zip rnds vs
            let g' = insertVertex v g
            go vs pv $! foldl' (putV pv v flipDir) g' vs'

        putV :: Graph g => Float -> Int -> Bool -> g Int () -> (Float, Int) -> g Int ()
        putV pv v flipDir g (p', v')
            | p' < pv = insertEdgePair pair g
            | otherwise = g
                where pair = if flipDir then (v', v) else (v, v')

        probability :: Float -> Float
        probability v | v >= 1 = 1 | v <= 0 = 0 | otherwise = v

-- | 'erdosRenyi' convinience 'UGraph' generation function
erdosRenyiU :: Int -> Float -> IO (UGraph Int ())
erdosRenyiU  = erdosRenyi

-- | 'erdosRenyi' convinience 'DGraph' generation function
erdosRenyiD :: Int -> Float -> IO (DGraph Int ())
erdosRenyiD  = erdosRenyi

-- | Generate a random square binary matrix
-- | Useful for use with 'fromAdjacencyMatrix'
randomMat :: Int -> IO [[Int]]
randomMat n = replicateM n randRow
    where randRow = replicateM n (randomRIO (0,1)) :: IO [Int]