massiv 0.2.7.0 → 0.2.8.0
raw patch · 5 files changed
+139/−38 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- massiv.cabal +1/−1
- src/Data/Massiv/Array/Stencil.hs +3/−2
- src/Data/Massiv/Array/Stencil/Convolution.hs +28/−17
- src/Data/Massiv/Array/Stencil/Unsafe.hs +3/−2
- tests/Data/Massiv/Array/StencilSpec.hs +104/−16
massiv.cabal view
@@ -1,5 +1,5 @@ name: massiv-version: 0.2.7.0+version: 0.2.8.0 synopsis: Massiv (Массив) is an Array Library. description: Multi-dimensional Arrays with fusion, stencils and parallel computation. homepage: https://github.com/lehins/massiv
src/Data/Massiv/Array/Stencil.hs view
@@ -49,10 +49,11 @@ where !window = Window- { windowStart = sCenter- , windowSize = liftIndex2 (-) sz (liftIndex2 (-) sSz (pureIndex 1))+ { windowStart = liftIndex2 min sCenter (liftIndex (max 0) (liftIndex (subtract 1) sz))+ , windowSize = liftIndex (max 0) (liftIndex2 min windowSz (liftIndex2 (-) sz sCenter)) , windowIndex = unValue . stencilF (Value . unsafeIndex arr) }+ !windowSz = liftIndex (max 0) (liftIndex2 (-) sz (liftIndex (subtract 1) sSz)) !sz = size arr {-# INLINE mapStencil #-}
src/Data/Massiv/Array/Stencil/Convolution.hs view
@@ -2,7 +2,7 @@ {-# LANGUAGE BangPatterns #-} -- | -- Module : Data.Massiv.Array.Stencil.Convolution--- Copyright : (c) Alexey Kuleshevich 2018+-- Copyright : (c) Alexey Kuleshevich 2018-2019 -- License : BSD3 -- Maintainer : Alexey Kuleshevich <lehins@yandex.ru> -- Stability : experimental@@ -28,20 +28,23 @@ -- Here is how to create a 2D horizontal Sobel Stencil: -- -- > sobelX :: Num e => Stencil Ix2 e e--- > sobelX = makeConvolutionStencil (3 :. 3) (1 :. 1) $--- > \f -> f (-1 :. -1) 1 . f (-1 :. 1) (-1) .--- > f ( 0 :. -1) 2 . f ( 0 :. 1) (-2) .--- > f ( 1 :. -1) 1 . f ( 1 :. 1) (-1)+-- > sobelX = makeConvolutionStencil (Sz2 3 3) (1 :. 1) $+-- > \f -> f (-1 :. -1) (-1) . f (-1 :. 1) 1 .+-- > f ( 0 :. -1) (-2) . f ( 0 :. 1) 2 .+-- > f ( 1 :. -1) (-1) . f ( 1 :. 1) 1 -- > {-# INLINE sobelX #-} --+-- @since 0.1.0 makeConvolutionStencil :: (Index ix, Num e) => Sz ix -> ix -> ((ix -> Value e -> Value e -> Value e) -> Value e -> Value e) -> Stencil ix e e-makeConvolutionStencil !sSz !sCenter relStencil = validateStencil 0 $ Stencil sSz sCenter stencil+makeConvolutionStencil !sz !sCenter relStencil =+ validateStencil 0 $ Stencil sz sInvertCenter stencil where+ !sInvertCenter = liftIndex2 (-) (liftIndex (subtract 1) sz) sCenter stencil getVal !ix = (inline relStencil $ \ !ixD !kVal !acc -> getVal (liftIndex2 (-) ix ixD) * kVal + acc) 0 {-# INLINE stencil #-}@@ -51,24 +54,30 @@ -- | Make a stencil out of a Kernel Array. This `Stencil` will be slower than if -- `makeConvolutionStencil` is used, but sometimes we just really don't know the -- kernel at compile time.+--+-- @since 0.1.0 makeConvolutionStencilFromKernel :: (Manifest r ix e, Num e) => Array r ix e -> Stencil ix e e-makeConvolutionStencilFromKernel kArr = Stencil sz sCenter stencil+makeConvolutionStencilFromKernel kArr = Stencil sz sInvertCenter stencil where- !sz = size kArr- !sCenter = liftIndex (`div` 2) sz+ !sz@(Sz szi) = size kArr+ !szi1 = liftIndex (subtract 1) szi+ !sInvertCenter = liftIndex2 (-) szi1 sCenter+ !sCenter = liftIndex (`quot` 2) szi stencil getVal !ix = Value (ifoldlS accum 0 kArr) where+ !ixOff = liftIndex2 (+) ix sCenter accum !acc !kIx !kVal =- unValue (getVal (liftIndex2 (+) ix (liftIndex2 (-) sCenter kIx))) * kVal + acc+ unValue (getVal (liftIndex2 (-) ixOff kIx)) * kVal + acc {-# INLINE accum #-} {-# INLINE stencil #-} {-# INLINE makeConvolutionStencilFromKernel #-} ---- | Make a <https://en.wikipedia.org/wiki/Cross-correlation cross-correlation> stencil.+-- | Make a <https://en.wikipedia.org/wiki/Cross-correlation cross-correlation> stencil+--+-- @since 0.1.5 makeCorrelationStencil :: (Index ix, Num e) => Sz ix@@ -82,10 +91,11 @@ {-# INLINE stencil #-} {-# INLINE makeCorrelationStencil #-} ---- | Make a stencil out of a Kernel Array. This `Stencil` will be slower than if--- `makeCorrelationStencil` is used, but sometimes we just really don't know the--- kernel at compile time.+-- | Make a <https://en.wikipedia.org/wiki/Cross-correlation cross-correlation> stencil out of a+-- Kernel Array. This `Stencil` will be slower than if `makeCorrelationStencil` is used, but+-- sometimes we just really don't know the kernel at compile time.+--+-- @since 0.1.5 makeCorrelationStencilFromKernel :: (Manifest r ix e, Num e) => Array r ix e@@ -95,8 +105,9 @@ !sz = size kArr !sCenter = liftIndex (`div` 2) sz stencil getVal !ix = Value (ifoldlS accum 0 kArr) where+ !ixOff = liftIndex2 (-) ix sCenter accum !acc !kIx !kVal =- unValue (getVal (liftIndex2 (+) ix (liftIndex2 (+) sCenter kIx))) * kVal + acc+ unValue (getVal (liftIndex2 (+) ixOff kIx)) * kVal + acc {-# INLINE accum #-} {-# INLINE stencil #-} {-# INLINE makeCorrelationStencilFromKernel #-}
src/Data/Massiv/Array/Stencil/Unsafe.hs view
@@ -48,10 +48,11 @@ where !window = Window- { windowStart = sCenter- , windowSize = liftIndex2 (-) sz (liftIndex2 (-) sSz (pureIndex 1))+ { windowStart = liftIndex2 min sCenter (liftIndex (max 0) (liftIndex (subtract 1) sz))+ , windowSize = liftIndex (max 0) (liftIndex2 min windowSz (liftIndex2 (-) sz sCenter)) , windowIndex = stencil (Just . unsafeIndex arr) }+ !windowSz = liftIndex (max 0) (liftIndex2 (-) sz (liftIndex (subtract 1) sSz)) stencil getVal !ix = inline relStencil $ \ !ixD -> getVal (liftIndex2 (+) ix ixD) {-# INLINE stencil #-} !sz = size arr
tests/Data/Massiv/Array/StencilSpec.hs view
@@ -1,18 +1,19 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE ScopedTypeVariables #-} module Data.Massiv.Array.StencilSpec (spec) where -import Control.DeepSeq (deepseq)-import Data.Massiv.CoreArbitrary as A-import Data.Maybe (fromJust)-import Data.Proxy-import Test.Hspec-import Test.QuickCheck-import Test.QuickCheck.Function-import Data.Default (Default(def))+import Control.DeepSeq (deepseq)+import Data.Default (Default(def))+import Data.Massiv.CoreArbitrary as A+import Data.Maybe (fromJust)+import Data.Proxy+import Test.Hspec+import Test.QuickCheck+import Test.QuickCheck.Function -- sum3x3Stencil :: Fractional a => Stencil Ix2 a a -- sum3x3Stencil = makeConvolutionStencil (3 :. 3) (1 :. 1) $ \ get ->@@ -50,7 +51,6 @@ i <- getDim sz r setDim zeroIndex r i - stencilSpec :: Spec stencilSpec = do describe "MapSingletonStencil" $ do@@ -78,8 +78,80 @@ (Default a, Unbox a, Manifest r Ix2 a) => Ix2 -> Ix2 -> Array r Ix2 a -> Array U Ix2 a stencilCorners ixC ix = computeAs U . mapStencil (Fill def) (makeStencil (3 :. 3) ixC $ \f -> f ix) +stencilConvolution :: Spec+stencilConvolution = do+ let xs3 :: Array U Ix1 Int+ xs3 = [1, 2, 3]+ xs3f f = f (-1) 1 . f 0 2 . f 1 3+ xs4 :: Array U Ix1 Int+ xs4 = [1, 2, 3, 4]+ xs4f f = f (-2) 1 . f (-1) 2 . f 0 3 . f 1 4+ ys :: Array U Ix1 Int+ ys = [1, 2, 3, 4, 5]+ ysConvXs3 = [4, 10, 16, 22, 22]+ ysConvXs4 = [10, 20, 30, 34, 31]+ ysCorrXs3 = [8, 14, 20, 26, 14]+ ysCorrXs4 = [11, 20, 30, 40, 26]+ ysConvXs4' = [4, 10, 20, 30, 34]+ ysCorrXs4' = [20, 30, 40, 26, 14]+ xs4f' f = f (-1) 1 . f 0 2 . f 1 3 . f 2 4+ applyStencil s = computeAs U . mapStencil (Fill 0) s+ describe "makeConvolutionStencilFromKernel" $ do+ it "1x3" $ applyStencil (makeConvolutionStencilFromKernel xs3) ys `shouldBe` ysConvXs3+ it "1x4" $ applyStencil (makeConvolutionStencilFromKernel xs4) ys `shouldBe` ysConvXs4+ describe "makeCorrelationStencilFromKernel" $ do+ it "1x3" $ applyStencil (makeCorrelationStencilFromKernel xs3) ys `shouldBe` ysCorrXs3+ it "1x4" $ applyStencil (makeCorrelationStencilFromKernel xs4) ys `shouldBe` ysCorrXs4+ describe "makeConvolutionStencil" $ do+ it "1x3" $ applyStencil (makeConvolutionStencil (Sz1 3) 1 xs3f) ys `shouldBe` ysConvXs3+ it "1x4" $ applyStencil (makeConvolutionStencil (Sz1 4) 2 xs4f) ys `shouldBe` ysConvXs4+ it "1x4" $ applyStencil (makeConvolutionStencil (Sz1 4) 1 xs4f') ys `shouldBe` ysConvXs4'+ describe "makeCorrelationStencil" $ do+ it "1x3" $ applyStencil (makeCorrelationStencil (Sz1 3) 1 xs3f) ys `shouldBe` ysCorrXs3+ it "1x4" $ applyStencil (makeCorrelationStencil (Sz1 4) 2 xs4f) ys `shouldBe` ysCorrXs4+ it "1x4" $ applyStencil (makeCorrelationStencil (Sz1 4) 1 xs4f') ys `shouldBe` ysCorrXs4'+ describe "makeConvolutionStencil == makeConvolutionStencilFromKernel" $ do+ it "Sobel Horizontal" $+ property $ \(arr :: Array U Ix2 Int) ->+ applyStencil (makeConvolutionStencil (3 :. 3) 1 sobelX) arr ===+ applyStencil (makeConvolutionStencilFromKernel sobelKernelX) arr+ it "1x3" $+ property $ \(arr :: Array U Ix1 Int) ->+ applyStencil (makeConvolutionStencil (Sz1 3) 1 xs3f) arr ===+ applyStencil (makeConvolutionStencilFromKernel xs3) arr+ it "1x4" $+ property $ \(arr :: Array U Ix1 Int) ->+ applyStencil (makeConvolutionStencil (Sz1 4) 2 xs4f) arr ===+ applyStencil (makeConvolutionStencilFromKernel xs4) arr+ describe "makeCorrelationStencil == makeCorrelationStencilFromKernel" $ do+ it "Sobel Horizontal" $+ property $ \(arr :: Array U Ix2 Int) ->+ applyStencil (makeCorrelationStencil (3 :. 3) 1 sobelX) arr ===+ applyStencil (makeCorrelationStencilFromKernel sobelKernelX) arr+ it "1x3" $+ property $ \(arr :: Array U Ix1 Int) ->+ applyStencil (makeCorrelationStencil (Sz1 3) 1 xs3f) arr ===+ applyStencil (makeCorrelationStencilFromKernel xs3) arr+ it "1x4" $+ property $ \(arr :: Array U Ix1 Int) ->+ applyStencil (makeCorrelationStencil (Sz1 4) 2 xs4f) arr ===+ applyStencil (makeCorrelationStencilFromKernel xs4) arr+ describe "makeConvolutionStencil == makeCorrelationStencil . rotate180" $ do+ it "Sobel Horizontal" $+ property $ \(arr :: Array U Ix2 Int) ->+ applyStencil (makeConvolutionStencilFromKernel sobelKernelX) arr ===+ applyStencil (makeCorrelationStencilFromKernel (rotate180 sobelKernelX)) arr+ it "1x3" $+ property $ \(arr :: Array U Ix1 Int) ->+ applyStencil (makeConvolutionStencilFromKernel xs3) arr ===+ applyStencil (makeCorrelationStencilFromKernel (rotate180 xs3)) arr+ -- it "1x4" $+ -- property $ \(arr :: Array U Ix1 Int) ->+ -- applyStencil (makeConvolutionStencilFromKernel xs4) arr ===+ -- applyStencil (makeCorrelationStencilFromKernel (rotate180 xs4)) arr+ spec :: Spec-spec =+spec = do describe "Stencil" $ do stencilSpec let arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] :: Array U Ix2 Int@@ -106,8 +178,24 @@ stride = Stride 2 it "map stencil with stride on small array" $ let strideArr = mapStencil (Fill 0) stencil arr- in computeWithStrideAs U stride strideArr `shouldBe` [[-4, 8],[2, 14]]+ in computeWithStrideAs U stride strideArr `shouldBe` [[-4, 8], [2, 14]] it "map stencil with stride on larger array" $ let largeArr = makeArrayR U Seq (5 :. 5) (succ . toLinearIndex (5 :. 5)) strideArr = mapStencil (Fill 0) stencil largeArr- in computeWithStrideAs U stride strideArr `shouldBe` [[-6, 1, 14], [-13, 9, 43], [4, 21, 44]]+ in computeWithStrideAs U stride strideArr `shouldBe`+ [[-6, 1, 14], [-13, 9, 43], [4, 21, 44]]+ stencilConvolution++sobelX :: Num e => (Ix2 -> e -> e -> e) -> e -> e+sobelX f = f (-1 :. -1) (-1) . f (-1 :. 1) 1 .+ f ( 0 :. -1) (-2) . f ( 0 :. 1) 2 .+ f ( 1 :. -1) (-1) . f ( 1 :. 1) 1++sobelKernelX :: Array U Ix2 Int+sobelKernelX = [ [-1, 0, 1]+ , [-2, 0, 2]+ , [-1, 0, 1] ]++rotate180 :: (Num ix, Index ix) => Array U ix Int -> Array U ix Int+rotate180 arr = computeAs U $ backpermute sz (\ix -> sz - 1 - ix) arr+ where sz = size arr