packages feed

circular 0.3.0 → 0.3.1

raw patch · 5 files changed

+104/−57 lines, 5 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.Stack.Circular: [mStack] :: MStack v s a -> Mutable v s a
- Data.Stack.Circular: foldl :: (Vector v b, PrimMonad m) => (a -> b -> a) -> a -> MStack v (PrimState m) b -> m a
- Data.Stack.Circular: product :: (Num a, Vector v a, PrimMonad m) => MStack v (PrimState m) a -> m a
- Data.Stack.Circular: sum :: (Num a, Vector v a, PrimMonad m) => MStack v (PrimState m) a -> m a
+ Data.Stack.Circular: [mVector] :: MStack v s a -> Mutable v s a
+ Data.Stack.Circular: foldKM :: (Vector v b, PrimMonad m) => Int -> (a -> b -> a) -> a -> MStack v (PrimState m) b -> m a
+ Data.Stack.Circular: foldM :: (Vector v b, PrimMonad m) => (a -> b -> a) -> a -> MStack v (PrimState m) b -> m a

Files

ChangeLog.md view
@@ -5,6 +5,12 @@ ## Unreleased changes  +## 0.3.1++-   Change monadic folds so that commutativity is not anymore required.+-   Provide `foldKM`, a fold over the last k elements on the stack.++ ## 0.3.0  -   Bugfix `take`.
bench/Bench.hs view
@@ -30,13 +30,13 @@ cstackV l = runST $ do   c <- C.replicate 1000 0 :: ST s (C.MStack V.Vector s Int)   c' <- foldlM (flip C.push) c [0 .. l]-  C.sum c'+  C.foldM (+) 0 c'  cstackU :: Int -> Int cstackU l = runST $ do   c <- C.replicate 1000 0 :: ST s (C.MStack U.Vector s Int)   c' <- foldlM (flip C.push) c [0 .. l]-  C.sum c'+  C.foldM (+) 0 c'  -- When using foldr, cstack is slower by far. This is because list are lazy. 
circular.cabal view
@@ -1,6 +1,6 @@ cabal-version:  1.12 name:           circular-version:        0.3.0+version:        0.3.1 synopsis:       Circular fixed-sized mutable vectors description:    Please see the README at <https://github.com/dschrempf/circular#readme> category:       Math, Data Structures
src/Data/Stack/Circular.hs view
@@ -37,14 +37,9 @@     pop,     push, -    -- ** Folds--    -- | __Commutativity__ of the combining function is __assumed__ for-    -- fold-like functions provided in this module, that is, the order of-    -- elements of the stack must not matter!-    foldl,-    sum,-    product,+    -- ** Monadic folds+    foldM,+    foldKM,      -- * Immutable circular stacks     Stack (..),@@ -56,7 +51,6 @@ import Control.Monad.Primitive import Data.Aeson import Data.Aeson.TH-import qualified Data.Foldable as F import qualified Data.Vector.Generic as VG import qualified Data.Vector.Generic.Mutable as VM import Prelude hiding (foldl, product, replicate, sum, take)@@ -64,7 +58,7 @@ -- | Mutable circular stacks with fixed size are just mutable vectors with a -- pointer to the last element. data MStack v s a = MStack-  { mStack :: VG.Mutable v s a,+  { mVector :: VG.Mutable v s a,     mIndex :: !Int   } @@ -81,9 +75,8 @@     return $ MStack v 0  -- | Convert a vector to a circular stack with size being equal to the length of--- the vector. The first element of the vector is the deepest (oldest) element--- of the stack, the last element of the vector is the current (newest) element--- of the stack.+-- the vector. The first element of the vector is the oldest element of the+-- stack, the last element of the vector is the youngest element of the stack. -- -- The vector must be non-empty. --@@ -98,8 +91,8 @@     n = VG.length v  -- | Convert a circular stack to a vector. The first element of the returned--- vector is the deepest (oldest) element of the stack, the last element of the--- returned vector is the current (newest) element of the stack.+-- vector is the oldest element of the stack, the last element of the returned+-- vector is the youngest element of the stack. -- -- O(n). toVector :: (VG.Vector v a, PrimMonad m) => MStack v (PrimState m) a -> m (v a)@@ -107,12 +100,12 @@   l <- VG.freeze $ VM.unsafeDrop i' v   r <- VG.freeze $ VM.unsafeTake i' v   return $ l VG.++ r-  where i' = i+1+  where+    i' = i + 1  -- | Convert the last k elements of a circular stack to a vector. The first--- element of the returned vector is the deepest (oldest) element of the stack,--- the last element of the returned vector is the current (newest) element of--- the stack.+-- element of the returned vector is the oldest element of the stack, the last+-- element of the returned vector is the youngest element of the stack. -- -- The size of the stack must be larger than k. --@@ -130,7 +123,7 @@     -- The length of r is i'.     r <- VG.freeze $ VM.unsafeTake i' v     -- The length of l has to be k-i'. So we have to drop n-(k-i')=n+i0.-    l <- VG.freeze $ VM.unsafeDrop (n+i0) v+    l <- VG.freeze $ VM.unsafeDrop (n + i0) v     return $ l VG.++ r   where     n = VM.length v@@ -145,14 +138,14 @@ get (MStack v i) = VM.unsafeRead v i {-# INLINE get #-} --- Select the previous element without changing the stack.+-- Select the previous older element without changing the stack. previous :: VG.Vector v a => MStack v s a -> MStack v s a previous (MStack v i) = MStack v i'   where     j = i - 1     i' = if j < 0 then VM.length v - 1 else j --- | Pop the current element from the stack and put the focus on the previous+-- | Pop the youngest element from the stack and put the focus on the previous -- element. -- -- Be careful:@@ -170,11 +163,11 @@   val <- get x   return (val, previous x) --- Replace the current element.+-- Replace the youngest element. put :: (VG.Vector v a, PrimMonad m) => a -> MStack v (PrimState m) a -> m (MStack v (PrimState m) a) put x (MStack v i) = VM.unsafeWrite v i x >> return (MStack v i) --- Select the next element without changing the stack.+-- Select the next younger element without changing the stack. next :: VG.Vector v a => MStack v s a -> MStack v s a next (MStack v i) = MStack v i'   where@@ -186,35 +179,49 @@ push :: (VG.Vector v a, PrimMonad m) => a -> MStack v (PrimState m) a -> m (MStack v (PrimState m) a) push x = put x . next --- Left fold over a mutable vector. This is all a little stupid.-foldlMV :: (VM.MVector v b, PrimMonad m) => (a -> b -> a) -> a -> v (PrimState m) b -> m a-foldlMV f x v = F.foldlM (\acc i -> f acc <$> VM.unsafeRead v i) x [0 .. (n -1)]-  where-    n = VM.length v---- | Left fold over all elements of the stack.+-- | Monadic fold from young to old over all elements of the stack. ----- Please see the documentation of 'pop'.+-- Please also see the documentation of 'pop'. -- -- O(n).-foldl :: (VG.Vector v b, PrimMonad m) => (a -> b -> a) -> a -> MStack v (PrimState m) b -> m a-foldl f x (MStack v _) = foldlMV f x v+foldM :: (VG.Vector v b, PrimMonad m) => (a -> b -> a) -> a -> MStack v (PrimState m) b -> m a+foldM f x s = foldKM n f x s+  where n = VM.length $ mVector s --- | Compute the sum of the elements on the stack.------ Please see the documentation of 'pop'.------ O(n).-sum :: (Num a, VG.Vector v a, PrimMonad m) => MStack v (PrimState m) a -> m a-sum = foldl (+) 0+-- Monadic fold over k elements in a vector.+foldKV ::+  (VM.MVector v b, PrimMonad m) =>+  -- Number of elements to take.+  Int ->+  -- Current index.+  Int ->+  (a -> b -> a) ->+  a ->+  v (PrimState m) b ->+  m a+foldKV 0 _ _ x _ = return x+foldKV k i f x v = do+  x' <- f x <$> VM.unsafeRead v i+  -- Assume that i-1 is non-negative.+  foldKV (k-1) (i-1) f x' v --- | Compute the product of the elements on the stack.------ Please see the documentation of 'pop'.+-- | See 'foldM' but only over the @k@ youngest elements on the stack. ----- O(n).-product :: (Num a, VG.Vector v a, PrimMonad m) => MStack v (PrimState m) a -> m a-product = foldl (*) 1+-- O(k).+foldKM :: (VG.Vector v b, PrimMonad m) => Int -> (a -> b -> a) -> a -> MStack v (PrimState m) b -> m a+foldKM k f x (MStack v i)+  | k < 0 = error "foldKM: k is negative."+  | k > n = error "foldKM: k is larger than the stack size."+  -- We can do the fold in one go.+  | k <= i' = foldKV k i f x v+  -- Or not.+  | otherwise = do+      x' <- foldKV i' i f x v+      -- Continue from the end of the vector.+      foldKV (k-i') (n-1) f x' v+  where+    n = VM.length v+    i' = i+1  -- | Immutable circular stack; useful, for example, to save, or restore a -- mutable circular stack.
test/Data/Stack/CircularSpec.hs view
@@ -23,6 +23,7 @@ import Control.Monad.Primitive import Control.Monad.ST import Data.Aeson+import Data.List import qualified Data.Stack.Circular as C import qualified Data.Vector as VB -- import Debug.Trace@@ -46,6 +47,12 @@ ss :: PrimMonad m => m (C.MStack VB.Vector (PrimState m) Int) ss = se >>= C.push 13 +s3 :: PrimMonad m => m (C.MStack VB.Vector (PrimState m) Int)+s3 = ss >>= C.push 12 >>= C.push 11++s3' :: PrimMonad m => m (C.MStack VB.Vector (PrimState m) Int)+s3' = se >>= (fmap snd <$> C.pop) >>= C.push 1 >>= C.push 2 >>= C.push 3+ fromTo :: VB.Vector Int -> VB.Vector Int fromTo v = runST $ C.fromVector v >>= C.toVector @@ -63,7 +70,7 @@ prop_push x v   | VB.length v == 0 = True   | otherwise =-    (runST $ C.fromVector v >>= C.push x >>= C.toVector)+    runST (C.fromVector v >>= C.push x >>= C.toVector)       == VB.tail v VB.++ VB.singleton x  prop_many_pushes :: [Int] -> VB.Vector Int -> Bool@@ -71,11 +78,12 @@   | VB.length v == 0 = True   | length xs <= VB.length v = True   | otherwise =-    ( runST $ do-        ms <- C.fromVector v-        ms' <- foldM (flip C.push) ms xs-        C.toVector ms'-    )+    runST+      ( do+          ms <- C.fromVector v+          ms' <- foldM (flip C.push) ms xs+          C.toVector ms'+      )       == sol   where     nl = length xs@@ -102,7 +110,7 @@     --       ++ " Sol: "     --       ++ show solution     --   ) $-      stackTake == solution+    stackTake == solution   where     -- stackFull = runST $ do     --   m <- C.fromVector v@@ -129,6 +137,20 @@         -- So we need to drop (nv - k' + nl) from the beginning of the vector.           VB.drop (nv - k' + nl) v VB.++ VB.fromList l +-- We initialize a stack, push some values and take some values.+prop_fold_independent_of_index :: VB.Vector Int -> Bool+prop_fold_independent_of_index v+  | VB.length v == 0 = True+  | otherwise = do+    [solV] == nub solSs+  where+    n = VB.length v+    solV = VB.sum v+    solSs =+      runST $ do+        stack <- C.fromVector v+        sequence [C.foldM (+) 0 (stack {C.mIndex = i}) | i <- [0 .. n - 1 :: Int]]+ spec :: Spec spec = do   describe "construction" $@@ -145,9 +167,21 @@     it "fails to convert empty vectors" $       evaluate (runST $ C.fromVector VB.empty >>= C.freeze) `shouldThrow` anyErrorCall +  describe "foldKM over end" $+    it "works" $ do+      runST (s3 >>= C.foldKM 1 (+) 0) `shouldBe` 11+      runST (s3 >>= C.foldKM 2 (+) 0) `shouldBe` (11 + 12)+      runST (s3 >>= C.foldKM 3 (+) 0) `shouldBe` (11 + 12 + 13)+      runST (s3 >>= C.foldKM 4 (+) 0) `shouldBe` (11 + 12 + 13)+      runST (s3 >>= C.foldKM 3 (*) 1) `shouldBe` (11 * 12 * 13)+      runST (s3 >>= C.foldKM 4 (*) 1) `shouldBe` 0+      runST (s3' >>= C.foldKM 3 (*) 1) `shouldBe` 6+      runST (s3' >>= C.foldKM 4 (*) 1) `shouldBe` 0+   describe "properties" $ do     prop "push" prop_push     prop "push_get" prop_push_get     prop "many pushes" prop_many_pushes     prop "json" prop_json     prop "push_take" prop_push_take+    prop "fold_independent_of_index" prop_fold_independent_of_index