packages feed

ppad-random-0.1.0: bench/Weight.hs

{-# LANGUAGE BangPatterns #-}

module Main where

import qualified Crypto.CSPRNG as CSPRNG
import qualified Crypto.PRNG as PRNG
import qualified Crypto.PRNG.Pure as Pure
import qualified Data.ByteString as BS
import Data.Word (Word64)
import Weigh

-- note that 'weigh' doesn't work properly in a repl
main :: IO ()
main = do
  prng <- PRNG.new 42
  let !pg = Pure.new 42
  mc <- CSPRNG.new (BS.replicate 32 0)
  case mc of
    Nothing -> error "ppad-random (weigh): invalid seed"
    Just csprng -> mainWith $ do
      wgroup "PRNG" $ do
        io "word64 (x1000)" (sum_words (PRNG.word64 prng)) 1000
        io "double (x1000)" (sum_doubles (PRNG.double prng)) 1000
      wgroup "PRNG.Pure" $ do
        func "word64 (x1000)" (sum_draws Pure.word64 pg) 1000
        func "double (x1000)" (sum_draws Pure.double pg) 1000
        func "int_range 1 6 (x1000)" (sum_draws (Pure.int_range 1 6) pg) 1000
      wgroup "CSPRNG" $ do
        io "word64 (x1000)" (sum_words (CSPRNG.word64 csprng)) 1000
        io "bytes (32B)" (\n -> CSPRNG.bytes n csprng) 32
        io "bytes (1024B)" (\n -> CSPRNG.bytes n csprng) 1024

sum_words :: IO Word64 -> Int -> IO Word64
sum_words gen = loop 0 where
  loop !acc n
    | n <= 0    = pure acc
    | otherwise = do
        !w <- gen
        loop (acc + w) (n - 1)
{-# INLINE sum_words #-}

sum_doubles :: IO Double -> Int -> IO Double
sum_doubles gen = loop 0 where
  loop !acc n
    | n <= 0    = pure acc
    | otherwise = do
        !d <- gen
        loop (acc + d) (n - 1)
{-# INLINE sum_doubles #-}

-- sum the results of n draws from a pure generator
sum_draws :: Num a => (Pure.Gen -> Pure.Draw a) -> Pure.Gen -> Int -> a
sum_draws f = loop 0 where
  loop !acc !g n
    | n <= 0    = acc
    | otherwise = case f g of
        Pure.Draw x ng -> loop (acc + x) ng (n - 1)
{-# INLINE sum_draws #-}