packages feed

IntervalMap-0.4.1.0: bench/GenericLazyVsStrict.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

import Criterion.Main
import Criterion.Types (Config(..))

import Control.DeepSeq
import Prelude hiding (lookup, max, foldr)
import System.Random
import Data.Foldable (foldr)
import Data.List (sort)

import Data.IntervalMap.Generic.Interval
import qualified Data.IntervalMap.Generic.Lazy as L
import qualified Data.IntervalMap.Generic.Strict as S


seed :: Int
seed = 54321

ensure :: NFData a => a -> IO a
ensure xs = xs `deepseq` return xs

forceRange :: Int -> Int -> Int -> Int
forceRange lo hi n | n >= lo && n <= hi = n
                   | n < 0              = forceRange lo hi (0 - n)
                   | otherwise          = lo + (n `rem` (1 + hi - lo))

genRandomInts :: Int -> Int -> Int -> [Int]
genRandomInts lo hi n = Prelude.map (forceRange lo hi) . take n . randoms . mkStdGen $ seed

genRandomIntervals :: Int -> Int -> Int -> [(Int,Int)]
genRandomIntervals max lap n = genIvs . take (2*n) . randoms . mkStdGen $ seed
  where
    genIvs [] = []
    genIvs [_] = []
    genIvs (x:y:xs) = let lo = forceRange 1 max x
                          sz = forceRange 0 lap y
                      in (lo, lo + sz) : genIvs xs


benchConfig :: Config
benchConfig =  defaultConfig { reportFile = Just "bench-lazy-strict.html" }

cDATA_SIZE :: Int
cDATA_SIZE =  10000

data IV = IV {-# UNPACK #-} !Int {-# UNPACK #-} !Int
          deriving (Eq, Ord)

instance NFData IV where
  rnf a = a `seq` ()

instance Interval IV Int where
  lowerBound (IV l _) = l
  upperBound (IV _ u) = u

move :: Int -> IV -> IV
move n (IV a b) = IV (a+n) (b+n)


main :: IO ()
main =
  do
      let ivs  = genRandomIntervals cDATA_SIZE 20 cDATA_SIZE
      ivsP   <- ensure $ [(IV lo hi, lo) | (lo,hi) <- ivs]
      oIvsP  <- ensure $ sort ivsP
      lookupKeys <- ensure $ [i | (i,_) <- ivsP]
      sMap <- ensure $ S.fromList ivsP
      lMap <- ensure $ L.fromList ivsP
      rndInts <- ensure (genRandomInts 1 cDATA_SIZE cDATA_SIZE)
      defaultMainWith benchConfig [
         bgroup "fromList (insert)" [
           bench "Lazy"     $ nf L.fromList ivsP,
           bench "Strict"   $ nf S.fromList ivsP
         ],
         bgroup "fromAscList" [
           bench "Lazy"     $ nf L.fromAscList oIvsP,
           bench "Strict"   $ nf S.fromAscList oIvsP
         ],
         bgroup "search" [
           bench "lookup lazy"          $ nf (\m -> [L.lookup i m | i <- lookupKeys]) lMap,
           bench "lookup strict"        $ nf (\m -> [S.lookup i m | i <- lookupKeys]) sMap,
           bench "containing lazy"      $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `L.containing` p]) lMap,
           bench "containing strict"      $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `S.containing` p]) sMap,
           bench "intersecting lazy"    $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `L.intersecting` (IV p (p+15))]) lMap,
           bench "intersecting strict"    $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `S.intersecting` (IV p (p+15))]) sMap,
           bench "within lazy" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `L.within` (IV p (p+15))]) lMap,
           bench "within strict" $ nf (\m -> sum [v | p <- rndInts, (_,v) <- m `S.within` (IV p (p+15))]) sMap
         ],
         bgroup "mapKeys" [
           bench "lazy"             $ nf (L.mapKeys (move 1)) lMap,
           bench "strict"           $ nf (S.mapKeys (move 1)) sMap,
           bench "monotonic lazy"   $ nf (L.mapKeysMonotonic (move 1)) lMap,
           bench "monotonic strict" $ nf (S.mapKeysMonotonic (move 1)) sMap
         ],
         bgroup "map" [
           bench "lazy"    $ nf (L.map (1+)) lMap,
           bench "strict"  $ nf (S.map (1+)) sMap
         ],
         bgroup "union" [
           bench "Large/Empty lazy"   $ nf (\m -> L.union m L.empty) lMap,
           bench "Large/Empty strict" $ nf (\m -> S.union m S.empty) sMap,
           bench "Empty/Large lazy"   $ nf (\m -> L.union L.empty m) lMap,
           bench "Empty/Large strict" $ nf (\m -> S.union S.empty m) sMap,
           bench "self lazy"          $ nf (\m -> L.union m m) lMap,
           bench "self strict"        $ nf (\m -> S.union m m) sMap
         ]
       ]