packages feed

massiv 0.3.5.0 → 0.3.6.0

raw patch · 17 files changed

+449/−28 lines, 17 filesdep +ghc-primdep ~primitivePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: ghc-prim

Dependency ranges changed: primitive

API changes (from Hackage documentation)

+ Data.Massiv.Array: iterateUntil :: (Load r' ix e, Mutable r ix e) => (Int -> Array r ix e -> Array r ix e -> Bool) -> (Int -> Array r ix e -> Array r' ix e) -> Array r ix e -> Array r ix e
+ Data.Massiv.Array.Mutable.Algorithms: iterateUntilM :: (Load r' ix e, Mutable r ix e, PrimMonad m, MonadIO m, PrimState m ~ RealWorld) => (Int -> Array r ix e -> MArray (PrimState m) r ix e -> m Bool) -> (Int -> Array r ix e -> Array r' ix e) -> Array r ix e -> m (Array r ix e)
+ Data.Massiv.Array.Numeric: identityMatrix :: Int -> Array DL Ix2 Int
+ Data.Massiv.Array.Unsafe: unsafeArrayLinearCopy :: (Mutable r ix e, PrimMonad m) => Array r ix e -> Ix1 -> MArray (PrimState m) r ix e -> Ix1 -> Sz1 -> m ()
+ Data.Massiv.Array.Unsafe: unsafeLinearCopy :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> Ix1 -> MArray (PrimState m) r ix e -> Ix1 -> Sz1 -> m ()
+ Data.Massiv.Array.Unsafe: unsafeLinearGrow :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> Sz ix -> m (MArray (PrimState m) r ix e)
+ Data.Massiv.Array.Unsafe: unsafeLinearShrink :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> Sz ix -> m (MArray (PrimState m) r ix e)
- Data.Massiv.Array.Unsafe: unsafeLinearSet :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> Int -> Int -> e -> m ()
+ Data.Massiv.Array.Unsafe: unsafeLinearSet :: (Mutable r ix e, PrimMonad m) => MArray (PrimState m) r ix e -> Ix1 -> Int -> e -> m ()

Files

CHANGELOG.md view
@@ -1,3 +1,9 @@+# 0.3.6++* Addition of `unsafeArrayLinearCopy`, `unsafeLinearCopy`, `unsafeLinearShrink`, `unsafeLinearGrow`+* Implementation of `iterateUntil` and `iterateUntilM`+* `identityMatrix` - generation of identity matrix+ # 0.3.5  * Fix and export `guardNumberOfElements`
massiv.cabal view
@@ -1,5 +1,5 @@ name:                massiv-version:             0.3.5.0+version:             0.3.6.0 synopsis:            Massiv (Массив) is an Array Library. description:         Multi-dimensional Arrays with fusion, stencils and parallel computation. homepage:            https://github.com/lehins/massiv@@ -79,6 +79,10 @@                      , primitive                      , unliftio-core                      , vector++  if impl(ghc < 8.4)+    build-depends: ghc-prim+   include-dirs: include   install-includes: massiv.h 
src/Data/Massiv/Array.hs view
@@ -118,8 +118,11 @@   , module Data.Massiv.Array.Ops.Transform   -- * Slicing   , module Data.Massiv.Array.Ops.Slice-  -- * Sorting+  -- * Algorithms+  -- ** Sorting   , quicksort+  -- ** Iterations+  , iterateUntil   -- * Conversion   , module Data.Massiv.Array.Manifest.List   -- * Mutable
src/Data/Massiv/Array/Delayed/Pull.hs view
@@ -28,7 +28,6 @@ import qualified Data.Foldable as F import Data.Massiv.Array.Ops.Fold.Internal as A import Data.Massiv.Core.Common-import Data.Massiv.Core.Index.Internal import Data.Massiv.Core.List (L, showArrayList, showsArrayPrec) import GHC.Base (build) import Prelude hiding (zipWith)
src/Data/Massiv/Array/Manifest/Internal.hs view
@@ -38,6 +38,8 @@   , fromRaggedArray   , sizeofArray   , sizeofMutableArray+  , iterateUntil+  , iterateUntilM   ) where  import Control.Exception (try)@@ -375,3 +377,131 @@      (Mutable r ix e, StrideLoad r' ix e) => r -> Stride ix -> Array r' ix e -> Array r ix e computeWithStrideAs _ = computeWithStride {-# INLINE computeWithStrideAs #-}++++-- | Efficiently iterate a function until a convergence condition is satisfied. If the+-- size of array doesn't change between iterations then no more than two new arrays will be+-- allocated, regardless of the number of iterations. If the size does change from one+-- iteration to another, an attempt will be made to grow/shrink the intermediate mutable+-- array instead of allocating a new one.+--+-- ====__Example__+--+-- >>> import Data.Massiv.Array+-- >>> a = computeAs P $ makeLoadArrayS (Sz2 8 8) (0 :: Int) $ \ w -> w (0 :. 0) 1 >> pure ()+-- >>> a+-- Array P Seq (Sz (8 :. 8))+--   [ [ 1, 0, 0, 0, 0, 0, 0, 0 ]+--   , [ 0, 0, 0, 0, 0, 0, 0, 0 ]+--   , [ 0, 0, 0, 0, 0, 0, 0, 0 ]+--   , [ 0, 0, 0, 0, 0, 0, 0, 0 ]+--   , [ 0, 0, 0, 0, 0, 0, 0, 0 ]+--   , [ 0, 0, 0, 0, 0, 0, 0, 0 ]+--   , [ 0, 0, 0, 0, 0, 0, 0, 0 ]+--   , [ 0, 0, 0, 0, 0, 0, 0, 0 ]+--   ]+-- >>> nextPascalRow cur above = if cur == 0 then above else cur+-- >>> pascal = makeStencil (Sz2 2 2) 1 $ \ get -> nextPascalRow <$> get (0 :. 0) <*> get (-1 :. -1) + get (-1 :. 0)+-- >>> iterateUntil (\_ _ a -> (a ! (7 :. 7)) /= 0) (\ _ -> mapStencil (Fill 0) pascal) a+-- Array P Seq (Sz (8 :. 8))+--   [ [ 1, 0, 0, 0, 0, 0, 0, 0 ]+--   , [ 1, 1, 0, 0, 0, 0, 0, 0 ]+--   , [ 1, 2, 1, 0, 0, 0, 0, 0 ]+--   , [ 1, 3, 3, 1, 0, 0, 0, 0 ]+--   , [ 1, 4, 6, 4, 1, 0, 0, 0 ]+--   , [ 1, 5, 10, 10, 5, 1, 0, 0 ]+--   , [ 1, 6, 15, 20, 15, 6, 1, 0 ]+--   , [ 1, 7, 21, 35, 35, 21, 7, 1 ]+--   ]+--+-- @since 0.3.6+iterateUntil ::+     (Load r' ix e, Mutable r ix e)+  => (Int -> Array r ix e -> Array r ix e -> Bool)+  -- ^ Convergence condition. Accepts current iteration counter, array at the previous+  -- state and at the current state.+  -> (Int -> Array r ix e -> Array r' ix e)+  -- ^ A modifying function to apply at each iteration. The size of resulting array may+  -- differ if necessary+  -> Array r ix e -- ^ Initial source array+  -> Array r ix e+iterateUntil convergence iteration initArr0+  | convergence 0 initArr0 initArr1 = initArr1+  | otherwise =+    unsafePerformIO $ do+      let loadArr = iteration 1 initArr1+      marr <- unsafeNew (size loadArr)+      iterateLoop+        (\n a a' _ -> pure $ convergence n a a')+        iteration+        1+        initArr1+        loadArr+        (asArr initArr0 marr)+  where+    !initArr1 = compute $ iteration 0 initArr0+    asArr :: Array r ix e -> MArray s r ix e -> MArray s r ix e+    asArr _ = id+{-# INLINE iterateUntil #-}++-- | Monadic version of `iterateUntil` where at each iteration mutable version of an array+-- is available.+--+-- @since 0.3.6+iterateUntilM ::+     (Load r' ix e, Mutable r ix e, PrimMonad m, MonadIO m, PrimState m ~ RealWorld)+  => (Int -> Array r ix e -> MArray (PrimState m) r ix e -> m Bool)+  -- ^ Convergence condition. Accepts current iteration counter, pure array at previous+  -- state and a mutable at the current state, therefore after each iteration its contents+  -- can be modifed if necessary.+  -> (Int -> Array r ix e -> Array r' ix e)+  -- ^ A modifying function to apply at each iteration.  The size of resulting array may+  -- differ if necessary.+  -> Array r ix e -- ^ Initial source array+  -> m (Array r ix e)+iterateUntilM convergence iteration initArr0 = do+  let loadArr0 = iteration 0 initArr0+  initMArr1 <- unsafeNew (size loadArr0)+  computeInto initMArr1 loadArr0+  shouldStop <- convergence 0 initArr0 initMArr1+  initArr1 <- unsafeFreeze (getComp loadArr0) initMArr1+  if shouldStop+    then pure initArr1+    else do+      let loadArr1 = iteration 1 initArr1+      marr <- unsafeNew (size loadArr1)+      iterateLoop (\n a _ -> convergence n a) iteration 1 initArr1 loadArr1 marr+{-# INLINE iterateUntilM #-}+++iterateLoop ::+     (Load r' ix e, Mutable r ix e, PrimMonad m, MonadIO m, PrimState m ~ RealWorld)+  => (Int -> Array r ix e -> Array r ix e -> MArray (PrimState m) r ix e -> m Bool)+  -> (Int -> Array r ix e -> Array r' ix e)+  -> Int+  -> Array r ix e+  -> Array r' ix e+  -> MArray (PrimState m) r ix e+  -> m (Array r ix e)+iterateLoop convergence iteration = go+  where+    go !n !arr !loadArr !marr = do+      let !sz = size loadArr+          !k = totalElem sz+          !mk = totalElem (msize marr)+      marr' <-+        if k == mk+          then pure marr+          else if k < mk+                 then unsafeLinearShrink marr sz+                 else unsafeLinearGrow marr sz+      computeInto marr' loadArr+      arr' <- unsafeFreeze (getComp loadArr) marr'+      shouldStop <- convergence n arr arr' marr'+      if shouldStop+        then pure arr'+        else do+          nextMArr <- unsafeThaw arr+          go (n + 1) arr' (iteration (n + 1) arr') nextMArr+{-# INLINE iterateLoop #-}
src/Data/Massiv/Array/Manifest/Primitive.hs view
@@ -26,6 +26,7 @@   , toMutableByteArray   , fromMutableByteArrayM   , fromMutableByteArray+  , shrinkMutableByteArray   , unsafeAtomicReadIntArray   , unsafeAtomicWriteIntArray   , unsafeCasIntArray@@ -51,6 +52,9 @@ import Data.Primitive.Types import GHC.Base (Int(..)) import GHC.Exts as GHC+#if !MIN_VERSION_base(4,11,0)+import GHC.Prim as GHC+#endif import Prelude hiding (mapM) import System.IO.Unsafe (unsafePerformIO) @@ -193,7 +197,26 @@   unsafeLinearSet (MPArray _ ma) = setByteArray ma   {-# INLINE unsafeLinearSet #-} +  unsafeLinearCopy (MPArray _ maFrom) iFrom (MPArray _ maTo) iTo (Sz k) =+    copyMutableByteArray maTo (iTo * esz) maFrom (iFrom * esz) (k * esz)+    where esz = sizeOf (undefined :: e)+  {-# INLINE unsafeLinearCopy #-} +  unsafeArrayLinearCopy (PArray _ _ aFrom) iFrom (MPArray _ maTo) iTo (Sz k) =+    copyByteArray maTo (iTo * esz) aFrom (iFrom * esz) (k * esz)+    where esz = sizeOf (undefined :: e)+  {-# INLINE unsafeArrayLinearCopy #-}++  unsafeLinearShrink (MPArray _ ma) sz = do+    shrinkMutableByteArray ma (totalElem sz * sizeOf (undefined :: e))+    pure $ MPArray sz ma+  {-# INLINE unsafeLinearShrink #-}++  unsafeLinearGrow (MPArray _ ma) sz =+    MPArray sz <$> resizeMutableByteArray ma (totalElem sz * sizeOf (undefined :: e))+  {-# INLINE unsafeLinearGrow #-}++ instance (Prim e, Index ix) => Load P ix e where   size = pSize   {-# INLINE size #-}@@ -458,3 +481,24 @@   mba   (toLinearIndex sz ix) {-# INLINE unsafeAtomicXorIntArray #-}++++#if !MIN_VERSION_primitive(0,6,4)+resizeMutableByteArray ::+     PrimMonad m => MutableByteArray (PrimState m) -> Int -> m (MutableByteArray (PrimState m))+resizeMutableByteArray (MutableByteArray arr#) (I# n#) =+  primitive+    (\s# ->+       case resizeMutableByteArray# arr# n# s# of+         (# s'#, arr'# #) -> (# s'#, MutableByteArray arr'# #))+{-# INLINE resizeMutableByteArray #-}+#endif++shrinkMutableByteArray :: forall m. (PrimMonad m)+  => MutableByteArray (PrimState m)+  -> Int -- ^ new size+  -> m ()+{-# INLINE shrinkMutableByteArray #-}+shrinkMutableByteArray (MutableByteArray arr#) (I# n#)+  = primitive_ (shrinkMutableByteArray# arr# n#)
src/Data/Massiv/Array/Manifest/Storable.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MagicHash #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-}@@ -32,8 +33,11 @@  import Control.DeepSeq (NFData(..), deepseq) import Control.Monad.IO.Unlift+import Control.Monad.Primitive (unsafePrimToPrim) import Data.Massiv.Array.Delayed.Pull (eq, ord) import Data.Massiv.Array.Manifest.Internal+import Data.Massiv.Array.Manifest.Primitive (shrinkMutableByteArray)+import Data.Primitive.ByteArray (MutableByteArray(..)) import Data.Massiv.Array.Manifest.List as A import Data.Massiv.Array.Mutable import Data.Massiv.Core.Common@@ -41,8 +45,11 @@ import qualified Data.Vector.Generic.Mutable as VGM import qualified Data.Vector.Storable as VS import qualified Data.Vector.Storable.Mutable as MVS-import Foreign.ForeignPtr import Foreign.Ptr+import GHC.ForeignPtr (ForeignPtr(..), ForeignPtrContents(..))+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Storable+import Foreign.Marshal.Array (copyArray, advancePtr) import GHC.Exts as GHC (IsList(..)) import Prelude hiding (mapM) import System.IO.Unsafe (unsafePerformIO)@@ -155,6 +162,43 @@   unsafeLinearWrite (MSArray _ mv) =     INDEX_CHECK("(Mutable S ix e).unsafeLinearWrite", Sz . MVS.length, MVS.unsafeWrite) mv   {-# INLINE unsafeLinearWrite #-}++  -- TODO: Try approach from `vector`, fallback on Prim for setByteArray/recursive copyArray+  -- unsafeLinearSet (MSArray _ v) = setByteArray ma+  -- {-# INLINE unsafeLinearSet #-}++  unsafeLinearCopy marrFrom iFrom marrTo iTo (Sz k) = do+    let MSArray _ (MVS.MVector _ fpFrom) = marrFrom+        MSArray _ (MVS.MVector _ fpTo) = marrTo+    unsafePrimToPrim $+      withForeignPtr fpFrom $ \ ptrFrom ->+        withForeignPtr fpTo $ \ ptrTo -> do+          let ptrFrom' = advancePtr ptrFrom iFrom+              ptrTo' = advancePtr ptrTo iTo+          copyArray ptrTo' ptrFrom' k+  {-# INLINE unsafeLinearCopy #-}++  unsafeArrayLinearCopy arrFrom iFrom marrTo iTo sz = do+    marrFrom <- unsafeThaw arrFrom+    unsafeLinearCopy marrFrom iFrom marrTo iTo sz+  {-# INLINE unsafeArrayLinearCopy #-}++  unsafeLinearShrink marr@(MSArray _ mv@(MVS.MVector _ (ForeignPtr _ fpc))) sz = do+    let shrinkMBA :: MutableByteArray RealWorld -> IO ()+        shrinkMBA mba = shrinkMutableByteArray mba (totalElem sz * sizeOf (undefined :: e))+        {-# INLINE shrinkMBA #-}+    case fpc of+      MallocPtr mba# _ -> do+        unsafePrimToPrim $ shrinkMBA (MutableByteArray mba#)+        pure $ MSArray sz mv+      PlainPtr mba# -> do+        unsafePrimToPrim $ shrinkMBA (MutableByteArray mba#)+        pure $ MSArray sz mv+      _ -> unsafeDefaultLinearShrink marr sz+  {-# INLINE unsafeLinearShrink #-}++  unsafeLinearGrow (MSArray _ mv) sz = MSArray sz <$> MVS.unsafeGrow mv (totalElem sz)+  {-# INLINE unsafeLinearGrow #-}   instance (Index ix, VS.Storable e) => Load S ix e where
src/Data/Massiv/Array/Manifest/Unboxed.hs view
@@ -177,6 +177,8 @@     INDEX_CHECK("(Mutable U ix e).unsafeLinearWrite", Sz . MVU.length, MVU.unsafeWrite) mv   {-# INLINE unsafeLinearWrite #-} +  unsafeLinearGrow (MUArray _ mv) sz = MUArray sz <$> MVU.unsafeGrow mv (totalElem sz)+  {-# INLINE unsafeLinearGrow #-}  instance ( VU.Unbox e          , IsList (Array L ix e)
src/Data/Massiv/Array/Mutable.hs view
@@ -82,7 +82,7 @@  -- TODO: add fromListM, et al. -import Control.Monad (unless)+import Control.Monad (when, unless) import Control.Monad.ST import Control.Scheduler import Data.Massiv.Core.Common@@ -140,8 +140,20 @@ -- -- @since 0.1.0 thaw :: forall r ix e m. (Mutable r ix e, MonadIO m) => Array r ix e -> m (MArray RealWorld r ix e)-thaw arr = liftIO $ makeMArrayLinear (getComp arr) (size arr) (pure . unsafeLinearIndexM arr)--- TODO: use faster memcpy+thaw arr =+  liftIO $ do+    let sz = size arr+        totalLength = totalElem sz+    marr <- unsafeNew sz+    withScheduler_ (getComp arr) $ \scheduler ->+      splitLinearly (numWorkers scheduler) totalLength $ \chunkLength slackStart -> do+        loopM_ 0 (< slackStart) (+ chunkLength) $ \ !start ->+          scheduleWork_ scheduler $ unsafeArrayLinearCopy arr start marr start (SafeSz chunkLength)+        let slackLength = totalLength - slackStart+        when (slackLength > 0) $+          scheduleWork_ scheduler $+          unsafeArrayLinearCopy arr slackStart marr slackStart (SafeSz slackLength)+    pure marr {-# INLINE thaw #-}  -- | Same as `thaw`, but restrict computation to sequential only.@@ -162,13 +174,13 @@      forall r ix e m. (Mutable r ix e, PrimMonad m)   => Array r ix e   -> m (MArray (PrimState m) r ix e)-thawS arr = makeMArrayLinearS (size arr) (pure . unsafeLinearIndexM arr)--- TODO: use faster memcpy+thawS arr = do+  tmarr <- unsafeNew (size arr)+  unsafeArrayLinearCopy arr 0 tmarr 0 (SafeSz (totalElem (size arr)))+  pure tmarr {-# INLINE thawS #-}  --- TODO: implement and benchmark parallel `thawIO` and `freezeIO` with memcpy- -- | /O(n)/ - Yield an immutable copy of the mutable array. Note that mutable representations -- have to be the same. --@@ -189,7 +201,20 @@   => Comp   -> MArray RealWorld r ix e   -> m (Array r ix e)-freeze comp marr = liftIO $ generateArrayLinear comp (msize marr) (unsafeLinearRead marr)+freeze comp smarr =+  liftIO $ do+    let sz = msize smarr+        totalLength = totalElem sz+    tmarr <- unsafeNew sz+    withScheduler_ comp $ \scheduler ->+      splitLinearly (numWorkers scheduler) totalLength $ \chunkLength slackStart -> do+        loopM_ 0 (< slackStart) (+ chunkLength) $ \ !start ->+          scheduleWork_ scheduler $ unsafeLinearCopy smarr start tmarr start (SafeSz chunkLength)+        let slackLength = totalLength - slackStart+        when (slackLength > 0) $+          scheduleWork_ scheduler $+          unsafeLinearCopy smarr slackStart tmarr slackStart (SafeSz slackLength)+    unsafeFreeze comp tmarr {-# INLINE freeze #-}  @@ -201,8 +226,13 @@      forall r ix e m. (Mutable r ix e, PrimMonad m)   => MArray (PrimState m) r ix e   -> m (Array r ix e)-freezeS marr = generateArrayLinearS Seq (msize marr) (unsafeLinearRead marr)+freezeS smarr = do+  let sz = msize smarr+  tmarr <- unsafeNew sz+  unsafeLinearCopy smarr 0 tmarr 0 (SafeSz (totalElem sz))+  unsafeFreeze Seq tmarr {-# INLINE freezeS #-}+  newMaybeInitialized ::      (Load r' ix e, Mutable r ix e, PrimMonad m) => Array r' ix e -> m (MArray (PrimState m) r ix e)
src/Data/Massiv/Array/Mutable/Algorithms.hs view
@@ -11,9 +11,11 @@ module Data.Massiv.Array.Mutable.Algorithms   ( quicksortM_   , unstablePartitionM+  , iterateUntilM   ) where  import Data.Massiv.Array.Ops.Sort+import Data.Massiv.Array.Manifest.Internal (iterateUntilM) import Data.Massiv.Core.Common  
src/Data/Massiv/Array/Numeric.hs view
@@ -19,6 +19,7 @@   , (.^)   , (|*|)   , multiplyTransposed+  , identityMatrix   , negateA   , absA   , signumA@@ -64,6 +65,7 @@   ) where  import Data.Massiv.Array.Delayed.Pull+import Data.Massiv.Array.Delayed.Push import Data.Massiv.Array.Manifest.Internal import Data.Massiv.Array.Ops.Fold as A import Data.Massiv.Array.Ops.Map as A@@ -179,6 +181,25 @@     SafeSz (m1 :. n1) = size arr1     SafeSz (n2 :. m2) = size arr2 {-# INLINE multiplyTransposed #-}++-- | Create an indentity matrix.+--+-- ====___Example__+--+-- >>> import Data.Massiv.Array+-- >>> identityMatrix 5+-- Array DL Seq (Sz (5 :. 5))+--   [ [ 1, 0, 0, 0, 0 ]+--   , [ 0, 1, 0, 0, 0 ]+--   , [ 0, 0, 1, 0, 0 ]+--   , [ 0, 0, 0, 1, 0 ]+--   , [ 0, 0, 0, 0, 1 ]+--   ]+--+-- @since 0.3.6+identityMatrix :: Int -> Array DL Ix2 Int+identityMatrix n = makeLoadArrayS (Sz2 n n) 0 $ \ w -> loopM_ 0 (< n) (+1) $ \ i -> w (i :. i) 1+{-# INLINE identityMatrix #-}   negateA
src/Data/Massiv/Array/Stencil.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-} -- | -- Module      : Data.Massiv.Array.Stencil -- Copyright   : (c) Alexey Kuleshevich 2018-2019@@ -114,3 +115,4 @@       inline relStencil $ \ !ixD -> getVal (liftIndex2 (+) ix ixD)     {-# INLINE stencil #-} {-# INLINE makeStencilDef #-}+
src/Data/Massiv/Array/Stencil/Internal.hs view
@@ -25,7 +25,6 @@ import Control.DeepSeq import Data.Massiv.Array.Delayed.Pull import Data.Massiv.Core.Common-import Data.Massiv.Core.Index.Internal  -- | Stencil is abstract description of how to handle elements in the neighborhood of every array -- cell in order to compute a value for the cells in the new array. Use `Data.Array.makeStencil` and
src/Data/Massiv/Array/Unsafe.hs view
@@ -42,6 +42,10 @@   , unsafeWrite   , unsafeLinearWrite   , unsafeLinearSet+  , unsafeLinearCopy+  , unsafeArrayLinearCopy+  , unsafeLinearShrink+  , unsafeLinearGrow     -- * Pointer access   , unsafeWithPtr   , unsafeArrayToForeignPtr
src/Data/Massiv/Core/Common.hs view
@@ -37,6 +37,7 @@   , unsafeRead   , unsafeWrite   , unsafeLinearModify+  , unsafeDefaultLinearShrink   , Ragged(..)   , Nested(..)   , NestedStruct@@ -45,6 +46,7 @@   -- * Size   , elemsCount   , isEmpty+  , Sz(SafeSz)   -- * Indexing   , (!?)   , index@@ -86,6 +88,7 @@                           scheduleWork, scheduleWork_) import Data.Massiv.Core.Exception import Data.Massiv.Core.Index+import Data.Massiv.Core.Index.Internal (Sz(SafeSz)) import Data.Typeable  #include "massiv.h"@@ -328,12 +331,78 @@     return marr   {-# INLINE initializeNew #-} -+  -- | Set all cells in the mutable array within the range to a specified value.+  --+  -- @since 0.3.0   unsafeLinearSet :: PrimMonad m =>-                     MArray (PrimState m) r ix e -> Int -> Int -> e -> m ()+                     MArray (PrimState m) r ix e -> Ix1 -> Int -> e -> m ()   unsafeLinearSet marr offset len e =     loopM_ offset (< (offset + len)) (+1) (\i -> unsafeLinearWrite marr i e)   {-# INLINE unsafeLinearSet #-}++  -- | Copy part of one mutable array into another+  --+  -- @since 0.3.6+  unsafeLinearCopy :: PrimMonad m =>+                      MArray (PrimState m) r ix e -- ^ Source mutable array+                   -> Ix1 -- ^ Starting index at source array+                   -> MArray (PrimState m) r ix e -- ^ Target mutable array+                   -> Ix1 -- ^ Starting index at target array+                   -> Sz1 -- ^ Number of elements to copy+                   -> m ()+  unsafeLinearCopy marrFrom iFrom marrTo iTo (SafeSz k) = do+    let delta = iTo - iFrom+    loopM_ iFrom (< k + iFrom) (+1) $ \i ->+      unsafeLinearRead marrFrom i >>= unsafeLinearWrite marrTo (i + delta)+  {-# INLINE unsafeLinearCopy #-}++  -- | Copy a part of a pure array into a mutable array+  --+  -- @since 0.3.6+  unsafeArrayLinearCopy :: PrimMonad m =>+                           Array r ix e -- ^ Source pure array+                        -> Ix1 -- ^ Starting index at source array+                        -> MArray (PrimState m) r ix e -- ^ Target mutable array+                        -> Ix1 -- ^ Starting index at target array+                        -> Sz1 -- ^ Number of elements to copy+                        -> m ()+  unsafeArrayLinearCopy arrFrom iFrom marrTo iTo (SafeSz k) = do+    let delta = iTo - iFrom+    loopM_ iFrom (< k + iFrom) (+1) $ \i ->+      unsafeLinearWrite marrTo (i + delta) (unsafeLinearIndex arrFrom i)+  {-# INLINE unsafeArrayLinearCopy #-}++  -- | Linearly reduce the size of an array. Total number of elements should be smaller.+  --+  -- @since 0.3.6+  unsafeLinearShrink :: PrimMonad m =>+                     MArray (PrimState m) r ix e -> Sz ix -> m (MArray (PrimState m) r ix e)+  unsafeLinearShrink = unsafeDefaultLinearShrink+  {-# INLINE unsafeLinearShrink #-}++  -- | Linearly increase the size of an array. Total number of elements should be larger.+  --+  -- @since 0.3.6+  unsafeLinearGrow :: PrimMonad m =>+                     MArray (PrimState m) r ix e -> Sz ix -> m (MArray (PrimState m) r ix e)+  unsafeLinearGrow marr sz = do+    marr' <- unsafeNew sz+    unsafeLinearCopy marr 0 marr' 0 $ SafeSz (totalElem (msize marr))+    pure marr'+  {-# INLINE unsafeLinearGrow #-}+++unsafeDefaultLinearShrink ::+     (Mutable r ix e, PrimMonad m)+  => MArray (PrimState m) r ix e+  -> Sz ix+  -> m (MArray (PrimState m) r ix e)+unsafeDefaultLinearShrink marr sz = do+  marr' <- unsafeNew sz+  unsafeLinearCopy marr 0 marr' 0 $ SafeSz (totalElem sz)+  pure marr'+{-# INLINE unsafeDefaultLinearShrink #-}+  -- | Read an array element unsafeRead :: (Mutable r ix e, PrimMonad m) =>
src/Data/Massiv/Core/List.hs view
@@ -33,7 +33,6 @@ import Data.Foldable (foldr') import qualified Data.List as L import Data.Massiv.Core.Common-import Data.Massiv.Core.Index.Internal import Data.Proxy import Data.Typeable import GHC.Exts
tests/Data/Massiv/Array/MutableSpec.hs view
@@ -7,6 +7,7 @@ module Data.Massiv.Array.MutableSpec (spec) where  import Control.Concurrent.Async+import Control.Monad (when) import Control.Monad.ST import Data.Functor.Identity import Data.List as L@@ -43,6 +44,50 @@   arr' <- run $ generateArray (getComp arr) (size arr) (evaluateM arr)   return (arr === arr') +prop_shrinkIO ::+     ( Mutable r ix Int+     , Resize r ix+     , Source r Ix1 Int+     )+  => r+  -> Proxy ix+  -> ArrIx r ix Int+  -> Property+prop_shrinkIO _ _ (ArrIx arr ix) =+  monadicIO $+  run $ do+    marr <- thaw arr+    sarr <- unsafeFreeze (getComp arr) =<< unsafeLinearShrink marr (Sz ix)+    pure (A.foldlS (.&&.) (property True) $ A.zipWith (===) (flatten arr) (flatten sarr))++prop_growShrinkIO ::+     ( Show (Array r ix Int)+     , Eq (Array r ix Int)+     , Mutable r ix Int+     , Extract r ix Int+     , Num ix+     , Load (EltRepr r ix) ix Int+     )+  => r+  -> Proxy ix+  -> Arr r ix Int+  -> NonNegative Int+  -> Property+prop_growShrinkIO _ _ (Arr arr) (NonNegative delta) =+  monadicIO $+  run $ do+    marr <- thaw arr+    let sz = size arr+    k <- getDimM (unSz sz) (dimensions sz)+    -- increase the outer most dimension, just so the structure doesn't change+    newSz <- Sz <$> setDimM (unSz sz) (dimensions sz) (k + delta)+    gMarr <- unsafeLinearGrow marr newSz+    -- Make sure we can write into the newly allocated area+    when (delta > 0) $ write' gMarr (unSz newSz - 1) delta+    garr <- compute . extract' 0 sz <$> unsafeFreeze (getComp arr) gMarr+    sarr <- freeze (getComp arr) =<< unsafeLinearShrink gMarr sz+    pure (garr === arr .&&. sarr === arr)+ prop_atomicModifyIntArrayMany :: ArrIx P Ix2 Int -> Array B Ix1 Int -> Property prop_atomicModifyIntArrayMany (ArrIx arr ix) barr =   monadicIO $ do@@ -58,15 +103,16 @@   prop_atomicReadIntArrayMany :: Array P Ix2 Int -> Array B Ix1 Ix2 -> Property-prop_atomicReadIntArrayMany arr bix = monadicIO $ do+prop_atomicReadIntArrayMany arr bix =+  monadicIO $   run $ do-      marr <- thaw arr-      as :: Array N Ix1 (Maybe Int) <- forM bix (A.read marr)-      as' <- forM bix (atomicReadIntArray marr)-      pure (as === as')+    marr <- thaw arr+    as :: Array N Ix1 (Maybe Int) <- forM bix (A.read marr)+    as' <- forM bix (atomicReadIntArray marr)+    pure (as === as')  -prop_atomicWriteIntArrayMany :: Array P Ix2 Int -> Array B Ix1 Ix2 -> (Fun Ix2 Int) -> Property+prop_atomicWriteIntArrayMany :: Array P Ix2 Int -> Array B Ix1 Ix2 -> Fun Ix2 Int -> Property prop_atomicWriteIntArrayMany arr bix f =   monadicIO $   run $ do@@ -96,20 +142,30 @@           rev a = computeAs P $ backpermute' sz1 (\ix1 -> unSz sz1 - ix1 - 1) a  + mutableSpec ::      ( Show r-     , Show (Array r Ix3 Int)      , Show (Array r Ix1 Int)      , Show (Array r Ix2 Int)-     , Eq (Array r Ix3 Int)+     , Show (Array r Ix3 Int)      , Eq (Array r Ix1 Int)      , Eq (Array r Ix2 Int)-     , Mutable r Ix3 Int+     , Eq (Array r Ix3 Int)      , Mutable r Ix1 Int      , Mutable r Ix2 Int-     , Construct r Ix3 Int+     , Mutable r Ix3 Int      , Construct r Ix1 Int      , Construct r Ix2 Int+     , Construct r Ix3 Int+     , Extract r Ix1 Int+     , Extract r Ix2 Int+     , Extract r Ix3 Int+     , Resize r Ix1+     , Resize r Ix2+     , Resize r Ix3+     , Load (EltRepr r Ix1) Ix1 Int+     , Load (EltRepr r Ix2) Ix2 Int+     , Load (EltRepr r Ix3) Ix3 Int      )   => r   -> SpecWith ()@@ -131,7 +187,14 @@       it "Ix1" $ property $ prop_generateMakeIO r (Proxy :: Proxy Ix1)       it "Ix2" $ property $ prop_generateMakeIO r (Proxy :: Proxy Ix2)       it "Ix3" $ property $ prop_generateMakeIO r (Proxy :: Proxy Ix3)-+    describe "shrink" $ do+      it "Ix1" $ property $ prop_shrinkIO r (Proxy :: Proxy Ix1)+      it "Ix2" $ property $ prop_shrinkIO r (Proxy :: Proxy Ix2)+      it "Ix3" $ property $ prop_shrinkIO r (Proxy :: Proxy Ix3)+    describe "grow+shrink" $ do+      it "Ix1" $ property $ prop_growShrinkIO r (Proxy :: Proxy Ix1)+      it "Ix2" $ property $ prop_growShrinkIO r (Proxy :: Proxy Ix2)+      it "Ix3" $ property $ prop_growShrinkIO r (Proxy :: Proxy Ix3)  generateSpec :: Spec generateSpec = do