4 patches for repository auryn:Darcs/containers:

Tue Sep 21 12:28:02 CEST 2010  Milan Straka <fox@ucw.cz>
  * Add a testsuite for Data.IntSet.

Tue Sep 21 12:32:25 CEST 2010  Milan Straka <fox@ucw.cz>
  * Add criterion-based benchmark for IntSet.hs.
  
  The benchmark is nearly identical copy of Set.hs benchmark.

Tue Sep 21 13:58:21 CEST 2010  Milan Straka <fox@ucw.cz>
  * Compile only the benchmark source, not the Data/*.hs.

Thu Sep 23 14:56:04 CEST 2010  Milan Straka <fox@ucw.cz>
  * Worker/wrapper transformation for Data.IntSet.

New patches:

[Add a testsuite for Data.IntSet.
Milan Straka <fox@ucw.cz>**20100921102802
 Ignore-this: e55484ee185e71915452bdf2a7b2a2b3
] {
hunk ./Data/IntSet.hs 42
 
 module Data.IntSet  ( 
             -- * Set type
+#if !defined(TESTING)
               IntSet          -- instance Eq,Show
hunk ./Data/IntSet.hs 44
+#else
+              IntSet(..)      -- instance Eq,Show
+#endif
 
             -- * Operators
             , (\\)
hunk ./Data/IntSet.hs 106
             -- * Debugging
             , showTree
             , showTreeWith
+
+#if defined(TESTING)
+            -- * Internals
+            , match
+#endif
             ) where
 
 
hunk ./Data/IntSet.hs 122
 import Data.Maybe (fromMaybe)
 import Data.Typeable
 
-{-
--- just for testing
-import Test.QuickCheck 
-import List (nub,sort)
-import qualified List
-import qualified Data.Set as Set
--}
-
 #if __GLASGOW_HASKELL__
 import Text.Read
 import Data.Data (Data(..), mkNoRepType)
hunk ./Data/IntSet.hs 993
   = case xs of
       []     -> z
       (x:xx) -> let z' = f z x in seq z' (foldlStrict f z' xx)
-
-
-{-
-{--------------------------------------------------------------------
-  Testing
---------------------------------------------------------------------}
-testTree :: [Int] -> IntSet
-testTree xs   = fromList xs
-test1 = testTree [1..20]
-test2 = testTree [30,29..10]
-test3 = testTree [1,4,6,89,2323,53,43,234,5,79,12,9,24,9,8,423,8,42,4,8,9,3]
-
-{--------------------------------------------------------------------
-  QuickCheck
---------------------------------------------------------------------}
-qcheck prop
-  = check config prop
-  where
-    config = Config
-      { configMaxTest = 500
-      , configMaxFail = 5000
-      , configSize    = \n -> (div n 2 + 3)
-      , configEvery   = \n args -> let s = show n in s ++ [ '\b' | _ <- s ]
-      }
-
-
-{--------------------------------------------------------------------
-  Arbitrary, reasonably balanced trees
---------------------------------------------------------------------}
-instance Arbitrary IntSet where
-  arbitrary = do{ xs <- arbitrary
-                ; return (fromList xs)
-                }
-
-
-{--------------------------------------------------------------------
-  Single, Insert, Delete
---------------------------------------------------------------------}
-prop_Single :: Int -> Bool
-prop_Single x
-  = (insert x empty == singleton x)
-
-prop_InsertDelete :: Int -> IntSet -> Property
-prop_InsertDelete k t
-  = not (member k t) ==> delete k (insert k t) == t
-
-
-{--------------------------------------------------------------------
-  Union
---------------------------------------------------------------------}
-prop_UnionInsert :: Int -> IntSet -> Bool
-prop_UnionInsert x t
-  = union t (singleton x) == insert x t
-
-prop_UnionAssoc :: IntSet -> IntSet -> IntSet -> Bool
-prop_UnionAssoc t1 t2 t3
-  = union t1 (union t2 t3) == union (union t1 t2) t3
-
-prop_UnionComm :: IntSet -> IntSet -> Bool
-prop_UnionComm t1 t2
-  = (union t1 t2 == union t2 t1)
-
-prop_Diff :: [Int] -> [Int] -> Bool
-prop_Diff xs ys
-  =  toAscList (difference (fromList xs) (fromList ys))
-    == List.sort ((List.\\) (nub xs)  (nub ys))
-
-prop_Int :: [Int] -> [Int] -> Bool
-prop_Int xs ys
-  =  toAscList (intersection (fromList xs) (fromList ys))
-    == List.sort (nub ((List.intersect) (xs)  (ys)))
-
-{--------------------------------------------------------------------
-  Lists
---------------------------------------------------------------------}
-prop_Ordered
-  = forAll (choose (5,100)) $ \n ->
-    let xs = concat [[i-n,i-n]|i<-[0..2*n :: Int]]
-    in fromAscList xs == fromList xs
-
-prop_List :: [Int] -> Bool
-prop_List xs
-  = (sort (nub xs) == toAscList (fromList xs))
-
-{--------------------------------------------------------------------
-  Bin invariants
---------------------------------------------------------------------}
-powersOf2 :: IntSet
-powersOf2 = fromList [2^i | i <- [0..63]]
-
--- Check the invariant that the mask is a power of 2.
-prop_MaskPow2 :: IntSet -> Bool
-prop_MaskPow2 (Bin _ msk left right) = member msk powersOf2 && prop_MaskPow2 left && prop_MaskPow2 right
-prop_MaskPow2 _ = True
-
--- Check that the prefix satisfies its invariant.
-prop_Prefix :: IntSet -> Bool
-prop_Prefix s@(Bin prefix msk left right) = all (\elem -> match elem prefix msk) (toList s) && prop_Prefix left && prop_Prefix right
-prop_Prefix _ = True
-
--- Check that the left elements don't have the mask bit set, and the right
--- ones do.
-prop_LeftRight :: IntSet -> Bool
-prop_LeftRight (Bin _ msk left right) = and [x .&. msk == 0 | x <- toList left] && and [x .&. msk == msk | x <- toList right]
-prop_LeftRight _ = True
-
-{--------------------------------------------------------------------
-  IntSet operations are like Set operations
---------------------------------------------------------------------}
-toSet :: IntSet -> Set.Set Int
-toSet = Set.fromList . toList
-
--- Check that IntSet.isProperSubsetOf is the same as Set.isProperSubsetOf.
-prop_isProperSubsetOf :: IntSet -> IntSet -> Bool
-prop_isProperSubsetOf a b = isProperSubsetOf a b == Set.isProperSubsetOf (toSet a) (toSet b)
-
--- In the above test, isProperSubsetOf almost always returns False (since a
--- random set is almost never a subset of another random set).  So this second
--- test checks the True case.
-prop_isProperSubsetOf2 :: IntSet -> IntSet -> Bool
-prop_isProperSubsetOf2 a b = isProperSubsetOf a c == (a /= c) where
-  c = union a b
--}
addfile ./tests/intset-properties.hs
hunk ./tests/intset-properties.hs 1
+{-# LANGUAGE CPP, ScopedTypeVariables #-}
+
+-- QuickCheck properties for Data.IntSet
+-- > ghc -DTESTING -fforce-recomp -O2 --make -fhpc -i..  intset-properties.hs
+
+import Data.Bits ((.&.))
+import Data.IntSet
+import Data.List (nub,sort)
+import qualified Data.List as List
+import qualified Data.Set as Set
+import Prelude hiding (lookup, null, map ,filter)
+import Test.QuickCheck hiding ((.&.))
+
+main :: IO ()
+main = do
+    q $ label "prop_Single" prop_Single
+    q $ label "prop_InsertDelete" prop_InsertDelete
+    q $ label "prop_UnionInsert" prop_UnionInsert
+    q $ label "prop_UnionAssoc" prop_UnionAssoc
+    q $ label "prop_UnionComm" prop_UnionComm
+    q $ label "prop_Diff" prop_Diff
+    q $ label "prop_Int" prop_Int
+    q $ label "prop_Ordered" prop_Ordered
+    q $ label "prop_List" prop_List
+    q $ label "prop_MaskPow2" prop_MaskPow2
+    q $ label "prop_Prefix" prop_Prefix
+    q $ label "prop_LeftRight" prop_LeftRight
+    q $ label "prop_isProperSubsetOf" prop_isProperSubsetOf
+    q $ label "prop_isProperSubsetOf2" prop_isProperSubsetOf2
+  where
+    q :: Testable prop => prop -> IO ()
+    q = quickCheckWith args
+{--------------------------------------------------------------------
+  QuickCheck
+--------------------------------------------------------------------}
+
+args :: Args
+args = stdArgs { maxSuccess = 500
+               , maxDiscard = 500
+               }
+
+{--------------------------------------------------------------------
+  Arbitrary, reasonably balanced trees
+--------------------------------------------------------------------}
+instance Arbitrary IntSet where
+  arbitrary = do{ xs <- arbitrary
+                ; return (fromList xs)
+                }
+
+
+{--------------------------------------------------------------------
+  Single, Insert, Delete
+--------------------------------------------------------------------}
+prop_Single :: Int -> Bool
+prop_Single x
+  = (insert x empty == singleton x)
+
+prop_InsertDelete :: Int -> IntSet -> Property
+prop_InsertDelete k t
+  = not (member k t) ==> delete k (insert k t) == t
+
+
+{--------------------------------------------------------------------
+  Union
+--------------------------------------------------------------------}
+prop_UnionInsert :: Int -> IntSet -> Bool
+prop_UnionInsert x t
+  = union t (singleton x) == insert x t
+
+prop_UnionAssoc :: IntSet -> IntSet -> IntSet -> Bool
+prop_UnionAssoc t1 t2 t3
+  = union t1 (union t2 t3) == union (union t1 t2) t3
+
+prop_UnionComm :: IntSet -> IntSet -> Bool
+prop_UnionComm t1 t2
+  = (union t1 t2 == union t2 t1)
+
+prop_Diff :: [Int] -> [Int] -> Bool
+prop_Diff xs ys
+  =  toAscList (difference (fromList xs) (fromList ys))
+    == List.sort ((List.\\) (nub xs)  (nub ys))
+
+prop_Int :: [Int] -> [Int] -> Bool
+prop_Int xs ys
+  =  toAscList (intersection (fromList xs) (fromList ys))
+    == List.sort (nub ((List.intersect) (xs)  (ys)))
+
+{--------------------------------------------------------------------
+  Lists
+--------------------------------------------------------------------}
+prop_Ordered
+  = forAll (choose (5,100)) $ \n ->
+    let xs = concat [[i-n,i-n]|i<-[0..2*n :: Int]]
+    in fromAscList xs == fromList xs
+
+prop_List :: [Int] -> Bool
+prop_List xs
+  = (sort (nub xs) == toAscList (fromList xs))
+
+{--------------------------------------------------------------------
+  Bin invariants
+--------------------------------------------------------------------}
+powersOf2 :: IntSet
+powersOf2 = fromList [2^i | i <- [0..63]]
+
+-- Check the invariant that the mask is a power of 2.
+prop_MaskPow2 :: IntSet -> Bool
+prop_MaskPow2 (Bin _ msk left right) = member msk powersOf2 && prop_MaskPow2 left && prop_MaskPow2 right
+prop_MaskPow2 _ = True
+
+-- Check that the prefix satisfies its invariant.
+prop_Prefix :: IntSet -> Bool
+prop_Prefix s@(Bin prefix msk left right) = all (\elem -> match elem prefix msk) (toList s) && prop_Prefix left && prop_Prefix right
+prop_Prefix _ = True
+
+-- Check that the left elements don't have the mask bit set, and the right
+-- ones do.
+prop_LeftRight :: IntSet -> Bool
+prop_LeftRight (Bin _ msk left right) = and [x .&. msk == 0 | x <- toList left] && and [x .&. msk == msk | x <- toList right]
+prop_LeftRight _ = True
+
+{--------------------------------------------------------------------
+  IntSet operations are like Set operations
+--------------------------------------------------------------------}
+toSet :: IntSet -> Set.Set Int
+toSet = Set.fromList . toList
+
+-- Check that IntSet.isProperSubsetOf is the same as Set.isProperSubsetOf.
+prop_isProperSubsetOf :: IntSet -> IntSet -> Bool
+prop_isProperSubsetOf a b = isProperSubsetOf a b == Set.isProperSubsetOf (toSet a) (toSet b)
+
+-- In the above test, isProperSubsetOf almost always returns False (since a
+-- random set is almost never a subset of another random set).  So this second
+-- test checks the True case.
+prop_isProperSubsetOf2 :: IntSet -> IntSet -> Bool
+prop_isProperSubsetOf2 a b = isProperSubsetOf a c == (a /= c) where
+  c = union a b
}
[Add criterion-based benchmark for IntSet.hs.
Milan Straka <fox@ucw.cz>**20100921103225
 Ignore-this: 3d31a820830c7382748626bc9a1ba54
 
 The benchmark is nearly identical copy of Set.hs benchmark.
] {
addfile ./benchmarks/IntSet.hs
hunk ./benchmarks/IntSet.hs 1
+{-# LANGUAGE BangPatterns #-}
+
+module Main where
+
+import Control.DeepSeq
+import Control.Exception (evaluate)
+import Control.Monad.Trans (liftIO)
+import Criterion.Config
+import Criterion.Main
+import Data.List (foldl')
+import qualified Data.IntSet as S
+
+instance NFData S.IntSet where
+    rnf S.Nil = ()
+    rnf (S.Tip a) = rnf a
+    rnf (S.Bin p m l r) = rnf p `seq` rnf m `seq` rnf l `seq` rnf r
+
+main = do
+    let s = S.fromAscList elems :: S.IntSet
+        s_even = S.fromAscList elems_even :: S.IntSet
+        s_odd = S.fromAscList elems_odd :: S.IntSet
+    defaultMainWith
+        defaultConfig
+        (liftIO . evaluate $ rnf [s, s_even, s_odd])
+        [ bench "member" $ nf (member elems) s
+        , bench "insert" $ nf (ins elems) S.empty
+        , bench "map" $ nf (S.map (+ 1)) s
+        , bench "filter" $ nf (S.filter ((== 0) . (`mod` 2))) s
+        , bench "partition" $ nf (S.partition ((== 0) . (`mod` 2))) s
+        , bench "fold" $ nf (S.fold (:) []) s
+        , bench "delete" $ nf (del elems) s
+        , bench "findMin" $ nf S.findMin s
+        , bench "findMax" $ nf S.findMax s
+        , bench "deleteMin" $ nf S.deleteMin s
+        , bench "deleteMax" $ nf S.deleteMax s
+        , bench "unions" $ nf S.unions [s_even, s_odd]
+        , bench "union" $ nf (S.union s_even) s_odd
+        , bench "difference" $ nf (S.difference s) s_even
+        , bench "intersection" $ nf (S.intersection s) s_even
+        ]
+  where
+    elems = [1..2^10]
+    elems_even = [2,4..2^10]
+    elems_odd = [1,3..2^10]
+
+member :: [Int] -> S.IntSet -> Int
+member xs s = foldl' (\n x -> if S.member x s then n + 1 else n) 0 xs
+
+ins :: [Int] -> S.IntSet -> S.IntSet
+ins xs s0 = foldl' (\s a -> S.insert a s) s0 xs
+
+del :: [Int] -> S.IntSet -> S.IntSet
+del xs s0 = foldl' (\s k -> S.delete k s) s0 xs
hunk ./benchmarks/Makefile 5
 version := $(shell awk '/^version:/{print $$2}' ../$(package).cabal)
 lib := ../dist/build/libHS$(package)-$(version).a
 
-programs := bench-Map bench-Set bench-IntMap
+programs := bench-Map bench-Set bench-IntMap bench-IntSet
 all: $(programs)
 run: $(patsubst %, %.csv, $(programs))
 
}
[Compile only the benchmark source, not the Data/*.hs.
Milan Straka <fox@ucw.cz>**20100921115821
 Ignore-this: f94d9e3ffe126cd057d23490c973a4e9
] hunk ./benchmarks/Makefile 10
 run: $(patsubst %, %.csv, $(programs))
 
 bench-%: %.hs ../Data/%.hs
-	ghc -DTESTING -cpp -O2 -fregs-graph --make -fforce-recomp -i.. -o $@ $^
+	ghc -DTESTING -cpp -O2 -fregs-graph --make -fforce-recomp -i.. -o $@ $<
 
 bench-%.csv: bench-%
 	./bench-$* -u bench-$*.csv +RTS -K10M
[Worker/wrapper transformation for Data.IntSet.
Milan Straka <fox@ucw.cz>**20100923125604
 Ignore-this: b0228582818f7bfb690d0853022a7809
] {
hunk ./Data/IntSet.hs 224
 
 -- | /O(min(n,W))/. Is the value a member of the set?
 member :: Int -> IntSet -> Bool
-member x t
-  = case t of
-      Bin p m l r 
-        | nomatch x p m -> False
-        | zero x m      -> member x l
-        | otherwise     -> member x r
-      Tip y -> (x==y)
-      Nil   -> False
-    
+member x Nil = x `seq` False
+member x t = x `seq` go t
+  where go (Bin p m l r)
+          | nomatch x p m = False
+          | zero x m      = go l
+          | otherwise     = go r
+        go (Tip y) = x == y
 -- | /O(min(n,W))/. Is the element not in the set?
 notMember :: Int -> IntSet -> Bool
 notMember k = not . member k
hunk ./Data/IntSet.hs 237
 
 -- 'lookup' is used by 'intersection' for left-biasing
 lookup :: Int -> IntSet -> Maybe Int
-lookup k t
-  = let nk = natFromInt k  in seq nk (lookupN nk t)
-
-lookupN :: Nat -> IntSet -> Maybe Int
-lookupN k t
-  = case t of
-      Bin _ m l r
-        | zeroN k (natFromInt m) -> lookupN k l
-        | otherwise              -> lookupN k r
-      Tip kx
-        | (k == natFromInt kx)  -> Just kx
-        | otherwise             -> Nothing
-      Nil -> Nothing
+lookup k Nil = k `seq` Nothing
+lookup k t = k `seq` go t
+  where go (Bin _ m l r)
+          | zero k m  = go l
+          | otherwise = go r
+        go (Tip kx)
+          | k == kx   = Just kx
+          | otherwise = Nothing
 
 {--------------------------------------------------------------------
   Construction
hunk ./Data/IntSet.hs 266
 -- an element of the set, it is replaced by the new one, ie. 'insert'
 -- is left-biased.
 insert :: Int -> IntSet -> IntSet
-insert x t
-  = case t of
-      Bin p m l r 
-        | nomatch x p m -> join x (Tip x) p t
-        | zero x m      -> Bin p m (insert x l) r
-        | otherwise     -> Bin p m l (insert x r)
-      Tip y 
-        | x==y          -> Tip x
-        | otherwise     -> join x (Tip x) y t
-      Nil -> Tip x
+insert x = x `seq` go
+  where go t@(Bin p m l r )
+          | nomatch x p m = join x (Tip x) p t
+          | zero x m      = Bin p m (go l) r
+          | otherwise     = Bin p m l (go r)
+        go t@(Tip y)
+          | x==y          = Tip x
+          | otherwise     = join x (Tip x) y t
+        go Nil            = Tip x
 
 -- right-biased insertion, used by 'union'
 insertR :: Int -> IntSet -> IntSet
hunk ./Data/IntSet.hs 278
-insertR x t
-  = case t of
-      Bin p m l r 
-        | nomatch x p m -> join x (Tip x) p t
-        | zero x m      -> Bin p m (insert x l) r
-        | otherwise     -> Bin p m l (insert x r)
-      Tip y 
-        | x==y          -> t
-        | otherwise     -> join x (Tip x) y t
-      Nil -> Tip x
+insertR x = x `seq` go
+  where go t@(Bin p m l r )
+          | nomatch x p m = join x (Tip x) p t
+          | zero x m      = Bin p m (go l) r
+          | otherwise     = Bin p m l (go r)
+        go t@(Tip y)
+          | x==y          = t
+          | otherwise     = join x (Tip x) y t
+        go Nil            = Tip x
 
 -- | /O(min(n,W))/. Delete a value in the set. Returns the
 -- original set when the value was not present.
hunk ./Data/IntSet.hs 291
 delete :: Int -> IntSet -> IntSet
-delete x t
-  = case t of
-      Bin p m l r 
-        | nomatch x p m -> t
-        | zero x m      -> bin p m (delete x l) r
-        | otherwise     -> bin p m l (delete x r)
-      Tip y 
-        | x==y          -> Nil
-        | otherwise     -> t
-      Nil -> Nil
-
+delete x = x `seq` go
+  where go t@(Bin p m l r)
+          | nomatch x p m = t
+          | zero x m      = bin p m (go l) r
+          | otherwise     = bin p m l (go r)
+        go t@(Tip y)
+          | x==y          = Nil
+          | otherwise     = t
+        go t@Nil          = t
 
 {--------------------------------------------------------------------
   Union
hunk ./Data/IntSet.hs 903
 mask i m
   = maskW (natFromInt i) (natFromInt m)
 
-zeroN :: Nat -> Nat -> Bool
-zeroN i m = (i .&. m) == 0
-
 {--------------------------------------------------------------------
   Big endian operations  
 --------------------------------------------------------------------}
}

Context:

[Further improve Data.Set balance function.
Milan Straka <fox@ucw.cz>**20100921091828
 Ignore-this: f23be37859224e9bbe919a3c0a71fdc6
 
 As suggested by Kazu Yamamoto, we split balance to balanceL and
 balanceR, which handle only one-sided inbalance, but need fewer
 tests than balance.
 
 As nearly all functions modifying the structure use balance, this
 results in speedup of many functions. On my 32-bit GHC 6.12.1,
 11% speedup for insert, 12% speedup for delete.
] 
[Further improve Data.Map balance function.
Milan Straka <fox@ucw.cz>**20100921091547
 Ignore-this: 8abfd027142a5183b2b5282e96ccb414
 
 As suggested by Kazu Yamamoto, we split balance to balanceL and
 balanceR, which handle only one-sided inbalance, but need fewer
 tests than balance.
 
 As nearly all functions modifying the structure use balance, this
 results in speedup of many functions. On my 32-bit GHC 6.12.1,
 20% speedup for insert, 7% speedup for delete, 5% speedup for update.
] 
[Changing delta to 3 in Data.Set.
Milan Straka <fox@ucw.cz>**20100921090507
 Ignore-this: a47d0c542ed9cee99ad6b17c52c977a1
 
 Only possible values are 3 and 4. The value 3 has much faster inserts,
 value 4 slightly faster deletes, so choosing 3.
 
 Also changed the inequalities to rebalance only when one subtree
 is _strictly_ larger than delta * the other one, to mimic the behaviour
 from the proof (both from the Adams' and from the one to come).
] 
[Changing delta to 3 in Data.Map.
Milan Straka <fox@ucw.cz>**20100921090358
 Ignore-this: 85f733f836b65b2b1038383ddb92e8e1
 
 Only possible values are 3 and 4. The value 3 has much faster inserts,
 value 4 slightly faster deletes, so choosing 3.
 
 Also changed the inequalities to rebalance only when one subtree
 is _strictly_ larger than delta * the other one, to mimic the behaviour
 from the proof (both from the Adams' and from the one to come).
] 
[Correct Data.Set Arbitrary instance never to return unbalanced trees.
Milan Straka <fox@ucw.cz>**20100914150442
 Ignore-this: b5c70fa98a56f225b8eb5faf420677b0
 
 The previous instance sometimes returned unbalanced trees,
 which broke the tests.
 
 Also the new instance mimics Data.Map instance more closely in the shape
 of the generated trees.
] 
[Correct Data.Map Arbitrary instance never to return unbalanced trees.
Milan Straka <fox@ucw.cz>**20100914145841
 Ignore-this: 114bbcc63acdb16b77140ea56aeb0a95
 
 The previous instance sometimes returned unbalanced trees,
 which broke the tests.
] 
[Improve Data.Set benchmark.
Milan Straka <fox@ucw.cz>**20100914142010
 Ignore-this: 9b878ae3aa5a43ef083abfd7f9b22513
 
 Add union, difference and intersection to Data.Set benchmark.
] 
[Improve benchmark infrastructure and Data.Map benchmark.
Milan Straka <fox@ucw.cz>**20100914141707
 Ignore-this: 67e8dafcb4abcb9c726b9b29c7c320fd
 
 Renamed Benchmarks.hs to Map.hs, as it only benchmarks Data.Map.
 Improve the Makefile to work with multiple benchmarks.
 Add union, difference and intersection to Data.Map benchmark.
] 
[Improve the performance of Data.Set balance function.
Milan Straka <fox@ucw.cz>**20100914140417
 Ignore-this: 577c511c219695b8d483af546c7387e8
 
 The balance function is now one monolithic function, which allows
 to perform all pattern-matches only once.
 
 Nearly all functions modifying Data.Map use balance.
 The improvements are 12% for insert, 14% for delete (GHC 6.12.1).
] 
[Improve the performance of Data.Map balance function.
Milan Straka <fox@ucw.cz>**20100914140217
 Ignore-this: 951181e035fcac90674dff3300350a1
 
 The balance function is now one monolithic function, which allows
 to perform all pattern-matches only once.
 
 Nearly all functions modifying Data.Map use balance.
 The improvements are 7-11% for various insert*, delete*, alter,
 update or intersection functions (GHC 6.12.1).
] 
[Improve performance of Data.Set union and difference operations.
Milan Straka <fox@ucw.cz>**20100914135725
 Ignore-this: 6dc4a186ea060b9cdb9e783db71ca280
 
 Use datatype storing evaluated bound instead of high-order functions.
 The improvements are over 25% for both union and difference (GHC 6.12.1).
] 
[Improve performance of Data.Map union* and difference* operations.
Milan Straka <fox@ucw.cz>**20100914134614
 Ignore-this: 35b23a40ef33e9fa14eb81fdee4b152d
 
 Use datatype storing evaluated bound instead of high-order functions.
 The improvements are 22% for union and 20% for difference (GHC 6.12.1).
] 
[Make the Set store the elements evaluated (bang added).
Milan Straka <fox@ucw.cz>**20100913165132
 Ignore-this: b3f230db5bf30d93d3fddf2c81c5f3b4
] 
[Improved performance of Data.Set
Johan Tibell <johan.tibell@gmail.com>**20100831124352
 Ignore-this: 38a304a0408d29a2956aa9a1fc0ce755
 
 Performance improvements are due to manually applying the
 worker/wrapper transformation and strictifying the keys.
 
 Average speed-up is 32% on a 2GHz Core 2 Duo on OS X 10.5.8
] 
[Added benchmarks for Data.Set
Johan Tibell <johan.tibell@gmail.com>**20100831124225
 Ignore-this: fcacf88761034b8c534d936f0b336cc0
] 
[Added a test suite for Data.Set
Johan Tibell <johan.tibell@gmail.com>**20100831124030
 Ignore-this: f430dc302c0fcb8b5d62db2272a1d6f7
 
 Expression coverage: 74%
] 
[fix warnings
Simon Marlow <marlowsd@gmail.com>**20100831114555
 Ignore-this: 53df71bc054a779b8ad2dad89c09e02d
] 
[Missing MagicHash for IntSet
Don Stewart <dons@galois.com>**20100831093446
 Ignore-this: d075f760adb9a2aa0ee04676e38a07cc
] 
[Performance improvements for Data.IntMap (worker/wrapper and inlining)
Don Stewart <dons@galois.com>**20100831093316
 Ignore-this: 206036448558d270f0eb85ef4cd55368
] 
[Add criterion-based benchmarking for IntMap
Don Stewart <dons@galois.com>**20100831093240
 Ignore-this: d7d85b9afb513532cc30f5b51a3f825e
] 
[Add comprehensive testsuite for IntMap
Don Stewart <dons@galois.com>**20100831093202
 Ignore-this: d455fedbc615e5b63ac488e605550557
] 
[-O2 -fregs-graph is a uniform 10% improvements for IntMap
Don Stewart <dons@galois.com>**20100831092956
 Ignore-this: 2372cf4be945fe7939d0af94e32c567f
] 
[Missed base case for updateAt worker. Spotted by Jan-Willem Maessen
Don Stewart <dons@galois.com>**20100829163329
 Ignore-this: b8daf1c55c163c16f50c3b54cca2dba1
] 
[Major bump (new functions, clarified strictness properties, vastly better performance)
Don Stewart <dons@galois.com>**20100829122628
 Ignore-this: 9bfbc58ecaa24a86be37b8c4cb043457
] 
[Add two new functions: foldlWithKey' and insertLookupWithKey'
Don Stewart <dons@galois.com>**20100829122147
 Ignore-this: a2f112653ba38737fe1b38609e06c314
 
 These two functions use strict accumulators, compared to their existing
 counterparts (which are lazy left folds, that appear not to be useful). 
 Performance is significantly better.
 
] 
[Performance improvements to Data.Map
Don Stewart <dons@galois.com>**20100829120245
 Ignore-this: b4830cddfa6d62e4883f4e0f58ac4e57
 
 Applied several standard transformations to improve the performance of
 code:
 
     * Worker/wrapper of all recursive functions with constant arguments
     * Inlining of all (non-recursive) wrappers
     * Consistent use of strict keys
 
 Average performance improvements across common API (with GHC 6.12.3):
 
     * Linux / x86_64 / 2.6Ghz i7        : 48%
     * Mac OSX 10.5 / x86 / 2 Ghz Xeon   : 36%
 
 Graphs and raw data: http://is.gd/eJHIE
 
 This patch is (mostly) orthogonal to the algorithmic changes suggested
 by Milan Straka in his HW 2010 paper:
 
     http://research.microsoft.com/~simonpj/papers/containers/containers.pdf
 
 Those changes could be added separately, for some additional improvments.
 
 Work carried out over 28/29th August, 2010 in Utrecht, NL, by Johan Tibell
 and Don Stewart.
 
] 
[Add a criterion-based benchmark suite for Data.Map
Don Stewart <dons@galois.com>**20100829114611
 Ignore-this: ec61668f5bcb78bd15b72e2728c01c19
 
 This adds a criterion-based micro-benchmarking suite for Data.Map. It
 can be used to measure performance improvements for individual top-level
 functions.
 
 Examples here: http://is.gd/eJHIE
 
] 
[Add a comprehensive testsuite for Data.Map
Don Stewart <dons@galois.com>**20100829113545
 Ignore-this: 891e7fe6bac3523868714ac1ff51c0a3
 
 This patch adds a joint quickcheck2 / hunit testsuite, with coverage of
 91% of top level functions (remaining features are mostly in instances).
 
 The coverage data is here: 
     
     http://code.haskell.org/~dons/tests/containers/hpc_index.html
 
 No bugs were found. It includes unit tests for known past bugs
 (balancing).
 
] 
[Oops, get the #ifdef symbol correct.
Malcolm.Wallace@me.com**20100902081938] 
[Protect a gratuitous GHC-ism with #ifdefs.
Malcolm.Wallace@me.com**20100902081217] 
[Set Data.Map's delta to 4; fixes #4242
Ian Lynagh <igloo@earth.li>**20100815131954] 
[Add a test for #4242
Ian Lynagh <igloo@earth.li>**20100815131856] 
[Add a local type signature
simonpj@microsoft.com**20100730124447
 Ignore-this: b581d3f2c80a7a860456d589960f12f2
] 
[Add type signature in local where clause
simonpj@microsoft.com**20100727151709
 Ignore-this: 5929c4156500b25b280eb414b508c508
] 
[Fix Data.Sequence's breakr, and add a test for it; fixes trac #4157
Ian Lynagh <igloo@earth.li>**20100704140627] 
[Fix proposal #4109: Make Data.Map.insertWith's strictness consistent
Ian Lynagh <igloo@earth.li>**20100615133055] 
[Tweak layout to work with the alternative layout rule
Ian Lynagh <igloo@earth.li>**20091129154519] 
[Disable building Data.Sequence (and dependents) for nhc98.
Malcolm.Wallace@cs.york.ac.uk**20091124025653
 There is some subtlety of polymorphically recursive datatypes and
 type-class defaulting that nhc98's type system barfs over.
] 
[Fix another instance of non-ghc breakage.
Malcolm.Wallace@cs.york.ac.uk**20091123092637] 
[Add #ifdef around ghc-only (<$) as member of Functor class.
Malcolm.Wallace@cs.york.ac.uk**20091123085155] 
[Fix broken code in non-GHC branch of an ifdef.
Malcolm.Wallace@cs.york.ac.uk**20091123084824] 
[doc bugfix: correct description of index argument
Ross Paterson <ross@soi.city.ac.uk>**20091028105532
 Ignore-this: 9790e7bf422c4cb528722c03cfa4fed9
 
 As noted by iaefai on the libraries list.
 
 Please merge to STABLE.
] 
[Bump version to 0.3.0.0
Ian Lynagh <igloo@earth.li>**20090920141847] 
[update base dependency
Ross Paterson <ross@soi.city.ac.uk>**20090916073125
 Ignore-this: ad382ffc6c6a18c15364e6c072f19edb
 
 The package uses mkNoRepType and Data.Functor, which were not in the
 stable branch of base-4.
] 
[add fast version of <$ for Seq
Ross Paterson <ross@soi.city.ac.uk>**20090916072812
 Ignore-this: 5a39a7d31d39760ed589790b1118d240
] 
[new methods for Data.Sequence (proposal #3271)
Ross Paterson <ross@soi.city.ac.uk>**20090915173324
 Ignore-this: cf17bedd709a6ab3448fd718dcdf62e7
 
 Adds a lot of new methods to Data.Sequence, mostly paralleling those
 in Data.List.  Several of these are significantly faster than versions
 implemented with the previous public interface.  In particular, replicate
 takes O(log n) time and space instead of O(n).
 (by Louis Wasserman)
] 
[Fix "Cabal check" warnings
Ian Lynagh <igloo@earth.li>**20090811215900] 
[TAG 2009-06-25
Ian Lynagh <igloo@earth.li>**20090625160202] 
Patch bundle hash:
61be40493531581e7b58a84c449950a35392eeca
