packages feed

massiv 0.4.3.0 → 0.4.4.0

raw patch · 11 files changed

+218/−21 lines, 11 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Massiv.Array: appendOuterM :: forall ix e m. (Index ix, MonadThrow m) => Array DL ix e -> Array DL ix e -> m (Array DL ix e)
+ Data.Massiv.Array: concatOuterM :: forall ix e m. (Index ix, MonadThrow m) => [Array DL ix e] -> m (Array DL ix e)
+ Data.Massiv.Array: tally :: (Mutable r Ix1 e, Resize r ix, Load r ix e, Ord e) => Array r ix e -> Array DS Ix1 (e, Int)
+ Data.Massiv.Array: zoom :: Source r ix e => Stride ix -> Array r ix e -> Array DL ix e
+ Data.Massiv.Array.Mutable: modify_ :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> (e -> m e) -> ix -> m ()
+ Data.Massiv.Array.Mutable: swap_ :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> ix -> m ()
+ Data.Massiv.Array.Mutable: write_ :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> e -> m ()

Files

CHANGELOG.md view
@@ -1,3 +1,13 @@+# 0.4.4++* Addition of `appendOuterM` and `concatOuterM`+* Addition of `zoom`+* Addition of `write_`, `modify_` and `swap_`++# 0.4.3++* Addition of `catMaybesS` and `tally`+ # 0.4.3  * Addition of `applyStencil` and `Padding` with helper functions `noPadding` and `samePadding`.
massiv.cabal view
@@ -1,5 +1,5 @@ name:                massiv-version:             0.4.3.0+version:             0.4.4.0 synopsis:            Massiv (Массив) is an Array Library. description:         Multi-dimensional Arrays with fusion, stencils and parallel computation. homepage:            https://github.com/lehins/massiv@@ -16,7 +16,9 @@ tested-with:          GHC == 8.4.3                     , GHC == 8.4.4                     , GHC == 8.6.3+                    , GHC == 8.6.4                     , GHC == 8.6.5+                    , GHC == 8.8.1  flag unsafe-checks   description: Enable all the bounds checks for unsafe functions at the cost of
src/Data/Massiv/Array.hs view
@@ -135,6 +135,7 @@   -- * Algorithms   -- ** Sorting   , quicksort+  , tally   -- ** Iterations   , iterateUntil   -- * Conversion@@ -163,7 +164,7 @@ import Data.Massiv.Array.Ops.Fold import Data.Massiv.Array.Ops.Map import Data.Massiv.Array.Ops.Slice-import Data.Massiv.Array.Ops.Sort (quicksort)+import Data.Massiv.Array.Ops.Sort (quicksort, tally) import Data.Massiv.Array.Ops.Transform import Data.Massiv.Array.Stencil import Data.Massiv.Core
src/Data/Massiv/Array/Delayed/Push.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-}@@ -24,6 +25,8 @@   , makeLoadArray   , unsafeMakeLoadArray   , fromStrideLoad+  , appendOuterM+  , concatOuterM   ) where  import Control.Monad@@ -117,6 +120,51 @@     {-# INLINE load #-} {-# INLINE mappendDL #-} +-- | Append two arrays together along the outer most dimension. Inner dimensions must+-- agree, otherwise `SizeMismatchException`.+--+-- @since 0.4.4+appendOuterM ::+     forall ix e m. (Index ix, MonadThrow m)+  => Array DL ix e+  -> Array DL ix e+  -> m (Array DL ix e)+appendOuterM (DLArray c1 sz1 mDef1 load1) (DLArray c2 sz2 mDef2 load2) = do+  let (!i1, !szl1) = unconsSz sz1+      (!i2, !szl2) = unconsSz sz2+  unless (szl1 == szl2) $ throwM $ SizeMismatchException sz1 sz2+  pure $+    DLArray {dlComp = c1 <> c2, dlSize = consSz (i1 + i2) szl1, dlDefault = Nothing, dlLoad = load}+  where+    !k1 = totalElem sz1+    !k2 = totalElem sz2+    load :: Monad n => Scheduler n () -> Int -> (Int -> e -> n ()) -> n ()+    load scheduler !startAt dlWrite = do+      scheduleWork_ scheduler $ do+        S.traverse_ (\def1 -> loopM_ startAt (< k1) (+ 1) (`dlWrite` def1)) mDef1+        load1 scheduler startAt dlWrite+      scheduleWork_ scheduler $ do+        let !startAt2 = startAt + k1+        S.traverse_ (\def2 -> loopM_ startAt2 (< startAt2 + k2) (+ 1) (`dlWrite` def2)) mDef2+        load2 scheduler startAt2 dlWrite+    {-# INLINE load #-}+{-# INLINE appendOuterM #-}++-- | Concat arrays together along the most most dimension. Inner dimensions must agree+-- for all arrays in the list, otherwise `SizeMismatchException`.+--+-- @since 0.4.4+concatOuterM ::+     forall ix e m. (Index ix, MonadThrow m)+  => [Array DL ix e]+  -> m (Array DL ix e)+concatOuterM =+  \case+    [] -> pure empty+    (x:xs) -> F.foldlM appendOuterM x xs+{-# INLINE concatOuterM #-}++ -- | Describe how an array should be loaded into memory sequentially. For parallelizable -- version see `makeLoadArray`. --@@ -203,7 +251,7 @@ toLoadArray :: Load r ix e => Array r ix e -> Array DL ix e toLoadArray arr =   DLArray (getComp arr) (size arr) Nothing $ \scheduler startAt dlWrite ->-    loadArrayM scheduler arr (\ !i -> dlWrite (i + startAt))+    loadArrayM scheduler arr (dlWrite . (+ startAt)) {-# INLINE toLoadArray #-}  -- | Convert an array that can be loaded with stride into `DL` representation.
src/Data/Massiv/Array/Delayed/Stream.hs view
@@ -23,6 +23,7 @@   , filterM   , mapMaybeS   , mapMaybeM+  , catMaybesS   , unfoldr   , unfoldrN   ) where@@ -300,12 +301,19 @@   -- | Apply a function to each element of the array, while discarding `Nothing` and--- keepingt he `Maybe` result.+-- keeping the `Maybe` result. -- -- @since 0.4.1 mapMaybeS :: S.Stream r ix a => (a -> Maybe b) -> Array r ix a -> Array DS Ix1 b mapMaybeS f = DSArray . S.mapMaybe f . S.toStream {-# INLINE mapMaybeS #-}++-- | Keep all `Maybe`s and discard the `Nothing`s.+--+-- @since 0.4.4+catMaybesS :: S.Stream r ix (Maybe a) => Array r ix (Maybe a) -> Array DS Ix1 a+catMaybesS = mapMaybeS id+{-# INLINE catMaybesS #-}   -- | Similar to `mapMaybeS`, but with the use of `Applicative`
src/Data/Massiv/Array/Delayed/Windowed.hs view
@@ -27,7 +27,6 @@   ) where  import Control.Exception (Exception(..))-import Control.Scheduler (trivialScheduler_) import Control.Monad (when) import Data.Massiv.Array.Delayed.Pull import Data.Massiv.Array.Manifest.Boxed@@ -75,12 +74,7 @@   {-# INLINE makeArray #-}  --- TODO: adjust in response to Window--- instance Index ix => Extract DW ix e where---   unsafeExtract sIx newSz = unsafeExtract sIx newSz . dwArray---   {-# INLINE unsafeExtract #-} - instance Functor (Array DW ix) where   fmap f arr@DWArray{dwArray, dwWindow} =     arr@@ -364,7 +358,7 @@   {-# INLINE size #-}   getComp = dComp . dwArray   {-# INLINE getComp #-}-  loadArrayM scheduler = loadWithIxN (scheduleWork scheduler)+  loadArrayM = loadWithIxN   {-# INLINE loadArrayM #-}  instance (Index (IxN n), StrideLoad DW (Ix (n - 1)) e) => StrideLoad DW (IxN n) e where@@ -421,11 +415,11 @@  loadWithIxN ::      (Index ix, Monad m, Load DW (Lower ix) e)-  => (m () -> m ())+  => Scheduler m ()   -> Array DW ix e   -> (Int -> e -> m ())   -> m ()-loadWithIxN with arr uWrite = do+loadWithIxN scheduler arr uWrite = do   let DWArray darr window = arr       DArray {dSize = sz, dIndex = indexBorder} = darr       Window {windowStart, windowSize, windowIndex, windowUnrollIx2} = fromMaybe zeroWindow window@@ -443,8 +437,8 @@       mkLowerArray mw i =         DWArray {dwArray = DArray Seq szL (indexBorder . consDim i), dwWindow = ($ i) <$> mw}       loadLower mw !i =-        with $-        loadArrayM trivialScheduler_ (mkLowerArray mw i) (\k -> uWrite (k + pageElements * i))+        scheduleWork_ scheduler $+        loadArrayM scheduler (mkLowerArray mw i) (\k -> uWrite (k + pageElements * i))       {-# NOINLINE loadLower #-}   loopM_ 0 (< headDim windowStart) (+ 1) (loadLower Nothing)   loopM_ t (< headDim windowEnd) (+ 1) (loadLower (Just mkLowerWindow))
src/Data/Massiv/Array/Mutable.hs view
@@ -20,13 +20,16 @@   , readM   , read'   , write+  , write_   , writeM   , write'   , modify+  , modify_   , modifyM   , modifyM_   , modify'   , swap+  , swap_   , swapM   , swapM_   , swap'@@ -910,6 +913,16 @@   else pure False {-# INLINE write #-} +-- | /O(1)/ - Write an element into the cell of a mutable array. Same as `write` function+-- in case of an out of bounds index it is noop, but unlike `write`, there is no+-- information is returned about was the writing of element successful or not.  In other+-- words, just like `writeM`, but doesn't throw an exception.+--+-- @since 0.4.4+write_ :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> e -> m ()+write_ marr ix = when (isSafeIndex (msize marr) ix) . unsafeWrite marr ix+{-# INLINE write_ #-}+ -- | /O(1)/ - Same as `write`, but throws `IndexOutOfBoundsException` on an invalid index. -- -- @since 0.4.0@@ -946,6 +959,20 @@     else return Nothing {-# INLINE modify #-} +-- | /O(1)/ - Same as `modify`, except that neither the previous value, nor any+-- information on whether the modification was successful are returned. In other words,+-- just like `modifyM_`, but doesn't throw an exception.+--+-- @since 0.4.4+modify_ ::+     (Mutable r ix e, PrimMonad m)+  => MArray (PrimState m) r ix e -- ^ Array to mutate.+  -> (e -> m e) -- ^ Monadic action that modifies the element+  -> ix -- ^ Index at which to perform modification.+  -> m ()+modify_ marr f ix = when (isSafeIndex (msize marr) ix) $ void $ unsafeModify marr f ix+{-# INLINE modify_ #-}+ -- | /O(1)/ - Modify an element in the cell of a mutable array with a supplied -- action. Throws an `IndexOutOfBoundsException` exception for invalid index and returns -- the previous value otherwise.@@ -997,18 +1024,29 @@ {-# DEPRECATED modify' "In favor of more general `modifyM`" #-}  --- | /O(1)/ - Same as `swapM`, but instead of thropwing an exception returns `Nothing` when+-- | /O(1)/ - Same as `swapM`, but instead of throwing an exception returns `Nothing` when -- either one of the indices is out of bounds and `Just` elements under those indices -- otherwise. -- -- @since 0.1.0 swap :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> ix -> m (Maybe (e, e)) swap marr ix1 ix2 =-  let sz = msize marr+  let !sz = msize marr    in if isSafeIndex sz ix1 && isSafeIndex sz ix2         then Just <$> unsafeSwap marr ix1 ix2         else pure Nothing {-# INLINE swap #-}+++-- | /O(1)/ - Same as `swap`, but instead of returning `Nothing` it does nothing. In other+-- words, it is similar to `swapM_`, but does not throw any exceptions.+--+-- @since 0.4.4+swap_ :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> ix -> m ()+swap_ marr ix1 ix2 =+  let !sz = msize marr+   in when (isSafeIndex sz ix1 && isSafeIndex sz ix2) $ void $ unsafeSwap marr ix1 ix2+{-# INLINE swap_ #-}  -- | /O(1)/ - Swap two elements in a mutable array under the supplied indices. Throws an -- `IndexOutOfBoundsException` when either one of the indices is out of bounds and
src/Data/Massiv/Array/Numeric/Integral.hs view
@@ -30,7 +30,6 @@   , fromFunction   -- ** Sampled at the midpoint   , fromFunctionMidpoint-  -- * Helper functions   ) where  import           Data.Coerce
src/Data/Massiv/Array/Ops/Construct.hs view
@@ -258,7 +258,7 @@ -- | Create an array with random values by using a pure splittable random number generator -- such as one provided by either [splitmix](https://www.stackage.org/package/splitmix) or -- [random](https://www.stackage.org/package/random) packages. If you don't have a--- splittable generator consider using `randomArrayS` or `randomArrayIO` instead.+-- splittable generator consider using `randomArrayS` or `randomArrayWS` instead. -- -- Because of the pure nature of the generator and its splitability we are not only able -- to parallelize the random value generation, but also guarantee that it will be
src/Data/Massiv/Array/Ops/Sort.hs view
@@ -10,16 +10,53 @@ -- Portability : non-portable -- module Data.Massiv.Array.Ops.Sort-  ( quicksort+  ( tally+  , quicksort   , quicksortM_   , unsafeUnstablePartitionRegionM   ) where  import Control.Monad (when) import Control.Scheduler+import Data.Massiv.Array.Delayed.Stream import Data.Massiv.Array.Mutable+import Data.Massiv.Array.Ops.Transform import Data.Massiv.Core.Common import System.IO.Unsafe++-- | Count how many occurance of each element there is in the array. Results will be+-- sorted in ascending order of the element.+--+-- ==== __Example__+--+-- >>> import Data.Massiv.Array as A+-- >>> xs = fromList Seq [2, 4, 3, 2, 4, 5, 2, 1] :: Array P Ix1 Int+-- >>> xs+-- Array P Seq (Sz1 8)+--   [ 2, 4, 3, 2, 4, 5, 2, 1 ]+-- >>> tally xs+-- Array DS Seq (Sz1 5)+--   [ (1,1), (2,3), (3,1), (4,2), (5,1) ]+--+-- @since 0.4.4+tally :: (Mutable r Ix1 e, Resize r ix, Load r ix e, Ord e) => Array r ix e -> Array DS Ix1 (e, Int)+tally arr+  | isEmpty arr = setComp (getComp arr) empty+  | otherwise = catMaybesS $ unfoldrN (sz + 1) count (0, 0, sorted ! 0)+  where+    sz@(Sz k) = size sorted+    count (!i, !n, !prev)+      | i < k =+        let !e' = unsafeLinearIndex sorted i+         in if prev == e'+              then Just (Nothing, (i + 1, n + 1, prev))+              else Just (Just (prev, n), (i + 1, 1, e'))+      | otherwise = Just (Just (prev, n), (i + 1, n, prev))+    {-# INLINE count #-}+    sorted = quicksort $ flatten arr+{-# INLINE tally #-}++  -- | Partition a segment of a vector. Starting and ending indices are unchecked. --
src/Data/Massiv/Array/Ops/Transform.hs view
@@ -45,8 +45,10 @@   , unsnocM   -- , lastM   -- , last'+  , appendOuterM   , appendM   , append'+  , concatOuterM   , concatM   , concat'   , splitAtM@@ -58,6 +60,7 @@   , upsample   , downsample   -- ** Zoom+  , zoom   , zoomWithGrid   -- ** Transform   , transformM@@ -886,7 +889,14 @@ -- ==== __Example__ -- -- >>> import Data.Massiv.Array as A--- >>> zoomWithGrid 0 (Stride (2 :. 3)) $ resize' (Sz2 3 2) (Ix1 1 ... 6)+-- >>> arr = resize' (Sz2 3 2) (Ix1 1 ... 6)+-- >>> arr+-- Array D Seq (Sz (3 :. 2))+--   [ [ 1, 2 ]+--   , [ 3, 4 ]+--   , [ 5, 6 ]+--   ]+-- >>> zoomWithGrid 0 (Stride (2 :. 3)) arr -- Array DL Seq (Sz (10 :. 9)) --   [ [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ] --   , [ 0, 1, 1, 1, 0, 2, 2, 2, 0 ]@@ -918,3 +928,53 @@     !lastNewIx = liftIndex2 (*) kx $ unSz (size arr)     !newSz = Sz (liftIndex (+1) lastNewIx) {-# INLINE zoomWithGrid #-}++-- | Increaze the size of the array accoridng to the stride multiplier while replicating+-- the same element to fill the neighbors. It is exactly the same as `zoomWithGrid`, but+-- without the grid.+--+-- ==== __Example__+--+-- >>> import Data.Massiv.Array as A+-- >>> arr = resize' (Sz3 1 3 2) (Ix1 1 ... 6)+-- >>> arr+-- Array D Seq (Sz (1 :> 3 :. 2))+--   [ [ [ 1, 2 ]+--     , [ 3, 4 ]+--     , [ 5, 6 ]+--     ]+--   ]+-- >>> zoom (Stride (2 :> 2 :. 3)) arr+-- Array DL Seq (Sz (2 :> 6 :. 6))+--   [ [ [ 1, 1, 1, 2, 2, 2 ]+--     , [ 1, 1, 1, 2, 2, 2 ]+--     , [ 3, 3, 3, 4, 4, 4 ]+--     , [ 3, 3, 3, 4, 4, 4 ]+--     , [ 5, 5, 5, 6, 6, 6 ]+--     , [ 5, 5, 5, 6, 6, 6 ]+--     ]+--   , [ [ 1, 1, 1, 2, 2, 2 ]+--     , [ 1, 1, 1, 2, 2, 2 ]+--     , [ 3, 3, 3, 4, 4, 4 ]+--     , [ 3, 3, 3, 4, 4, 4 ]+--     , [ 5, 5, 5, 6, 6, 6 ]+--     , [ 5, 5, 5, 6, 6, 6 ]+--     ]+--   ]+--+-- @since 0.4.4+zoom ::+     Source r ix e+  => Stride ix -- ^ Scaling factor+  -> Array r ix e -- ^ Source array+  -> Array DL ix e+zoom (Stride zoomFactor) arr =+  unsafeMakeLoadArray Seq newSz Nothing $ \scheduler _ writeElement ->+    iforSchedulerM_ scheduler arr $ \ !ix !e -> do+      let !kix = liftIndex2 (*) ix zoomFactor+      mapM_ (\ !ix' -> writeElement (toLinearIndex newSz ix') e) $+        range Seq kix (liftIndex2 (+) kix zoomFactor)+  where+    !lastNewIx = liftIndex2 (*) zoomFactor $ unSz (size arr)+    !newSz = Sz lastNewIx+{-# INLINE zoom #-}