bff-0.1: Stats.hs
{-# LANGUAGE ExistentialQuantification, PolymorphicComponents,
TemplateHaskell
#-}
import Test.BenchPress
import Control.Exception (evaluate)
import Data.Bff
import Control.Applicative
import Control.Monad.Writer
import Control.Monad.State
import Control.Monad.Fix
import Data.Traversable hiding (mapM, sequence)
import qualified Data.Traversable as T
import qualified Data.Foldable as F
import Data.Zippable
import Data.DeriveTH
import Data.Derive.Zippable
import Data.Derive.Traversable
import Data.Derive.Functor
import Data.List
import Prelude
import Data.Ord
import Data.Maybe
import Text.Printf
import System.IO
import List
import StatsDef
-------------------
-- Configuration --
-------------------
sizes = (\n -> [1,(n`div`200)..n])
repetitions = 10
tests_to_run =
[ runTest test1
, runTest test2
, runTest test3
, runTest test4
]
----------------------
-- Test definitions --
----------------------
data Test c c' a = Test
{ testName :: String
, maxN :: Int
, genTestCase :: Int -> c a
, getTest :: c a -> c' a
, putTestMan :: c a -> c' a -> c a
, putTestAuto :: c a -> c' a -> c a
, modifyTest :: c' a -> c' a
, scale :: Double -> Int -> Double
}
--
-- Test 1
--
test1 = Test
{ testName = "halve, normalized"
, maxN = 100000
, genTestCase = \n -> [1..n]
, getTest = halve
, putTestMan = put1
, putTestAuto = bff halve
, modifyTest = id
, scale = \m s -> m / fromIntegral s
}
halve :: [a] -> [a]
halve as = take (length as `div` 2) as
put1 :: [a] -> [a] -> [a]
put1 as as' | length as' == n
= as' ++ drop n as
where n = length as `div` 2
--
-- Test 2
--
test2 = Test
{ testName = "flatten, left-leaning trees, normalized"
, maxN = 5000
, genTestCase = fix (\loop n -> if n == 1
then Leaf ()
else Node (loop (n-1)) (Leaf ()))
, getTest = flatten
, putTestMan = put2
, putTestAuto = bff flatten
, modifyTest = id
, scale = \m s -> m / fromIntegral s
}
flatten :: Tree a -> [a]
flatten (Leaf a) = [a]
flatten (Node t1 t2) = flatten t1 ++ flatten t2
put2 :: Tree a -> [a] -> Tree a
put2 s v = case go s v of (t,[]) -> t
where go (Leaf a) (b:bs) = (Leaf b,bs)
go (Node s1 s2) bs = (Node t1 t2,ds)
where (t1,cs) = go s1 bs
(t2,ds) = go s2 cs
--
-- Test 3
--
test3 = Test
{ testName = "flatten, right-leaning trees, normalized"
, maxN = 100000
, genTestCase = fix (\loop n -> if n == 1
then Leaf ()
else Node (Leaf ()) (loop (n-1)))
, getTest = flatten
, putTestMan = put2
, putTestAuto = bff flatten
, modifyTest = id
, scale = \m s -> m / fromIntegral s
}
--
-- Test 4
--
test4 = Test
{ testName = "rmdups, all elements different, normalized"
, maxN = 10000
, genTestCase = \n -> [1..n]
, getTest = rmdups
, putTestMan = put3
, putTestAuto = bff_Eq rmdups
, modifyTest = id
, scale = \m s -> m / fromIntegral s
}
rmdups :: Eq a => [a] -> [a]
rmdups = List.nub
put3 :: Eq a => [a] -> [a] -> [a]
put3 s v | v == List.nub v && length v == length s'
= map (fromJust . flip lookup (zip s' v)) s
where s' = List.nub s
----------------------------------
-- Stats calculation and output --
----------------------------------
stats test putter size = (mean . fst) `fmap` benchmark repetitions
(do let source = genTestCase test size
view = getTest test source
view' = modifyTest test view
deepEvaluate (source, view')
)
(\_ -> return ())
(\(source, view') -> deepEvaluate (putter test source view')
)
deepEvaluate :: Show a => a -> IO a
deepEvaluate x = evaluate (length (show x)) >> return x
collectStats :: (Show (c a), Show (c' a)) => Test c c' a -> IO StatRunData
collectStats test = mapM (\size -> do
putStr "."
manual <- stats test putTestMan size
putStr "."
automatic <- stats test putTestAuto size
putStr " "
return (size, scale test manual size, scale test automatic size)
) (sizes (maxN test))
runTest :: (Show (c v), Show (c' v), F.Foldable c', Zippable c', Traversable c, Eq v) =>
Test c c' v -> IO (String, StatRunData)
runTest test = do
putStrLn $ ""
putStr $ "Test \"" ++ testName test ++ "\" "
statData <- collectStats test
putStrLn $ ""
return (testName test, statData)
main = do hSetBuffering stdout NoBuffering
putStrLn $ "Bff benchmarking program"
putStrLn $ "(c) 2008 Joachim Breitner"
putStrLn $ "Repeating every test " ++ show repetitions ++ " times."
rawData <- sequence tests_to_run
putStrLn $ "Writing data to stats.data"
writeFile "stats.data" (show rawData)
-- Data Definition
data Tree a = Leaf a | Node (Tree a) (Tree a) deriving Show
-- Lined in, otherwise name clashes with Prelude.foldr occurs
$(derive makeFunctor ''Tree)
instance F.Foldable Tree where
foldr f b (Leaf a1) = (f a1 . id) b
foldr f b (Node a1 a2) = (flip (F.foldr f) a1 . (flip (F.foldr f) a2 . id)) b
$(derive makeTraversable ''Tree)
$(derive makeZippable ''Tree)