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 +10/−0
- massiv.cabal +3/−1
- src/Data/Massiv/Array.hs +2/−1
- src/Data/Massiv/Array/Delayed/Push.hs +49/−1
- src/Data/Massiv/Array/Delayed/Stream.hs +9/−1
- src/Data/Massiv/Array/Delayed/Windowed.hs +5/−11
- src/Data/Massiv/Array/Mutable.hs +40/−2
- src/Data/Massiv/Array/Numeric/Integral.hs +0/−1
- src/Data/Massiv/Array/Ops/Construct.hs +1/−1
- src/Data/Massiv/Array/Ops/Sort.hs +38/−1
- src/Data/Massiv/Array/Ops/Transform.hs +61/−1
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 #-}