packages feed

incremental-maps-0.0.0.0: src/benchmarks/MapBenchmarks.hs

module Main where

-- Prelude

import Prelude hiding (id, (.))

-- Control

import Control.Applicative

-- Data

import           Data.Foldable (toList)
import           Data.MultiChange (MultiChange)
import qualified Data.MultiChange               as MultiChange
import           Data.Map (Map)
import qualified Data.Map                       as Map
import           Data.Incremental               
import qualified Data.Incremental.Tuple         as Tuple
import qualified Data.Incremental.Map           as IncMap

-- Criterion
import Criterion.Main
import Criterion.Types
import Control.DeepSeq
import GHC.Generics hiding (C)


-- Test

import Test.QuickCheck
import Test.QuickCheck.Poly

instance Arbitrary a => Arbitrary (PrimitiveChange a) where

    arbitrary = frequency [(1, keepGen), (5, replaceGen)] where

        keepGen = return Keep

        replaceGen = fmap ReplaceBy arbitrary

    shrink Keep            = []
    shrink (ReplaceBy val) = Keep : map ReplaceBy (shrink val)


instance Arbitrary p => Arbitrary (MultiChange p) where

    arbitrary = fmap MultiChange.singleton arbitrary

    shrink change = map MultiChange.fromList (shrink (toList change))


-- Pair changes
deriving instance (Show (DefaultChange a), Show (DefaultChange b)) =>
                  Show (Tuple.AtomicChange a b)

instance (Arbitrary (DefaultChange a), Arbitrary (DefaultChange b)) =>
         Arbitrary (Tuple.AtomicChange a b) where

    arbitrary = oneof [firstGen, secondGen] where

        firstGen = fmap Tuple.First arbitrary

        secondGen = fmap Tuple.Second arbitrary

    shrink (Tuple.First change)  = map Tuple.First (shrink change)
    shrink (Tuple.Second change) = map Tuple.Second (shrink change)

-- Map changes
instance (Arbitrary k, Arbitrary (DefaultChange k),Arbitrary v, Arbitrary (DefaultChange v)) =>
         Arbitrary (IncMap.AtomicChange k v) where

    arbitrary = oneof [delete, insert] where

        delete = liftA IncMap.Delete arbitrary

        insert = liftA2 IncMap.Insert arbitrary arbitrary

    shrink (IncMap.Insert k v)
        = [IncMap.Insert k' v'
              | (k', v') <- shrink (k, v)]
    shrink (IncMap.Delete k)
        = [IncMap.Delete k'
              | k' <- shrink k]

newtype AtomicAChange = DoubleAndAdd Integer deriving (Show, Arbitrary, Generic)

instance Change AtomicAChange where

    type Value AtomicAChange = A

    DoubleAndAdd diff $$ A integer = A (2 * integer + diff)

instance Changeable A where

    type DefaultChange A = MultiChange AtomicAChange

deriving instance Ord A

newtype AtomicBChange = TripleAndAdd Integer deriving (Show, Arbitrary, Generic)

instance Change AtomicBChange where

    type Value AtomicBChange = B

    TripleAndAdd diff $$ B integer = B (3 * integer + diff)

instance Changeable B where

    type DefaultChange B = MultiChange AtomicBChange

deriving instance Ord B

newtype AtomicCChange = QuadrupleAndAdd Integer deriving (Show, Arbitrary, Generic)

instance Change AtomicCChange where

    type Value AtomicCChange = C

    QuadrupleAndAdd diff $$ C integer = C (4 * integer + diff)

instance Changeable C where

    type DefaultChange C = MultiChange AtomicCChange

deriving instance Ord C


instance (NFData a) => NFData (MultiChange a)
instance NFData (Tuple.AtomicChange (Map A B) (Map A B))
instance NFData (Tuple.AtomicChange A B)
instance (Generic a, Generic b, NFData a, NFData b) => NFData (IncMap.AtomicChange a b)
instance NFData AtomicBChange
instance NFData AtomicAChange
instance NFData A
instance NFData B
instance NFData C

deriving instance (Generic a, Generic b) => Generic (IncMap.AtomicChange a b)
deriving instance Generic A
deriving instance Generic B
deriving instance Generic C

applyChanges :: Change p => (Value p, [p]) -> [Value p]
applyChanges (val, changes) = scanl (flip ($$)) val changes


testMap r n = do
    pairs <- generate $ vectorOf n $ resize r $ arbitrary 
    let resultMap = Map.fromList pairs
    return resultMap

--testMapSize :: Int -> IO (Int,Int)
--testMapSize n = do
--    pairs <- generate $ vectorOf n $ resize n $ (arbitrary :: Gen (A,B)) 
--    let resultMap = Map.fromList pairs
--    let resultMapSize = Map.size resultMap
--    return (n,resultMapSize)

testChanges r n = do
    changes <- generate $ vectorOf n (resize r $ arbitrary) 
    return changes

testFun r = do
    fun <- generate $ resize r $ arbitrary
    return fun

testKey r = do
    key <- generate $ resize r $ arbitrary
    return key

checkTrans trans (val,changes) = applyChanges (runTrans trans (val,changes))
checkOriginal trans (val,changes) = map trans (applyChanges (val,changes))

--benchmarks
main :: IO ()
main = 
  defaultMainWith
    (defaultConfig {reportFile = Just "performance.html"}) $ concat [
    map (benchFilter 10) [1000,10000,100000,1000000],
    map (benchMap 10) [1000,10000,100000,1000000],
    map (benchLookup 10) [1000,10000,100000,1000000],
    map (benchMember 10) [1000,10000,100000,1000000],
    map (benchPartition 10) [1000,10000,100000,1000000],
    map (benchUnion 10) [1000,10000,100000,1000000],
    map (benchDifference 10) [1000,10000,100000,1000000],
    map (benchIntersection 10) [1000,10000,100000,1000000],
    map (benchKeysSet 10) [1000,10000,100000,1000000],
    map (benchSubmapOf 10) [1000,10000,100000,1000000],
    map (benchSubmapOf 10) [1000,10000,100000,1000000],
    map (benchSplit 10) [1000,10000,100000,1000000],
    map (benchMapKeys 10) [1000,10000,100000,1000000]
    ]    



benchFilter ncgh n = env (do
            tMap <- testMap n n :: IO (Map A B) 
            tChanges <- testChanges n ncgh :: IO [MultiChange (IncMap.AtomicChange A B)]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) tMap) tChangesScan
            tFun  <- testFun n :: IO (B -> Bool)
            return (testValAndChanges,tFun))
         (\ ~(valAndChanges,fun) ->
            bgroup ("filter " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (Map.filter fun)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.filter fun)) (valAndChanges !! x)) [0..ncgh]
            ])
benchMap ncgh n = env (do
            tMap <- testMap n n :: IO (Map A B) 
            tChanges <- testChanges n ncgh :: IO [MultiChange (IncMap.AtomicChange A B)]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) tMap) tChangesScan
            tFun  <- testFun n :: IO (B -> C)
            return (testValAndChanges,tFun))
         (\ ~(valAndChanges,fun) ->
            bgroup ("map " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (Map.map fun)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.map fun)) (valAndChanges !! x)) [0..ncgh]
            ])

benchLookup ncgh n = env (do
            tMap <- testMap n n :: IO (Map A B) 
            tChanges <- testChanges n ncgh :: IO [MultiChange (IncMap.AtomicChange A B)]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) tMap) tChangesScan
            tKey  <- testKey n :: IO (A)
            return (testValAndChanges,tKey))
         (\ ~(valAndChanges,key) ->
            bgroup ("lookup " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (Map.lookup key)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.lookup key)) (valAndChanges !! x)) [0..ncgh]
            ])
benchMember ncgh n = env (do
            tMap <- testMap n n :: IO (Map A B) 
            tChanges <- testChanges n ncgh :: IO [MultiChange (IncMap.AtomicChange A B)]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) tMap) tChangesScan
            tKey  <- testKey n :: IO (A)
            return (testValAndChanges,tKey))
         (\ ~(valAndChanges,key) ->
            bgroup ("member " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (Map.member key)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.member key)) (valAndChanges !! x)) [0..ncgh]
            ])
benchPartition ncgh n = env (do
            tMap <- testMap n n :: IO (Map A B) 
            tChanges <- testChanges n ncgh :: IO [MultiChange (IncMap.AtomicChange A B)]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) tMap) tChangesScan
            tFun  <- testFun n :: IO (B -> Bool)
            return (testValAndChanges,tFun))
         (\ ~(valAndChanges,fun) ->
            bgroup ("partition " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (Map.partition fun)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.partition fun)) (valAndChanges !! x)) [0..ncgh]
            ])

benchUnion ncgh n = env (do
            tMap1 <- testMap n n :: IO (Map A B) 
            tMap2 <- testMap n n :: IO (Map A B) 
            tChanges <- testChanges n ncgh :: IO [MultiChange (Tuple.AtomicChange (Map A B) (Map A B))]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) (tMap1,tMap2)) tChangesScan
            return testValAndChanges)
         (\ ~(valAndChanges) ->
            bgroup ("union " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (uncurry Map.union)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.union)) (valAndChanges !! x)) [0..ncgh]
            ])

benchDifference ncgh n = env (do
            tMap1 <- testMap n n :: IO (Map A B) 
            tMap2 <- testMap n n :: IO (Map A B) 
            tChanges <- testChanges n ncgh :: IO [MultiChange (Tuple.AtomicChange (Map A B) (Map A B))]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) (tMap1,tMap2)) tChangesScan
            return testValAndChanges)
         (\ ~(valAndChanges) ->
            bgroup ("difference " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (uncurry Map.difference)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.difference)) (valAndChanges !! x)) [0..ncgh]
            ])

benchIntersection ncgh n = env (do
            tMap1 <- testMap n n :: IO (Map A B) 
            tMap2 <- testMap n n :: IO (Map A B) 
            tChanges <- testChanges n ncgh :: IO [MultiChange (Tuple.AtomicChange (Map A B) (Map A B))]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) (tMap1,tMap2)) tChangesScan
            return testValAndChanges)
         (\ ~(valAndChanges) ->
            bgroup ("intersection " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (uncurry Map.intersection)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.intersection)) (valAndChanges !! x)) [0..ncgh]
            ])

benchKeysSet ncgh n = env (do
            tMap <- testMap n n :: IO (Map A B) 
            tChanges <- testChanges n ncgh :: IO [MultiChange (IncMap.AtomicChange A B)]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) tMap) tChangesScan
            return testValAndChanges)
         (\ ~(valAndChanges) ->
            bgroup ("keysSet " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (Map.keysSet)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.keysSet)) (valAndChanges !! x)) [0..ncgh]
            ])

benchSubmapOf ncgh n = env (do
            tMap1 <- testMap n n :: IO (Map A B) 
            tMap2 <- testMap n n :: IO (Map A B) 
            tChanges <- testChanges n ncgh :: IO [MultiChange (Tuple.AtomicChange (Map A B) (Map A B))]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) (tMap1,tMap1)) tChangesScan
            return testValAndChanges)
         (\ ~(valAndChanges) ->
            bgroup ("submapOf " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (uncurry Map.isSubmapOf)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.isSubmapOf)) (valAndChanges !! x)) [0..ncgh]
            ])

benchSplit ncgh n = env (do
            tMap <- testMap n n :: IO (Map A B) 
            tKey <- testKey n :: IO (A)
            tChanges <- testChanges n ncgh :: IO [MultiChange (IncMap.AtomicChange A B)]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) tMap) tChangesScan
            return (testValAndChanges,tKey))
         (\ ~(valAndChanges,key) ->
            bgroup ("split " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (Map.split key)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.split key)) (valAndChanges !! x)) [0..ncgh]
            ])

benchMapKeys ncgh n = env (do
            tMap <- testMap n n :: IO (Map A B) 
            tFun <- testFun n :: IO (A -> C)
            tChanges <- testChanges n ncgh :: IO [MultiChange (IncMap.AtomicChange A B)]
            let tChangesScan = scanl (\x y -> x ++ [y]) [] tChanges
            let testValAndChanges = zip (replicate (ncgh+1) tMap) tChangesScan
            return (testValAndChanges,tFun))
         (\ ~(valAndChanges,fun) ->
            bgroup ("mapKeys " ++ show n) $ concat 
            [map (\x -> bench ("original change=" ++ show x) $ nf (checkOriginal (Map.mapKeys fun)) (valAndChanges !! x)) [0..ncgh],
             map (\x -> bench ("incremental change=" ++ show x) $ nf (checkTrans (IncMap.mapKeys fun)) (valAndChanges !! x)) [0..ncgh]
            ])