parent
							
								
									1d610d5096
								
							
						
					
					
						commit
						43a6269dcd
					
				
				 6 changed files with 341 additions and 0 deletions
			
			
		| @ -0,0 +1,75 @@ | |||||||
|  | # Basic Libraries | ||||||
|  | 
 | ||||||
|  | ## 28.6 Exercise: Benchmark Practice | ||||||
|  | 
 | ||||||
|  | see [src/benchSet.hs](./src/benchSet.hs) | ||||||
|  | 
 | ||||||
|  | ```shell | ||||||
|  | benchmarking member check map | ||||||
|  | time                 28.57 ns   (28.10 ns .. 29.11 ns) | ||||||
|  |                      0.998 R²   (0.996 R² .. 0.999 R²) | ||||||
|  | mean                 28.43 ns   (28.09 ns .. 28.97 ns) | ||||||
|  | std dev              1.357 ns   (899.3 ps .. 1.950 ns) | ||||||
|  | variance introduced by outliers: 70% (severely inflated) | ||||||
|  | 
 | ||||||
|  | benchmarking member check set | ||||||
|  | time                 27.93 ns   (27.55 ns .. 28.34 ns) | ||||||
|  |                      0.998 R²   (0.997 R² .. 0.999 R²) | ||||||
|  | mean                 27.92 ns   (27.58 ns .. 28.38 ns) | ||||||
|  | std dev              1.320 ns   (1.010 ns .. 1.940 ns) | ||||||
|  | variance introduced by outliers: 70% (severely inflated) | ||||||
|  | 
 | ||||||
|  | benchmarking insert check set | ||||||
|  | time                 127.9 ns   (127.4 ns .. 128.4 ns) | ||||||
|  |                      1.000 R²   (1.000 R² .. 1.000 R²) | ||||||
|  | mean                 127.1 ns   (126.7 ns .. 127.6 ns) | ||||||
|  | std dev              1.515 ns   (1.162 ns .. 2.043 ns) | ||||||
|  | variance introduced by outliers: 12% (moderately inflated) | ||||||
|  | 
 | ||||||
|  | benchmarking insert check set | ||||||
|  | time                 112.8 ns   (112.4 ns .. 113.3 ns) | ||||||
|  |                      1.000 R²   (1.000 R² .. 1.000 R²) | ||||||
|  | mean                 112.6 ns   (112.0 ns .. 113.4 ns) | ||||||
|  | std dev              2.414 ns   (1.889 ns .. 3.151 ns) | ||||||
|  | variance introduced by outliers: 30% (moderately inflated) | ||||||
|  | 
 | ||||||
|  | benchmarking union check set | ||||||
|  | time                 655.5 μs   (652.0 μs .. 658.8 μs) | ||||||
|  |                      1.000 R²   (0.999 R² .. 1.000 R²) | ||||||
|  | mean                 638.7 μs   (634.2 μs .. 642.7 μs) | ||||||
|  | std dev              15.07 μs   (12.96 μs .. 18.02 μs) | ||||||
|  | variance introduced by outliers: 14% (moderately inflated) | ||||||
|  | 
 | ||||||
|  | benchmarking union check set | ||||||
|  | time                 428.9 μs   (423.5 μs .. 433.8 μs) | ||||||
|  |                      0.999 R²   (0.999 R² .. 0.999 R²) | ||||||
|  | mean                 422.6 μs   (419.7 μs .. 425.9 μs) | ||||||
|  | std dev              10.16 μs   (8.544 μs .. 12.44 μs) | ||||||
|  | variance introduced by outliers: 15% (moderately inflated) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 28.9 Excercises: Vector | ||||||
|  | 
 | ||||||
|  | see [src/benchVector.hs](./src/benchVector.hs) | ||||||
|  | 
 | ||||||
|  | Using unboxed vector has better time performance. I tried measuring space, | ||||||
|  | but the difference is almost negligable. | ||||||
|  | 
 | ||||||
|  | ## 28.10 Chaper Exercises | ||||||
|  | 
 | ||||||
|  | ### Difference List | ||||||
|  | 
 | ||||||
|  | see [src/DiffList.hs](./src/DiffList.hs) | ||||||
|  | 
 | ||||||
|  | It is not actually faster, but it has the same performance as Data.DList and | ||||||
|  | the same implementation, so I guess this is to be expected? | ||||||
|  | 
 | ||||||
|  | ### A simple queue | ||||||
|  | 
 | ||||||
|  | see [src/SimpleQueue.hs](./src/SimpleQueue.hs) | ||||||
|  | 
 | ||||||
|  | Comparing Sequence and Queue seems a bit strange as they serve different | ||||||
|  | purposes. I could implement a function to add something to the back of the | ||||||
|  | queue (similar to |>) but that kinda defeats the purpose of queue... I compared | ||||||
|  | them based on what a queue should be capable of doing and it seem the queue | ||||||
|  | is better than the sequence in these cases. | ||||||
| @ -0,0 +1,61 @@ | |||||||
|  | module Main where | ||||||
|  | 
 | ||||||
|  | import Criterion.Main | ||||||
|  | 
 | ||||||
|  | -- import qualified Data.DList as DL | ||||||
|  | 
 | ||||||
|  | newtype DList a = DL { unDL :: [a] -> [a] } | ||||||
|  | 
 | ||||||
|  | -- 1 | ||||||
|  | empty :: DList a | ||||||
|  | empty = DL id | ||||||
|  | {-# INLINE empty #-} | ||||||
|  | 
 | ||||||
|  | -- 2 | ||||||
|  | singleton :: a -> DList a | ||||||
|  | singleton = DL . (:) | ||||||
|  | {-# INLINE singleton #-} | ||||||
|  | 
 | ||||||
|  | -- 3 | ||||||
|  | toList :: DList a -> [a] | ||||||
|  | toList dl = unDL dl [] | ||||||
|  | {-# INLINE toList #-} | ||||||
|  | 
 | ||||||
|  | -- 4 | ||||||
|  | infixr `cons` | ||||||
|  | cons :: a -> DList a -> DList a | ||||||
|  | cons x xs = DL ((x:) . unDL xs) | ||||||
|  | {-# INLINE cons #-} | ||||||
|  | 
 | ||||||
|  | -- 5 | ||||||
|  | infixl `snoc` | ||||||
|  | snoc :: DList a -> a -> DList a | ||||||
|  | snoc xs x = DL $ ((unDL xs) . (x:)) | ||||||
|  | {-# INLINE snoc #-} | ||||||
|  | 
 | ||||||
|  | -- 6 | ||||||
|  | append :: DList a -> DList a -> DList a | ||||||
|  | append d d' = DL $ (unDL d . unDL d') | ||||||
|  | {-# INLINE append #-} | ||||||
|  | 
 | ||||||
|  | schlemiel :: Int -> [Int] | ||||||
|  | schlemiel i = go i [] | ||||||
|  |     where go 0 xs = xs | ||||||
|  |           go n xs = go (n - 1) ([n] ++ xs) | ||||||
|  | 
 | ||||||
|  | constructDList :: Int -> [Int] | ||||||
|  | constructDList i = toList $ go i empty | ||||||
|  |     where go 0 xs = xs | ||||||
|  |           go n xs = go (n - 1) (singleton n `append` xs) | ||||||
|  | 
 | ||||||
|  | -- constructDList' :: Int -> [Int] | ||||||
|  | -- constructDList' i = DL.toList $ go i DL.empty | ||||||
|  | --     where go 0 xs = xs | ||||||
|  | --           go n xs = go (n - 1) (DL.singleton n `DL.append` xs) | ||||||
|  | 
 | ||||||
|  | main :: IO () | ||||||
|  | main = defaultMain | ||||||
|  |     [ bench "concat list" $ whnf schlemiel 123456 | ||||||
|  |     , bench "concat dlist" $ whnf constructDList 123456 | ||||||
|  |     -- , bench "concat dlist'" $ whnf constructDList' 123456 | ||||||
|  |     ] | ||||||
| @ -0,0 +1,106 @@ | |||||||
|  | module Main where | ||||||
|  | 
 | ||||||
|  | import Criterion.Main | ||||||
|  | import qualified Data.Sequence as S | ||||||
|  | 
 | ||||||
|  | data Queue a = Queue { enqueue :: [a] | ||||||
|  |                      , dequeue :: [a] | ||||||
|  |                      } deriving (Show, Eq) | ||||||
|  | 
 | ||||||
|  | empty :: Queue a | ||||||
|  | empty = Queue [] [] | ||||||
|  | 
 | ||||||
|  | push :: a -> Queue a -> Queue a | ||||||
|  | push a q = q { enqueue = a : enqueue q} | ||||||
|  | 
 | ||||||
|  | pop :: Queue a -> Maybe (a, Queue a) | ||||||
|  | pop (Queue [] []) = Nothing | ||||||
|  | pop (Queue xs []) = pop $ Queue [] (reverse xs) | ||||||
|  | pop (Queue xs (y:ys)) = Just (y, Queue xs ys) | ||||||
|  | 
 | ||||||
|  | alternateQ :: [Int] -> Bool | ||||||
|  | alternateQ [] = True | ||||||
|  | alternateQ (x:xs) = go x empty && alternateQ xs | ||||||
|  |     where go y q = f (pop $ push y q) y | ||||||
|  |           f Nothing _ = False | ||||||
|  |           f (Just (a, _)) b = a == b | ||||||
|  | 
 | ||||||
|  | pushL :: a -> [a] -> [a] | ||||||
|  | pushL = (:) | ||||||
|  | 
 | ||||||
|  | popL :: [a] -> Maybe (a, [a]) | ||||||
|  | popL [] = Nothing | ||||||
|  | popL xs = let xs' = reverse xs | ||||||
|  |           in Just (head $ xs', reverse $ tail xs') | ||||||
|  | 
 | ||||||
|  | alternateL :: [Int] -> Bool | ||||||
|  | alternateL [] = True | ||||||
|  | alternateL (x:xs) = go x [] && alternateL xs | ||||||
|  |     where go y q = f (popL $ pushL y q) y | ||||||
|  |           f Nothing _ = False | ||||||
|  |           f (Just (a, _)) b = a == b | ||||||
|  | 
 | ||||||
|  | pushThenPop :: [Int] -> [Int] | ||||||
|  | pushThenPop xs = (go' $ go xs empty) | ||||||
|  |     where go [] q = q | ||||||
|  |           go (y:ys) q = go ys (push y q) | ||||||
|  |           go' q = let r = pop q | ||||||
|  |                   in case r of | ||||||
|  |                     Nothing -> [] | ||||||
|  |                     (Just (a, q')) -> a : go' q' | ||||||
|  | 
 | ||||||
|  | pushThenPopL :: [Int] -> [Int] | ||||||
|  | pushThenPopL xs = (go' $ go xs []) | ||||||
|  |     where go [] q = q | ||||||
|  |           go (y:ys) q = go ys (pushL y q) | ||||||
|  |           go' q = let r = popL q | ||||||
|  |                   in case r of | ||||||
|  |                     Nothing -> [] | ||||||
|  |                     (Just (a, q')) -> a : go' q' | ||||||
|  | 
 | ||||||
|  | -- | ||||||
|  | fromList :: [a] -> Queue a | ||||||
|  | fromList = flip Queue [] | ||||||
|  | 
 | ||||||
|  | fromList' :: [a] -> Queue a | ||||||
|  | fromList' = Queue [] . reverse | ||||||
|  | 
 | ||||||
|  | (><) :: Queue a -> Queue a -> Queue a | ||||||
|  | (><) (Queue e d) (Queue e' d') = Queue [] q'' | ||||||
|  |     where q'' = d ++ reverse e ++ d' ++ reverse e' | ||||||
|  | 
 | ||||||
|  | testConcat :: [Int] -> Queue Int | ||||||
|  | testConcat xs = fromList xs >< fromList xs | ||||||
|  | 
 | ||||||
|  | testConcat' :: [Int] -> S.Seq Int | ||||||
|  | testConcat' xs = S.fromList xs S.>< S.fromList xs | ||||||
|  | 
 | ||||||
|  | pushA :: [Int] -> Queue Int | ||||||
|  | pushA xs = go xs empty | ||||||
|  |     where go [] q = q | ||||||
|  |           go (x:xs) q = go xs $ push x q | ||||||
|  | 
 | ||||||
|  | pushA' :: [Int] -> S.Seq Int | ||||||
|  | pushA' xs = go xs S.empty | ||||||
|  |     where go [] s = s | ||||||
|  |           go (x:xs) s = go xs $ x S.<| s | ||||||
|  | 
 | ||||||
|  | main :: IO () | ||||||
|  | main = defaultMain | ||||||
|  |     -- List will be faster because it has no overehead for Queue construction | ||||||
|  |     -- and queue still needs to reverse for every element just as list. | ||||||
|  |     [ bench "queue" $ nf alternateQ [1..1000] | ||||||
|  |     , bench "list" $ nf alternateL [1..1000] | ||||||
|  |     -- List will be slower than queue, because it needs to reverse for every | ||||||
|  |     -- element, while queue only reverse on empty dequeue. | ||||||
|  |     , bench "queue push pop" $ nf pushThenPop [1..1000] | ||||||
|  |     , bench "list push pop" $ nf pushThenPopL [1..1000] | ||||||
|  |     -- Queue is quite efficient at what it is good at: | ||||||
|  |     , bench "queue fromList" $ whnf fromList ([1..1000] :: [Int]) | ||||||
|  |     , bench "queue fromList'" $ whnf fromList' ([1..1000] :: [Int]) | ||||||
|  |     , bench "sequence fromList" $ whnf S.fromList ([1..1000] :: [Int]) | ||||||
|  |     , bench "queue concat" $ whnf testConcat ([1..100] :: [Int]) | ||||||
|  |     , bench "sequence concat" $ whnf testConcat' ([1..100] :: [Int]) | ||||||
|  |     , bench "insert queue" $ whnf pushA [1..1000] | ||||||
|  |     , bench "insert sequence" $ whnf pushA' [1..1000] | ||||||
|  |     ] | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | module Main where | ||||||
|  | 
 | ||||||
|  | import Control.Monad | ||||||
|  | import qualified Data.Text as T | ||||||
|  | import qualified Data.Text.IO as TIO | ||||||
|  | import qualified System.IO as SIO | ||||||
|  | import qualified Data.Text.Lazy as TL | ||||||
|  | import qualified Data.Text.Lazy.IO as TLIO | ||||||
|  | 
 | ||||||
|  | dictWords :: IO String | ||||||
|  | dictWords = SIO.readFile "/usr/share/dict/words" | ||||||
|  | 
 | ||||||
|  | dictWordsT :: IO T.Text | ||||||
|  | dictWordsT = TIO.readFile "/usr/share/dict/words" | ||||||
|  | 
 | ||||||
|  | dictWordsTL :: IO TL.Text | ||||||
|  | dictWordsTL = TLIO.readFile "/usr/share/dict/words" | ||||||
|  | 
 | ||||||
|  | main :: IO () | ||||||
|  | main = do | ||||||
|  |     replicateM_ 1000 (dictWords >>= print) | ||||||
|  |     replicateM_ 1000 (dictWordsT >>= TIO.putStrLn) | ||||||
|  |     replicateM_ 1000 (dictWordsTL >>= TLIO.putStrLn) | ||||||
| @ -0,0 +1,52 @@ | |||||||
|  | module Main where | ||||||
|  | 
 | ||||||
|  | import Criterion.Main | ||||||
|  | import qualified Data.Map as M | ||||||
|  | import qualified Data.Set as S | ||||||
|  | 
 | ||||||
|  | bumpIt :: (Num a, Num b) => (a, b) -> (a, b) | ||||||
|  | bumpIt (i, v) = (i + 1, v + 1) | ||||||
|  | 
 | ||||||
|  | m :: M.Map Int Int | ||||||
|  | m = M.fromList $ take 10000 stream | ||||||
|  |     where stream = iterate bumpIt (0, 0) | ||||||
|  | 
 | ||||||
|  | s :: S.Set Int | ||||||
|  | s = S.fromList $ take 10000 stream | ||||||
|  |     where stream = iterate (+1) 0 | ||||||
|  | 
 | ||||||
|  | membersMap :: Int -> Bool | ||||||
|  | membersMap i = M.member i m | ||||||
|  | 
 | ||||||
|  | membersSet :: Int -> Bool | ||||||
|  | membersSet i = S.member i s | ||||||
|  | 
 | ||||||
|  | insertMap :: (Int, Int) -> M.Map Int Int | ||||||
|  | insertMap (k, v) = M.insert k v m | ||||||
|  | 
 | ||||||
|  | insertSet :: Int -> S.Set Int | ||||||
|  | insertSet k = S.insert k s | ||||||
|  | 
 | ||||||
|  | m1 :: M.Map Int Int | ||||||
|  | m1 = M.fromList $ take 5000 stream | ||||||
|  |     where stream = iterate (bumpIt . bumpIt) (0, 0) | ||||||
|  | m2 :: M.Map Int Int | ||||||
|  | m2 = M.fromList $ take 5000 stream | ||||||
|  |     where stream = iterate (bumpIt . bumpIt) (1, 1) | ||||||
|  | 
 | ||||||
|  | s1 :: S.Set Int | ||||||
|  | s1 = S.fromList $ take 5000 stream | ||||||
|  |     where stream = iterate (+2) 0 | ||||||
|  | s2 :: S.Set Int | ||||||
|  | s2 = S.fromList $ take 5000 stream | ||||||
|  |     where stream = iterate (+2) 1 | ||||||
|  | 
 | ||||||
|  | main :: IO () | ||||||
|  | main = defaultMain | ||||||
|  |     [ bench "member check map" $ whnf (membersMap) 9999 | ||||||
|  |     , bench "member check set" $ whnf (membersSet) 9999 | ||||||
|  |     , bench "insert check set" $ whnf (insertMap) (10001, 10001) | ||||||
|  |     , bench "insert check set" $ whnf (insertSet) 100001 | ||||||
|  |     , bench "union check set" $ whnf (M.union m1) m2 | ||||||
|  |     , bench "union check set" $ whnf (S.union s1) s2 | ||||||
|  |     ] | ||||||
| @ -0,0 +1,24 @@ | |||||||
|  | module Main where | ||||||
|  | 
 | ||||||
|  | import Criterion.Main | ||||||
|  | import qualified Data.Vector as BV | ||||||
|  | import qualified Data.Vector.Unboxed as UV | ||||||
|  | 
 | ||||||
|  | import Control.Monad | ||||||
|  | 
 | ||||||
|  | total :: Int | ||||||
|  | total = 10^6 | ||||||
|  | 
 | ||||||
|  | boxed :: BV.Vector Bool | ||||||
|  | boxed = BV.fromList $ replicate total True | ||||||
|  | 
 | ||||||
|  | unboxed :: UV.Vector Bool | ||||||
|  | unboxed = UV.fromList $ replicate total True | ||||||
|  | 
 | ||||||
|  | main :: IO () | ||||||
|  | main = | ||||||
|  |     defaultMain | ||||||
|  |     [ | ||||||
|  |         bench "any boxed"   $ whnf (BV.and) boxed, | ||||||
|  |         bench "any unboxed" $ whnf (UV.and) unboxed | ||||||
|  |     ] | ||||||
					Loading…
					
					
				
		Reference in new issue