repa 2.2.0.1 → 3.0.0.1
raw patch · 48 files changed
+3357/−2940 lines, 48 filesdep +bytestringdep ~basedep ~template-haskell
Dependencies added: bytestring
Dependency ranges changed: base, template-haskell
Files
- Data/Array/Repa.hs +113/−175
- Data/Array/Repa/Arbitrary.hs +0/−99
- Data/Array/Repa/Base.hs +85/−0
- Data/Array/Repa/Eval.hs +130/−0
- Data/Array/Repa/Eval/Chunked.hs +138/−0
- Data/Array/Repa/Eval/Cursored.hs +217/−0
- Data/Array/Repa/Eval/Elt.hs +282/−0
- Data/Array/Repa/Eval/Fill.hs +71/−0
- Data/Array/Repa/Eval/Gang.hs +218/−0
- Data/Array/Repa/Eval/Reduction.hs +256/−0
- Data/Array/Repa/Eval/Selection.hs +126/−0
- Data/Array/Repa/Index.hs +36/−32
- Data/Array/Repa/Internals/Base.hs +0/−410
- Data/Array/Repa/Internals/Elt.hs +0/−283
- Data/Array/Repa/Internals/EvalBlockwise.hs +0/−153
- Data/Array/Repa/Internals/EvalChunked.hs +0/−62
- Data/Array/Repa/Internals/EvalCursored.hs +0/−136
- Data/Array/Repa/Internals/EvalReduction.hs +0/−121
- Data/Array/Repa/Internals/Forcing.hs +0/−215
- Data/Array/Repa/Internals/Gang.hs +0/−249
- Data/Array/Repa/Internals/Select.hs +0/−118
- Data/Array/Repa/Operators/IndexSpace.hs +75/−74
- Data/Array/Repa/Operators/Interleave.hs +28/−25
- Data/Array/Repa/Operators/Mapping.hs +147/−82
- Data/Array/Repa/Operators/Modify.hs +0/−53
- Data/Array/Repa/Operators/Reduction.hs +107/−48
- Data/Array/Repa/Operators/Select.hs +0/−44
- Data/Array/Repa/Operators/Selection.hs +43/−0
- Data/Array/Repa/Operators/Traversal.hs +120/−0
- Data/Array/Repa/Operators/Traverse.hs +0/−126
- Data/Array/Repa/Properties.hs +0/−115
- Data/Array/Repa/Repr/ByteString.hs +57/−0
- Data/Array/Repa/Repr/Cursored.hs +109/−0
- Data/Array/Repa/Repr/Delayed.hs +99/−0
- Data/Array/Repa/Repr/ForeignPtr.hs +111/−0
- Data/Array/Repa/Repr/Partitioned.hs +82/−0
- Data/Array/Repa/Repr/Unboxed.hs +233/−0
- Data/Array/Repa/Repr/Undefined.hs +41/−0
- Data/Array/Repa/Repr/Vector.hs +112/−0
- Data/Array/Repa/Shape.hs +1/−1
- Data/Array/Repa/Slice.hs +9/−9
- Data/Array/Repa/Specialised/Dim2.hs +26/−25
- Data/Array/Repa/Stencil.hs +3/−254
- Data/Array/Repa/Stencil/Base.hs +4/−5
- Data/Array/Repa/Stencil/Dim2.hs +228/−0
- Data/Array/Repa/Stencil/Template.hs +5/−2
- LICENSE +1/−1
- repa.cabal +44/−23
Data/Array/Repa.hs view
@@ -1,209 +1,147 @@-{-# LANGUAGE PatternGuards, PackageImports, ScopedTypeVariables, RankNTypes #-}-{-# LANGUAGE TypeOperators, FlexibleContexts, NoMonomorphismRestriction, FlexibleInstances, UndecidableInstances #-}-{-# OPTIONS -fno-warn-orphans #-} --- | See the repa-examples package for examples.+-- | Repa arrays are wrappers around a linear structure that holds the element+-- data. The representation tag determines what structure holds the data. ----- More information at <http://repa.ouroborus.net>.+-- Delayed Representations (functions that compute elements) ----- There is a draft tutorial at <http://www.haskell.org/haskellwiki/Numeric_Haskell:_A_Repa_Tutorial>+-- * `D` -- Functions from indices to elements. ----- @Release Notes:--- For 2.2.0.1:--- * Added unsafeFromForeignPtr, which helps use foreign source--- arrays without intermediate copying.--- * Added forceWith and forceWith2, which can be used to force--- arrays into foreign result buffers without intermediate copying.+-- * `C` -- Cursor functions. ----- For 2.1.0.1:--- * The fold and foldAll functions now run in parallel and require the--- starting element to be neutral with respect to the reduction operator.--- -- thanks to Trevor McDonell--- * Added (\/\/) update function. -- thanks to Trevor McDonell--- * Dropped unneeded Elt constraints from traverse functions.--- @+-- Manifest Representations (real data)+--+-- * `U` -- Adaptive unboxed vectors.+--+-- * `V` -- Boxed vectors.+--+-- * `B` -- Strict ByteStrings.+--+-- * `F` -- Foreign memory buffers.+--+-- Meta Representations+--+-- * `P` -- Arrays that are partitioned into several representations.+--+-- * `X` -- Arrays whose elements are all undefined.+--+-- Array fusion is achieved via the delayed (`D`) and cursored (`C`)+-- representations. At compile time, the GHC simplifier combines the functions+-- contained within `D` and `C` arrays without needing to create manifest+-- intermediate arrays. +--+-- Converting between the parallel manifest representations (eg `U` and `B`)+-- is either constant time or parallel copy, depending on the compatability+-- of the physical representation.+--+-- /Writing fast code:/+--+-- 1. Repa does not support nested parallellism. +-- This means that you cannot `map` a parallel worker function across+-- an array and then call `computeP` to evaluate it, or pass a parallel+-- worker to parallel reductions such as `foldP`. If you do then you will+-- get a run-time warning and the code will run very slowly.+--+-- 2. Arrays of type @(Array D sh a)@ or @(Array C sh a)@ are /not real arrays/.+-- They are represented as functions that compute each element on demand.+-- You need to use a function like `computeS`, `computeP`, `computeUnboxedP`+-- and so on to actually evaluate the elements.+-- +-- 3. You should add @INLINE@ pragmas to all leaf-functions in your code, +-- expecially ones that compute numberic results. This ensures they are +-- specialised at the appropriate element types.+--+-- 4. Scheduling a parallel computation takes about 200us on an OSX machine. +-- You should sequential computation for small arrays in inner loops, +-- or a the bottom of a divide-and-conquer algorithm.+-- module Data.Array.Repa- ( module Data.Array.Repa.Shape- , module Data.Array.Repa.Index- , module Data.Array.Repa.Slice-- -- from Data.Array.Repa.Internals.Elt ------------------------ , Elt(..)-- -- from Data.Array.Repa.Internals.Base ----------------------- , Array(..)- , Region(..)- , Range(..)- , Rect(..)- , Generator(..)- , deepSeqArray, deepSeqArrays- , singleton, toScalar- , extent, delay-- --- , withManifest, withManifest'-- -- * Indexing- , (!), index- , (!?), safeIndex- , unsafeIndex+ ( -- * Abstract array representation+ Array(..)+ , module Data.Array.Repa.Shape+ , module Data.Array.Repa.Index+ , Repr(..), (!), toList+ , deepSeqArrays - -- * Construction- , fromFunction- , fromVector- , fromList- , unsafeFromForeignPtr+ -- * Converting between array representations+ , computeP, computeS+ , copyP, copyS+ , now - -- from Data.Array.Repa.Interlals.Forcing -------------------- -- * Forcing- , force, forceWith- , force2, forceWith2- , toVector- , toList+ -- * Concrete array representations+ -- ** Delayed representation+ , D, fromFunction, toFunction+ , delay + -- ** Unboxed vector representation+ , U+ , computeUnboxedP, computeUnboxedS+ , fromListUnboxed+ , fromUnboxed+ , toUnboxed+ -- from Data.Array.Repa.Operators.IndexSpace ----------------- -- * Index space transformations+ -- * Operators+ -- ** Index space transformations , reshape , append, (++) , transpose , extend- , slice- , backpermute+ , backpermute, unsafeBackpermute , backpermuteDft + , module Data.Array.Repa.Slice+ , slice+ -- from Data.Array.Repa.Operators.Mapping -------------------- -- * Structure preserving operations+ -- ** Structure preserving operations , map , zipWith , (+^), (-^), (*^), (/^)-- -- from Data.Array.Repa.Operations.Modify -------------------- -- * Bulk updates- , (//)-- -- from Data.Array.Repa.Operators.Reduction ------------------ -- * Reductions- , fold, foldAll- , sum, sumAll-- -- from Data.Array.Repa.Operators.Traverse ------------------- -- * Generic Traversal- , traverse- , traverse2- , traverse3- , traverse4- , unsafeTraverse- , unsafeTraverse2- , unsafeTraverse3- , unsafeTraverse4+ , Combine(..) - -- from Data.Array.Repa.Operators.Interleave ----------------- -- * Interleaving+ -- from Data.Array.Repa.Operators.Traversal ------------------+ -- ** Generic traversal+ , traverse, unsafeTraverse+ , traverse2, unsafeTraverse2+ , traverse3, unsafeTraverse3+ , traverse4, unsafeTraverse4+ + -- from Data.Array.Repa.Operators.Interleave -----------------+ -- ** Interleaving , interleave2 , interleave3 , interleave4-- -- from Data.Array.Repa.Operators.Select --------------------- -- * Selection+ + -- from Data.Array.Repa.Operators.Reduction ------------------+ -- ** Reduction+ , foldP, foldS+ , foldAllP, foldAllS+ , sumP, sumS+ , sumAllP, sumAllS+ + -- from Data.Array.Repa.Operators.Selection ------------------ , select)- where+import Data.Array.Repa.Base+import Data.Array.Repa.Shape import Data.Array.Repa.Index import Data.Array.Repa.Slice-import Data.Array.Repa.Shape-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Base-import Data.Array.Repa.Internals.Forcing-import Data.Array.Repa.Operators.Traverse+import Data.Array.Repa.Eval+import Data.Array.Repa.Repr.Delayed+import Data.Array.Repa.Repr.Vector+import Data.Array.Repa.Repr.Unboxed+import Data.Array.Repa.Repr.ByteString+import Data.Array.Repa.Repr.ForeignPtr+import Data.Array.Repa.Repr.Cursored+import Data.Array.Repa.Repr.Partitioned+import Data.Array.Repa.Repr.Undefined ()+import Data.Array.Repa.Operators.Mapping+import Data.Array.Repa.Operators.Traversal import Data.Array.Repa.Operators.IndexSpace import Data.Array.Repa.Operators.Interleave-import Data.Array.Repa.Operators.Mapping-import Data.Array.Repa.Operators.Modify import Data.Array.Repa.Operators.Reduction-import Data.Array.Repa.Operators.Select-import qualified Data.Array.Repa.Shape as S--import Prelude hiding (sum, map, zipWith, (++))-import qualified Prelude as P--stage = "Data.Array.Repa"----- Instances ----------------------------------------------------------------------------------------- Show-instance (Shape sh, Elt a, Show a) => Show (Array sh a) where- show arr =- let shape = showShape (extent arr)- elems = show (toList arr)- in- "Array (" P.++ shape P.++ ") " P.++ elems----- Eq-instance (Shape sh, Elt a, Eq a) => Eq (Array sh a) where-- {-# INLINE (==) #-}- (==) arr1 arr2- = foldAll (&&) True- $ reshape (Z :. (S.size $ extent arr1))- $ zipWith (==) arr1 arr2-- {-# INLINE (/=) #-}- (/=) a1 a2- = not $ (==) a1 a2---- Num--- All operators apply elementwise.-instance (Shape sh, Elt a, Num a) => Num (Array sh a) where- {-# INLINE (+) #-}- (+) = zipWith (+)-- {-# INLINE (-) #-}- (-) = zipWith (-)-- {-# INLINE (*) #-}- (*) = zipWith (*)-- {-# INLINE negate #-}- negate = map negate-- {-# INLINE abs #-}- abs = map abs-- {-# INLINE signum #-}- signum = map signum-- {-# INLINE fromInteger #-}- fromInteger n = fromFunction failShape (\_ -> fromInteger n)- where failShape = error $ stage P.++ ".fromInteger: Constructed array has no shape."----- | Force an array before passing it to a function.-withManifest- :: (Shape sh, Elt a)- => (Array sh a -> b) -> Array sh a -> b--{-# INLINE withManifest #-}-withManifest f arr- = case arr of- Array sh [Region RangeAll (GenManifest vec)]- -> vec `seq` f (Array sh [Region RangeAll (GenManifest vec)])-- _ -> f (force arr)----- | Force an array before passing it to a function.-withManifest'- :: (Shape sh, Elt a)- => Array sh a -> (Array sh a -> b) -> b--{-# INLINE withManifest' #-}-withManifest' arr f- = case arr of- Array sh [Region RangeAll (GenManifest vec)]- -> vec `seq` f (Array sh [Region RangeAll (GenManifest vec)])-- _ -> f (force arr)+import Data.Array.Repa.Operators.Selection+import Prelude ()
− Data/Array/Repa/Arbitrary.hs
@@ -1,99 +0,0 @@-{-# LANGUAGE TypeOperators, FlexibleInstances #-}-{-# OPTIONS -fno-warn-orphans #-}---- Utils to help with testing. Not exported.-module Data.Array.Repa.Arbitrary- ( arbitraryShape- , arbitrarySmallShape- , arbitraryListOfLength- , arbitrarySmallArray)-where-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Base-import Data.Array.Repa.Index-import Data.Array.Repa.Shape as S-import Control.Monad-import Test.QuickCheck----- Arbitrary ---------------------------------------------------------------------------------------instance Arbitrary Z where- arbitrary = return Z---- | Generate an arbitrary index, which may have 0's for some components.-instance (Shape sh, Arbitrary sh) => Arbitrary (sh :. Int) where- arbitrary- = do sh1 <- arbitrary- let sh1Unit = if size sh1 == 0 then unitDim else sh1-- -- Make sure not to create an index so big that we get- -- integer overflow when converting it to the linear form.- n <- liftM abs $ arbitrary- let nMax = maxBound `div` (size sh1Unit)- let nMaxed = n `mod` nMax-- return $ sh1 :. nMaxed---- | Generate an aribrary shape that does not have 0's for any component.-arbitraryShape- :: (Shape sh, Arbitrary sh)- => Gen (sh :. Int)--arbitraryShape- = do sh1 <- arbitrary- let sh1Unit = if size sh1 == 0 then unitDim else sh1-- -- Make sure not to create an index so big that we get- -- integer overflow when converting it to the linear form.- n <- liftM abs $ arbitrary- let nMax = maxBound `div` size sh1Unit- let nMaxed = n `mod` nMax- let nClamped = if nMaxed == 0 then 1 else nMaxed-- return $ sh1Unit :. nClamped----- | Generate an arbitrary shape where each dimension is more than zero,--- but less than a specific value.-arbitrarySmallShape- :: (Shape sh, Arbitrary sh)- => Int- -> Gen (sh :. Int)--arbitrarySmallShape maxDim- = do sh <- arbitraryShape- let dims = listOfShape sh-- let clamp x- = case x `mod` maxDim of- 0 -> 1- n -> n-- return $ if True- then shapeOfList $ map clamp dims- else sh---arbitraryListOfLength- :: Arbitrary a- => Int -> Gen [a]--arbitraryListOfLength n- | n == 0 = return []- | otherwise- = do i <- arbitrary- rest <- arbitraryListOfLength (n - 1)- return $ i : rest---- | Create an arbitrary small array, restricting the size of each of the--- dimensions to some value.-arbitrarySmallArray- :: (Shape sh, Elt a, Arbitrary sh, Arbitrary a)- => Int- -> Gen (Array (sh :. Int) a)--arbitrarySmallArray maxDim- = do sh <- arbitrarySmallShape maxDim- xx <- arbitraryListOfLength (S.size sh)- return $ fromList sh xx-
+ Data/Array/Repa/Base.hs view
@@ -0,0 +1,85 @@++module Data.Array.Repa.Base+ ( Array+ , Repr (..), (!), toList+ , deepSeqArrays)+where+import Data.Array.Repa.Shape++-- | Arrays with a representation tag, shape, and element type.+-- Use one of the type tags like `D`, `U` and so on for @r@, +-- one of `DIM1`, `DIM2` ... for @sh@.+data family Array r sh e+++-- | Class of array representations that we can read elements from.+--+class Repr r e where+ -- | O(1). Take the extent of an array.+ extent :: Shape sh => Array r sh e -> sh++ -- | O(1). Shape polymorphic indexing.+ index, unsafeIndex+ :: Shape sh => Array r sh e -> sh -> e++ {-# INLINE index #-}+ index arr ix = arr `linearIndex` toIndex (extent arr) ix++ {-# INLINE unsafeIndex #-}+ unsafeIndex arr ix = arr `unsafeLinearIndex` toIndex (extent arr) ix++ -- | O(1). Linear indexing into underlying, row-major, array representation.+ linearIndex, unsafeLinearIndex+ :: Shape sh => Array r sh e -> Int -> e++ {-# INLINE unsafeLinearIndex #-}+ unsafeLinearIndex = linearIndex++ -- | Ensure an array's data structure is fully evaluated.+ deepSeqArray :: Shape sh => Array r sh e -> b -> b+++-- | O(1). Alias for `index`+(!) :: (Repr r e, Shape sh) => Array r sh e -> sh -> e+(!) = index+++-- | O(n). Convert an array to a list.+toList :: (Shape sh, Repr r e)+ => Array r sh e -> [e]+{-# INLINE toList #-}+toList arr + = go 0 + where len = size (extent arr)+ go ix+ | ix == len = []+ | otherwise = unsafeLinearIndex arr ix : go (ix + 1)+++-- | Apply `deepSeqArray` to up to four arrays. +--+-- The implementation of this function has been hand-unwound to work for up to+-- four arrays. Putting more in the list yields `error`.+-- +deepSeqArrays + :: (Shape sh, Repr r e)+ => [Array r sh e] -> b -> b+{-# INLINE deepSeqArrays #-}+deepSeqArrays arrs x+ = case arrs of+ [] -> x++ [a1]+ -> a1 `deepSeqArray` x++ [a1, a2]+ -> a1 `deepSeqArray` a2 `deepSeqArray` x++ [a1, a2, a3]+ -> a1 `deepSeqArray` a2 `deepSeqArray` a3 `deepSeqArray` x++ [a1, a2, a3, a4]+ -> a1 `deepSeqArray` a2 `deepSeqArray` a3 `deepSeqArray` a4 `deepSeqArray` x++ _ -> error "deepSeqArrays: only works for up to four arrays"+
+ Data/Array/Repa/Eval.hs view
@@ -0,0 +1,130 @@+{-# LANGUAGE UndecidableInstances #-}++-- | Low level interface to parallel array filling operators.+module Data.Array.Repa.Eval+ ( -- * Element types+ Elt (..)++ -- * Parallel array filling+ , Fillable (..)+ , Fill (..)+ , FillRange (..)+ , fromList+ + -- * Converting between representations+ , computeP, computeS+ , copyP, copyS+ , now+ + -- * Chunked filling+ , fillChunkedS+ , fillChunkedP+ , fillChunkedIOP++ -- * Blockwise filling+ , fillBlock2P+ , fillBlock2S+ + -- * Cursored blockwise filling+ , fillCursoredBlock2S+ , fillCursoredBlock2P+ + -- * Chunked selection+ , selectChunkedS+ , selectChunkedP)+where+import Data.Array.Repa.Eval.Elt+import Data.Array.Repa.Eval.Fill+import Data.Array.Repa.Eval.Chunked+import Data.Array.Repa.Eval.Cursored+import Data.Array.Repa.Eval.Selection+import Data.Array.Repa.Repr.Delayed+import Data.Array.Repa.Base+import Data.Array.Repa.Shape+import System.IO.Unsafe+++-- | Parallel computation of array elements.+--+-- * The `Fill` class is defined so that the source array must have a+-- delayed representation (`D` or `C`)+--+-- * If you want to copy data between manifest representations then use+-- `copyP` instead.+--+-- * If you want to convert a manifest array back to a delayed representation+-- then use `delay` instead.+--+computeP :: Fill r1 r2 sh e+ => Array r1 sh e -> Array r2 sh e+{-# INLINE [4] computeP #-}+computeP arr1+ = arr1 `deepSeqArray` + unsafePerformIO+ $ do marr2 <- newMArr (size $ extent arr1) + fillP arr1 marr2+ unsafeFreezeMArr (extent arr1) marr2+++-- | Sequential computation of array elements.+computeS + :: Fill r1 r2 sh e+ => Array r1 sh e -> Array r2 sh e+{-# INLINE [4] computeS #-}+computeS arr1+ = arr1 `deepSeqArray` + unsafePerformIO+ $ do marr2 <- newMArr (size $ extent arr1) + fillS arr1 marr2+ unsafeFreezeMArr (extent arr1) marr2+++++-- | Parallel copying of arrays.+--+-- * This is a wrapper that delays an array before calling `computeP`. +-- +-- * You can use it to copy manifest arrays between representations.+--+-- * You can also use it to compute elements, but doing this may not be as+-- efficient. This is because delaying it the second time can hide+-- information about the structure of the original computation.+--+copyP :: (Repr r1 e, Fill D r2 sh e)+ => Array r1 sh e -> Array r2 sh e+{-# INLINE [4] copyP #-}+copyP arr1 = computeP $ delay arr1+++-- | Sequential copying of arrays.+copyS :: (Repr r1 e, Fill D r2 sh e)+ => Array r1 sh e -> Array r2 sh e+{-# INLINE [4] copyS #-}+copyS arr1 = computeS $ delay arr1+++ ++-- | Apply `deepSeqArray` to an array so the result is actually constructed+-- at this point in a monadic computation. +--+-- * Haskell's laziness means that applications of `computeP` and `copyP` are+-- automatically suspended.+--+-- * Laziness can be problematic for data parallel programs, because we want+-- each array to be constructed in parallel before moving onto the next one.+-- +-- For example:+--+-- @ do arr2 <- now $ computeP $ map f arr1+-- arr3 <- now $ computeP $ zipWith arr2 arr1+-- return arr3+-- @+--+now :: (Shape sh, Repr r e, Monad m)+ => Array r sh e -> m (Array r sh e)+{-# INLINE [4] now #-}+now arr+ = do arr `deepSeqArray` return ()+ return arr
+ Data/Array/Repa/Eval/Chunked.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE MagicHash #-}+-- | Evaluate an array by breaking it up into linear chunks and filling+-- each chunk in parallel.+module Data.Array.Repa.Eval.Chunked+ ( fillChunkedP+ , fillChunkedS+ , fillChunkedS'+ , fillChunkedIOP)+where+import Data.Array.Repa.Eval.Gang+import GHC.Exts+import Prelude as P++-- | Fill something sequentially.+-- +-- * The array is filled linearly from start to finish. +-- +fillChunkedS+ :: Int -- ^ Number of elements.+ -> (Int -> a -> IO ()) -- ^ Update function to write into result buffer.+ -> (Int -> a) -- ^ Fn to get the value at a given index.+ -> IO ()++{-# INLINE [0] fillChunkedS #-}+fillChunkedS !(I# len) !write !getElem+ = fill 0#+ where fill !ix+ | ix >=# len = return ()+ | otherwise+ = do write (I# ix) (getElem (I# ix))+ fill (ix +# 1#)++fillChunkedS'+ :: Int+ -> (Int -> IO ())+ -> IO ()++fillChunkedS' !(I# len) eat+ = fill 0#+ where fill !ix+ | ix >=# len = return ()+ | otherwise+ = do eat (I# ix)+ fill (ix +# 1#)+++++-- | Fill something in parallel.+-- +-- * The array is split into linear chunks and each thread fills one chunk.+-- +fillChunkedP+ :: Int -- ^ Number of elements.+ -> (Int -> a -> IO ()) -- ^ Update function to write into result buffer.+ -> (Int -> a) -- ^ Fn to get the value at a given index.+ -> IO ()++{-# INLINE [0] fillChunkedP #-}+fillChunkedP !(I# len) !write !getElem+ = gangIO theGang+ $ \(I# thread) -> + let !start = splitIx thread+ !end = splitIx (thread +# 1#)+ in fill start end++ where+ -- Decide now to split the work across the threads.+ -- If the length of the vector doesn't divide evenly among the threads,+ -- then the first few get an extra element.+ !(I# threads) = gangSize theGang+ !chunkLen = len `quotInt#` threads+ !chunkLeftover = len `remInt#` threads++ {-# INLINE splitIx #-}+ splitIx thread+ | thread <# chunkLeftover = thread *# (chunkLen +# 1#)+ | otherwise = thread *# chunkLen +# chunkLeftover++ -- Evaluate the elements of a single chunk.+ {-# INLINE fill #-}+ fill !ix !end+ | ix >=# end = return ()+ | otherwise+ = do write (I# ix) (getElem (I# ix))+ fill (ix +# 1#) end+++-- | Fill something in parallel, using a separate IO action for each thread.+fillChunkedIOP+ :: Int -- ^ Number of elements.+ -> (Int -> a -> IO ()) -- ^ Update fn to write into result buffer.+ -> (Int -> IO (Int -> IO a)) -- ^ Create a fn to get the value at a given index.+ -- The first `Int` is the thread number, so you can do some+ -- per-thread initialisation.+ -> IO ()++{-# INLINE [0] fillChunkedIOP #-}+fillChunkedIOP !(I# len) !write !mkGetElem+ = gangIO theGang+ $ \(I# thread) -> + let !start = splitIx thread+ !end = splitIx (thread +# 1#)+ in fillChunk thread start end ++ where+ -- Decide now to split the work across the threads.+ -- If the length of the vector doesn't divide evenly among the threads,+ -- then the first few get an extra element.+ !(I# threads) = gangSize theGang+ !chunkLen = len `quotInt#` threads+ !chunkLeftover = len `remInt#` threads++ {-# INLINE splitIx #-}+ splitIx thread+ | thread <# chunkLeftover = thread *# (chunkLen +# 1#)+ | otherwise = thread *# chunkLen +# chunkLeftover+++ -- Given the threadId, starting and ending indices. + -- Make a function to get each element for this chunk+ -- and call it for every index.+ {-# INLINE fillChunk #-}+ fillChunk !thread !ixStart !ixEnd+ = do getElem <- mkGetElem (I# thread)+ fill getElem ixStart ixEnd+ + -- Call the provided getElem function for every element+ -- in a chunk, and feed the result to the write function.+ {-# INLINE fill #-}+ fill !getElem !ix0 !end+ = go ix0 + where go !ix+ | ix >=# end = return ()+ | otherwise+ = do x <- getElem (I# ix)+ write (I# ix) x+ go (ix +# 1#)
+ Data/Array/Repa/Eval/Cursored.hs view
@@ -0,0 +1,217 @@+{-# LANGUAGE MagicHash #-}+-- | Evaluate an array by dividing it into rectangular blocks and filling+-- each block in parallel.+module Data.Array.Repa.Eval.Cursored+ ( fillBlock2P+ , fillBlock2S+ , fillCursoredBlock2P+ , fillCursoredBlock2S )+where+import Data.Array.Repa.Index+import Data.Array.Repa.Shape+import Data.Array.Repa.Eval.Elt+import Data.Array.Repa.Eval.Gang+import GHC.Base (remInt, quotInt)+import Prelude as P+import GHC.Exts++-- Non-cursored interface -----------------------------------------------------+-- | Fill a block in a rank-2 array in parallel.+--+-- * Blockwise filling can be more cache-efficient than linear filling for+-- rank-2 arrays.+--+-- * Coordinates given are of the filled edges of the block.+-- +-- * We divide the block into columns, and give one column to each thread.+-- +-- * Each column is filled in row major order from top to bottom.+--+fillBlock2P + :: Elt a+ => (Int -> a -> IO ()) -- ^ Update function to write into result buffer.+ -> (DIM2 -> a) -- ^ Function to evaluate the element at an index.+ -> Int -- ^ Width of the whole array.+ -> Int -- ^ x0 lower left corner of block to fill+ -> Int -- ^ y0 + -> Int -- ^ x1 upper right corner of block to fill+ -> Int -- ^ y1+ -> IO ()++{-# INLINE [0] fillBlock2P #-}+fillBlock2P !write !getElem !imageWidth !x0 !y0 !x1 !y1+ = fillCursoredBlock2P + write id addDim getElem + imageWidth x0 y0 x1 y1+++-- | Fill a block in a rank-2 array sequentially.+--+-- * Blockwise filling can be more cache-efficient than linear filling for+-- rank-2 arrays.+--+-- * Coordinates given are of the filled edges of the block.+-- +-- * The block is filled in row major order from top to bottom.+--+fillBlock2S+ :: Elt a+ => (Int -> a -> IO ()) -- ^ Update function to write into result buffer.+ -> (DIM2 -> a) -- ^ Function to evaluate the element at an index.+ -> Int# -- ^ Width of the whole array.+ -> Int# -- ^ x0 lower left corner of block to fill+ -> Int# -- ^ y0+ -> Int# -- ^ x1 upper right corner of block to fill+ -> Int# -- ^ y1+ -> IO ()++{-# INLINE [0] fillBlock2S #-}+fillBlock2S !write !getElem imageWidth x0 y0 x1 y1+ = fillCursoredBlock2S+ write id addDim getElem + imageWidth x0 y0 x1 y1+++-- Block filling ----------------------------------------------------------------------------------+-- | Fill a block in a rank-2 array in parallel.+-- +-- * Blockwise filling can be more cache-efficient than linear filling for rank-2 arrays.+--+-- * Using cursor functions can help to expose inter-element indexing computations to+-- the GHC and LLVM optimisers.+--+-- * Coordinates given are of the filled edges of the block.+-- +-- * We divide the block into columns, and give one column to each thread.+-- +-- * Each column is filled in row major order from top to bottom.+--+fillCursoredBlock2P+ :: Elt a+ => (Int -> a -> IO ()) -- ^ Update function to write into result buffer.+ -> (DIM2 -> cursor) -- ^ Make a cursor to a particular element.+ -> (DIM2 -> cursor -> cursor) -- ^ Shift the cursor by an offset.+ -> (cursor -> a) -- ^ Function to evaluate the element at an index.+ -> Int -- ^ Width of the whole array.+ -> Int -- ^ x0 lower left corner of block to fill+ -> Int -- ^ y0+ -> Int -- ^ x1 upper right corner of block to fill+ -> Int -- ^ y1+ -> IO ()++{-# INLINE [0] fillCursoredBlock2P #-}+fillCursoredBlock2P+ !write+ !makeCursorFCB !shiftCursorFCB !getElemFCB+ !(I# imageWidth) !x0 !y0 !x1 !y1+ = gangIO theGang fillBlock+ where !threads = gangSize theGang+ !blockWidth = x1 - x0 + 1++ -- All columns have at least this many pixels.+ !colChunkLen = blockWidth `quotInt` threads++ -- Extra pixels that we have to divide between some of the threads.+ !colChunkSlack = blockWidth `remInt` threads++ -- Get the starting pixel of a column in the image.+ {-# INLINE colIx #-}+ colIx !ix+ | ix < colChunkSlack = x0 + ix * (colChunkLen + 1)+ | otherwise = x0 + ix * colChunkLen + colChunkSlack++ -- Give one column to each thread+ {-# INLINE fillBlock #-}+ fillBlock :: Int -> IO ()+ fillBlock !ix+ = let !(I# x0') = colIx ix+ !(I# x1') = colIx (ix + 1) - 1+ !(I# y0') = y0+ !(I# y1') = y1+ in fillCursoredBlock2S+ write+ makeCursorFCB shiftCursorFCB getElemFCB+ imageWidth x0' y0' x1' y1'+++-- | Fill a block in a rank-2 array, sequentially.+--+-- * Blockwise filling can be more cache-efficient than linear filling for rank-2 arrays.+--+-- * Using cursor functions can help to expose inter-element indexing computations to+-- the GHC and LLVM optimisers.+--+-- * Coordinates given are of the filled edges of the block.+--+-- * The block is filled in row major order from top to bottom.+--+fillCursoredBlock2S+ :: Elt a+ => (Int -> a -> IO ()) -- ^ Update function to write into result buffer.+ -> (DIM2 -> cursor) -- ^ Make a cursor to a particular element.+ -> (DIM2 -> cursor -> cursor) -- ^ Shift the cursor by an offset.+ -> (cursor -> a) -- ^ Function to evaluate an element at the given index.+ -> Int# -- ^ Width of the whole array.+ -> Int# -- ^ x0 lower left corner of block to fill.+ -> Int# -- ^ y0+ -> Int# -- ^ x1 upper right corner of block to fill.+ -> Int# -- ^ y1+ -> IO ()++{-# INLINE [0] fillCursoredBlock2S #-}+fillCursoredBlock2S+ !write+ !makeCursor !shiftCursor !getElem+ !imageWidth !x0 !y0 !x1 !y1++ = fillBlock y0++ where {-# INLINE fillBlock #-}+ fillBlock !y+ | y ># y1 = return ()+ | otherwise+ = do fillLine4 x0+ fillBlock (y +# 1#)++ where {-# INLINE fillLine4 #-}+ fillLine4 !x+ | x +# 4# ># x1 = fillLine1 x+ | otherwise+ = do -- Compute each source cursor based on the previous one so that+ -- the variable live ranges in the generated code are shorter.+ let srcCur0 = makeCursor (Z :. (I# y) :. (I# x))+ let srcCur1 = shiftCursor (Z :. 0 :. 1) srcCur0+ let srcCur2 = shiftCursor (Z :. 0 :. 1) srcCur1+ let srcCur3 = shiftCursor (Z :. 0 :. 1) srcCur2++ -- Get the result value for each cursor.+ let val0 = getElem srcCur0+ let val1 = getElem srcCur1+ let val2 = getElem srcCur2+ let val3 = getElem srcCur3++ -- Ensure that we've computed each of the result values before we+ -- write into the array. If the backend code generator can't tell+ -- our destination array doesn't alias with the source then writing+ -- to it can prevent the sharing of intermediate computations.+ touch val0+ touch val1+ touch val2+ touch val3++ -- Compute cursor into destination array.+ let !dstCur0 = x +# (y *# imageWidth)+ write (I# dstCur0) val0+ write (I# (dstCur0 +# 1#)) val1+ write (I# (dstCur0 +# 2#)) val2+ write (I# (dstCur0 +# 3#)) val3+ fillLine4 (x +# 4#)++ {-# INLINE fillLine1 #-}+ fillLine1 !x+ | x ># x1 = return ()+ | otherwise+ = do write (I# (x +# (y *# imageWidth)))+ (getElem $ makeCursor (Z :. (I# y) :. (I# x)))+ fillLine1 (x +# 1#)+
+ Data/Array/Repa/Eval/Elt.hs view
@@ -0,0 +1,282 @@+-- | Values that can be stored in Repa Arrays.+{-# LANGUAGE MagicHash, UnboxedTuples, TypeSynonymInstances, FlexibleInstances #-}+module Data.Array.Repa.Eval.Elt+ (Elt (..))+where+import GHC.Prim+import GHC.Exts+import GHC.Types+import GHC.Word+import GHC.Int+++-- Note that the touch# function is special because we can pass it boxed or unboxed+-- values. The argument type has kind ?, not just * or #.++-- | Element types that can be used with the blockwise filling functions.+-- +-- This class is mainly used to define the `touch` method. This is used internally+-- in the imeplementation of Repa to prevent let-binding from being floated+-- inappropriately by the GHC simplifier. Doing a `seq` sometimes isn't enough,+-- because the GHC simplifier can erase these, and still move around the bindings.+--+class Elt a where++ -- | Place a demand on a value at a particular point in an IO computation.+ touch :: a -> IO ()++ -- | Generic zero value, helpful for debugging.+ zero :: a++ -- | Generic one value, helpful for debugging.+ one :: a+++-- Bool -----------------------------------------------------------------------+instance Elt Bool where+ {-# INLINE touch #-}+ touch b+ = IO (\state -> case touch# b state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = False++ {-# INLINE one #-}+ one = True+++-- Floating -------------------------------------------------------------------+instance Elt Float where+ {-# INLINE touch #-}+ touch (F# f)+ = IO (\state -> case touch# f state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++instance Elt Double where+ {-# INLINE touch #-}+ touch (D# d)+ = IO (\state -> case touch# d state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++-- Int ------------------------------------------------------------------------+instance Elt Int where+ {-# INLINE touch #-}+ touch (I# i)+ = IO (\state -> case touch# i state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1++instance Elt Int8 where+ {-# INLINE touch #-}+ touch (I8# w)+ = IO (\state -> case touch# w state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++instance Elt Int16 where+ {-# INLINE touch #-}+ touch (I16# w)+ = IO (\state -> case touch# w state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++instance Elt Int32 where+ {-# INLINE touch #-}+ touch (I32# w)+ = IO (\state -> case touch# w state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++instance Elt Int64 where+ {-# INLINE touch #-}+ touch (I64# w)+ = IO (\state -> case touch# w state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++-- Word -----------------------------------------------------------------------+instance Elt Word where+ {-# INLINE touch #-}+ touch (W# i)+ = IO (\state -> case touch# i state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++instance Elt Word8 where+ {-# INLINE touch #-}+ touch (W8# w)+ = IO (\state -> case touch# w state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++instance Elt Word16 where+ {-# INLINE touch #-}+ touch (W16# w)+ = IO (\state -> case touch# w state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++instance Elt Word32 where+ {-# INLINE touch #-}+ touch (W32# w)+ = IO (\state -> case touch# w state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++instance Elt Word64 where+ {-# INLINE touch #-}+ touch (W64# w)+ = IO (\state -> case touch# w state of+ state' -> (# state', () #))++ {-# INLINE zero #-}+ zero = 0++ {-# INLINE one #-}+ one = 1+++-- Tuple ----------------------------------------------------------------------+instance (Elt a, Elt b) => Elt (a, b) where+ {-# INLINE touch #-}+ touch (a, b)+ = do touch a+ touch b++ {-# INLINE zero #-}+ zero = (zero, zero)++ {-# INLINE one #-}+ one = (one, one)+++instance (Elt a, Elt b, Elt c) => Elt (a, b, c) where+ {-# INLINE touch #-}+ touch (a, b, c)+ = do touch a+ touch b+ touch c++ {-# INLINE zero #-}+ zero = (zero, zero, zero)++ {-# INLINE one #-}+ one = (one, one, one)+++instance (Elt a, Elt b, Elt c, Elt d) => Elt (a, b, c, d) where+ {-# INLINE touch #-}+ touch (a, b, c, d)+ = do touch a+ touch b+ touch c+ touch d++ {-# INLINE zero #-}+ zero = (zero, zero, zero, zero)++ {-# INLINE one #-}+ one = (one, one, one, one)+++instance (Elt a, Elt b, Elt c, Elt d, Elt e) => Elt (a, b, c, d, e) where+ {-# INLINE touch #-}+ touch (a, b, c, d, e)+ = do touch a+ touch b+ touch c+ touch d+ touch e++ {-# INLINE zero #-}+ zero = (zero, zero, zero, zero, zero)++ {-# INLINE one #-}+ one = (one, one, one, one, one)+++instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f) => Elt (a, b, c, d, e, f) where+ {-# INLINE touch #-}+ touch (a, b, c, d, e, f)+ = do touch a+ touch b+ touch c+ touch d+ touch e+ touch f++ {-# INLINE zero #-}+ zero = (zero, zero, zero, zero, zero, zero)++ {-# INLINE one #-}+ one = (one, one, one, one, one, one)++
+ Data/Array/Repa/Eval/Fill.hs view
@@ -0,0 +1,71 @@++module Data.Array.Repa.Eval.Fill+ ( Fillable (..), fromList+ , Fill (..)+ , FillRange (..))+where+import Data.Array.Repa.Base+import Data.Array.Repa.Shape+import Control.Monad+import System.IO.Unsafe++-- Fillable -------------------------------------------------------------------+-- | Class of manifest array representations that can be filled in parallel +-- and then frozen into immutable Repa arrays.+class Fillable r e where++ -- | Mutable version of the representation.+ data MArr r e++ -- | Allocate a new mutable array of the given size.+ newMArr :: Int -> IO (MArr r e)++ -- | Write an element into the mutable array.+ unsafeWriteMArr :: MArr r e -> Int -> e -> IO ()++ -- | Freeze the mutable array into an immutable Repa array.+ unsafeFreezeMArr :: sh -> MArr r e -> IO (Array r sh e)+++-- | O(n). Construct a manifest array from a list.+fromList+ :: (Shape sh, Fillable r e)+ => sh -> [e] -> Array r sh e+fromList sh xx+ = unsafePerformIO+ $ do let len = length xx+ if len /= size sh+ then error "Data.Array.Repa.Eval.Fill.fromList: provide array shape does not match list length"+ else do+ marr <- newMArr len+ zipWithM_ (unsafeWriteMArr marr) [0..] xx+ unsafeFreezeMArr sh marr+++-- Fill -----------------------------------------------------------------------+-- | Compute all elements defined by an array and write them to a fillable+-- representation.+-- +-- Note that instances require that the source array to have a delayed+-- representation such as `D` or `C`. If you want to use a pre-existing+-- manifest array as the source then `delay` it first.+class (Shape sh, Repr r1 e, Fillable r2 e) => Fill r1 r2 sh e where+ -- | Fill an entire array sequentially.+ fillS :: Array r1 sh e -> MArr r2 e -> IO ()++ -- | Fill an entire array in parallel.+ fillP :: Array r1 sh e -> MArr r2 e -> IO ()+++-- FillRange ------------------------------------------------------------------+-- | Compute a range of elements defined by an array and write them to a fillable+-- representation.+class (Shape sh, Repr r1 e, Fillable r2 e) => FillRange r1 r2 sh e where+ -- | Fill a range of an array sequentially.+ fillRangeS :: Array r1 sh e -> MArr r2 e -> sh -> sh -> IO ()++ -- | Fill a range of an array in parallel.+ fillRangeP :: Array r1 sh e -> MArr r2 e -> sh -> sh -> IO ()+++
+ Data/Array/Repa/Eval/Gang.hs view
@@ -0,0 +1,218 @@+{-# LANGUAGE CPP #-}++-- | Gang Primitives.+module Data.Array.Repa.Eval.Gang+ ( theGang+ , Gang, forkGang, gangSize, gangIO, gangST) +where+import GHC.IO+import GHC.ST+import GHC.Conc (forkOn)+import Control.Concurrent.MVar+import Control.Exception (assert)+import Control.Monad+import GHC.Conc (numCapabilities)+import System.IO+++-- TheGang --------------------------------------------------------------------+-- | This globally shared gang is auto-initialised at startup and shared by all+-- Repa computations.+--+-- In a data parallel setting, it does not help to have multiple gangs+-- running at the same time. This is because a single data parallel+-- computation should already be able to keep all threads busy. If we had+-- multiple gangs running at the same time, then the system as a whole would+-- run slower as the gangs would contend for cache and thrash the scheduler.+--+-- If, due to laziness or otherwise, you try to start multiple parallel+-- Repa computations at the same time, then you will get the following+-- warning on stderr at runtime:+--+-- @Data.Array.Repa: Performing nested parallel computation sequentially.+-- You've probably called the 'compute' or 'copy' function while another+-- instance was already running. This can happen if the second version+-- was suspended due to lazy evaluation. Use 'deepSeqArray' to ensure that+-- each array is fully evaluated before you 'compute' the next one.+-- @+--+theGang :: Gang+{-# NOINLINE theGang #-}+theGang + = unsafePerformIO + $ do let caps = numCapabilities+ forkGang caps+++-- Requests -------------------------------------------------------------------+-- | The 'Req' type encapsulates work requests for individual members of a gang.+data Req+ -- | Instruct the worker to run the given action.+ = ReqDo (Int -> IO ())++ -- | Tell the worker that we're shutting the gang down.+ -- The worker should signal that it's receieved the request by+ -- writing to its result var before returning to the caller (forkGang).+ | ReqShutdown+++-- Gang -----------------------------------------------------------------------+-- | A 'Gang' is a group of threads that execute arbitrary work requests.+data Gang+ = Gang + { -- | Number of threads in the gang.+ _gangThreads :: !Int ++ -- | Workers listen for requests on these vars.+ , _gangRequestVars :: [MVar Req] ++ -- | Workers put their results in these vars.+ , _gangResultVars :: [MVar ()] ++ -- | Indicates that the gang is busy.+ , _gangBusy :: MVar Bool+ } ++instance Show Gang where+ showsPrec p (Gang n _ _ _)+ = showString "<<"+ . showsPrec p n+ . showString " threads>>"+++-- | O(1). Yield the number of threads in the 'Gang'.+gangSize :: Gang -> Int+gangSize (Gang n _ _ _) + = n+++-- | Fork a 'Gang' with the given number of threads (at least 1).+forkGang :: Int -> IO Gang+forkGang n+ = assert (n > 0)+ $ do+ -- Create the vars we'll use to issue work requests.+ mvsRequest <- sequence $ replicate n $ newEmptyMVar++ -- Create the vars we'll use to signal that threads are done.+ mvsDone <- sequence $ replicate n $ newEmptyMVar++ -- Add finalisers so we can shut the workers down cleanly if they+ -- become unreachable.+ zipWithM_ (\varReq varDone + -> addMVarFinalizer varReq (finaliseWorker varReq varDone)) + mvsRequest+ mvsDone++ -- Create all the worker threads+ zipWithM_ forkOn [0..]+ $ zipWith3 gangWorker + [0 .. n-1] mvsRequest mvsDone++ -- The gang is currently idle.+ busy <- newMVar False++ return $ Gang n mvsRequest mvsDone busy++++-- | The worker thread of a 'Gang'.+-- The threads blocks on the MVar waiting for a work request.+gangWorker :: Int -> MVar Req -> MVar () -> IO ()+gangWorker threadId varRequest varDone+ = do + -- Wait for a request + req <- takeMVar varRequest++ case req of+ ReqDo action+ -> do -- Run the action we were given.+ action threadId++ -- Signal that the action is complete.+ putMVar varDone ()++ -- Wait for more requests.+ gangWorker threadId varRequest varDone++ ReqShutdown+ -> putMVar varDone ()+++-- | Finaliser for worker threads.+-- We want to shutdown the corresponding thread when it's MVar becomes+-- unreachable.+-- Without this Repa programs can complain about "Blocked indefinitely+-- on an MVar" because worker threads are still blocked on the request+-- MVars when the program ends. Whether the finalizer is called or not+-- is very racey. It happens about 1 in 10 runs when for the+-- repa-edgedetect benchmark, and less often with the others.+--+-- We're relying on the comment in System.Mem.Weak that says+-- "If there are no other threads to run, the runtime system will+-- check for runnablefinalizers before declaring the system to be+-- deadlocked."+--+-- If we were creating and destroying the gang cleanly we wouldn't need+-- this, but theGang is created with a top-level unsafePerformIO.+-- Hacks beget hacks beget hacks...+--+finaliseWorker :: MVar Req -> MVar () -> IO ()+finaliseWorker varReq varDone + = do putMVar varReq ReqShutdown+ takeMVar varDone+ return ()+++-- | Issue work requests for the 'Gang' and wait until they complete.+--+-- If the gang is already busy then print a warning to `stderr` and just+-- run the actions sequentially in the requesting thread.+gangIO :: Gang+ -> (Int -> IO ())+ -> IO ()++{-# NOINLINE gangIO #-}+gangIO gang@(Gang _ _ _ busy) action+ = do b <- swapMVar busy True+ if b+ then do+ seqIO gang action++ else do+ parIO gang action+ _ <- swapMVar busy False+ return ()+++-- | Run an action on the gang sequentially.+seqIO :: Gang -> (Int -> IO ()) -> IO ()+seqIO (Gang n _ _ _) action+ = do hPutStr stderr+ $ unlines+ [ "Data.Array.Repa: Performing nested parallel computation sequentially."+ , " You've probably called the 'compute' or 'copy' function while another"+ , " instance was already running. This can happen if the second version"+ , " was suspended due to lazy evaluation. Use 'deepSeqArray' to ensure"+ , " that each array is fully evaluated before you 'compute' the next one."+ , "" ]++ mapM_ action [0 .. n-1]++-- | Run an action on the gang in parallel.+parIO :: Gang -> (Int -> IO ()) -> IO ()+parIO (Gang _ mvsRequest mvsResult _) action+ = do + -- Send requests to all the threads.+ mapM_ (\v -> putMVar v (ReqDo action)) mvsRequest++ -- Wait for all the requests to complete.+ mapM_ takeMVar mvsResult+++-- | Same as 'gangIO' but in the 'ST' monad.+gangST :: Gang -> (Int -> ST s ()) -> ST s ()+gangST g p = unsafeIOToST . gangIO g $ unsafeSTToIO . p+++
+ Data/Array/Repa/Eval/Reduction.hs view
@@ -0,0 +1,256 @@+{-# LANGUAGE BangPatterns, MagicHash #-}+module Data.Array.Repa.Eval.Reduction+ ( foldS, foldP+ , foldAllS, foldAllP)+where+import Data.Array.Repa.Eval.Elt+import Data.Array.Repa.Eval.Gang+import qualified Data.Vector.Unboxed as V+import qualified Data.Vector.Unboxed.Mutable as M+import GHC.Base ( quotInt, divInt )+import GHC.Exts++-- | Sequential reduction of a multidimensional array along the innermost dimension.+foldS :: (Elt a, V.Unbox a)+ => M.IOVector a -- ^ vector to write elements into+ -> (Int# -> a) -- ^ function to get an element from the given index+ -> (a -> a -> a) -- ^ binary associative combination function+ -> a -- ^ starting value (typically an identity)+ -> Int# -- ^ inner dimension (length to fold over)+ -> IO ()+{-# INLINE [1] foldS #-}+foldS vec !get !c !r !n+ = iter 0# 0#+ where+ !(I# end) = M.length vec++ {-# INLINE iter #-}+ iter !sh !sz + | sh >=# end = return ()+ | otherwise + = do let !next = sz +# n+ M.unsafeWrite vec (I# sh) (reduceAny get c r sz next)+ iter (sh +# 1#) next+++-- | Parallel reduction of a multidimensional array along the innermost dimension.+-- Each output value is computed by a single thread, with the output values+-- distributed evenly amongst the available threads.+foldP :: (Elt a, V.Unbox a)+ => M.IOVector a -- ^ vector to write elements into+ -> (Int -> a) -- ^ function to get an element from the given index+ -> (a -> a -> a) -- ^ binary associative combination operator + -> a -- ^ starting value. Must be neutral with respect+ -- ^ to the operator. eg @0 + a = a@.+ -> Int -- ^ inner dimension (length to fold over)+ -> IO ()+{-# INLINE [1] foldP #-}+foldP vec !f !c !r !(I# n)+ = gangIO theGang+ $ \(I# tid) -> fill (split tid) (split (tid +# 1#))+ where+ !(I# threads) = gangSize theGang+ !(I# len) = M.length vec+ !step = (len +# threads -# 1#) `quotInt#` threads++ {-# INLINE split #-}+ split !ix + = let !ix' = ix *# step+ in if len <# ix' + then len+ else ix'++ {-# INLINE fill #-}+ fill !start !end + = iter start (start *# n)+ where+ {-# INLINE iter #-}+ iter !sh !sz + | sh >=# end = return ()+ | otherwise + = do let !next = sz +# n+ M.unsafeWrite vec (I# sh) (reduce f c r (I# sz) (I# next))+ iter (sh +# 1#) next+++-- | Sequential reduction of all the elements in an array.+foldAllS :: (Elt a, V.Unbox a)+ => (Int# -> a) -- ^ function to get an element from the given index+ -> (a -> a -> a) -- ^ binary associative combining function+ -> a -- ^ starting value+ -> Int# -- ^ number of elements+ -> a++{-# INLINE [1] foldAllS #-}+foldAllS !f !c !r !len+ = reduceAny (\i -> f i) c r 0# len ++++-- | Parallel tree reduction of an array to a single value. Each thread takes an+-- equally sized chunk of the data and computes a partial sum. The main thread+-- then reduces the array of partial sums to the final result.+--+-- We don't require that the initial value be a neutral element, so each thread+-- computes a fold1 on its chunk of the data, and the seed element is only+-- applied in the final reduction step.+--+foldAllP :: (Elt a, V.Unbox a)+ => (Int -> a) -- ^ function to get an element from the given index+ -> (a -> a -> a) -- ^ binary associative combining function+ -> a -- ^ starting value+ -> Int -- ^ number of elements+ -> IO a+{-# INLINE [1] foldAllP #-}++foldAllP !f !c !r !len+ | len == 0 = return r+ | otherwise = do+ mvec <- M.unsafeNew chunks+ gangIO theGang $ \tid -> fill mvec tid (split tid) (split (tid+1))+ vec <- V.unsafeFreeze mvec+ return $! V.foldl' c r vec+ where+ !threads = gangSize theGang+ !step = (len + threads - 1) `quotInt` threads+ chunks = ((len + step - 1) `divInt` step) `min` threads++ {-# INLINE split #-}+ split !ix = len `min` (ix * step)++ {-# INLINE fill #-}+ fill !mvec !tid !start !end+ | start >= end = return ()+ | otherwise = M.unsafeWrite mvec tid (reduce f c (f start) (start+1) end)++++-- Reduce ---------------------------------------------------------------------+-- | This is the primitive reduction function.+-- We use manual specialisations and rewrite rules to avoid the result+-- being boxed up in the final iteration.+{-# INLINE [0] reduce #-}+reduce :: (Int -> a) -- ^ Get data from the array.+ -> (a -> a -> a) -- ^ Function to combine elements.+ -> a -- ^ Starting value.+ -> Int -- ^ Starting index in array.+ -> Int -- ^ Ending index in array.+ -> a -- ^ Result.+reduce f c r (I# start) (I# end)+ = reduceAny (\i -> f (I# i)) c r start end+++-- | Sequentially reduce values between the given indices+{-# INLINE [0] reduceAny #-}+reduceAny :: (Int# -> a) -> (a -> a -> a) -> a -> Int# -> Int# -> a+reduceAny !f !c !r !start !end + = iter start r+ where+ {-# INLINE iter #-}+ iter !i !z + | i >=# end = z + | otherwise = iter (i +# 1#) (f i `c` z)+++{-# INLINE [0] reduceInt #-}+reduceInt+ :: (Int# -> Int#)+ -> (Int# -> Int# -> Int#)+ -> Int# + -> Int# -> Int# + -> Int#++reduceInt !f !c !r !start !end + = iter start r+ where+ {-# INLINE iter #-}+ iter !i !z + | i >=# end = z + | otherwise = iter (i +# 1#) (f i `c` z)+++{-# INLINE [0] reduceFloat #-}+reduceFloat+ :: (Int# -> Float#) + -> (Float# -> Float# -> Float#)+ -> Float# + -> Int# -> Int# + -> Float#++reduceFloat !f !c !r !start !end + = iter start r+ where+ {-# INLINE iter #-}+ iter !i !z + | i >=# end = z + | otherwise = iter (i +# 1#) (f i `c` z)+++{-# INLINE [0] reduceDouble #-}+reduceDouble+ :: (Int# -> Double#) + -> (Double# -> Double# -> Double#)+ -> Double# + -> Int# -> Int# + -> Double#++reduceDouble !f !c !r !start !end + = iter start r+ where+ {-# INLINE iter #-}+ iter !i !z + | i >=# end = z + | otherwise = iter (i +# 1#) (f i `c` z)+++{-# INLINE unboxInt #-}+unboxInt :: Int -> Int#+unboxInt (I# i) = i+++{-# INLINE unboxFloat #-}+unboxFloat :: Float -> Float#+unboxFloat (F# f) = f+++{-# INLINE unboxDouble #-}+unboxDouble :: Double -> Double#+unboxDouble (D# d) = d+++{-# RULES "reduceInt" + forall (get :: Int# -> Int) f r start end+ . reduceAny get f r start end + = I# (reduceInt + (\i -> unboxInt (get i))+ (\d1 d2 -> unboxInt (f (I# d1) (I# d2)))+ (unboxInt r)+ start+ end)+ #-}+++{-# RULES "reduceFloat" + forall (get :: Int# -> Float) f r start end+ . reduceAny get f r start end + = F# (reduceFloat+ (\i -> unboxFloat (get i))+ (\d1 d2 -> unboxFloat (f (F# d1) (F# d2)))+ (unboxFloat r)+ start+ end)+ #-}+++{-# RULES "reduceDouble" + forall (get :: Int# -> Double) f r start end+ . reduceAny get f r start end + = D# (reduceDouble + (\i -> unboxDouble (get i))+ (\d1 d2 -> unboxDouble (f (D# d1) (D# d2)))+ (unboxDouble r)+ start+ end)+ #-}++
+ Data/Array/Repa/Eval/Selection.hs view
@@ -0,0 +1,126 @@+{-# LANGUAGE BangPatterns, ExplicitForAll, ScopedTypeVariables, PatternGuards #-}+module Data.Array.Repa.Eval.Selection+ (selectChunkedS, selectChunkedP)+where+import Data.Array.Repa.Eval.Gang+import Data.Array.Repa.Shape+import Data.Vector.Unboxed as V+import Data.Vector.Unboxed.Mutable as VM+import GHC.Base (remInt, quotInt)+import Prelude as P+import Control.Monad as P+import Data.IORef+++-- | Select indices matching a predicate.+-- +-- * This primitive can be useful for writing filtering functions.+--+selectChunkedS+ :: Shape sh+ => (sh -> a -> IO ()) -- ^ Update function to write into result.+ -> (sh -> Bool) -- ^ See if this predicate matches.+ -> (sh -> a) -- ^ .. and apply fn to the matching index+ -> sh -- ^ Extent of indices to apply to predicate.+ -> IO Int -- ^ Number of elements written to destination array.++{-# INLINE selectChunkedS #-}+selectChunkedS !fnWrite !fnMatch !fnProduce !shSize+ = fill 0 0+ where lenSrc = size shSize++ fill !nSrc !nDst+ | nSrc >= lenSrc = return nDst++ | ixSrc <- fromIndex shSize nSrc+ , fnMatch ixSrc+ = do fnWrite ixSrc (fnProduce ixSrc)+ fill (nSrc + 1) (nDst + 1)++ | otherwise+ = fill (nSrc + 1) nDst+++-- | Select indices matching a predicate, in parallel.+-- +-- * This primitive can be useful for writing filtering functions.+--+-- * The array is split into linear chunks, with one chunk being given to+-- each thread.+--+-- * The number of elements in the result array depends on how many threads+-- you're running the program with.+--+selectChunkedP+ :: forall a+ . Unbox a+ => (Int -> Bool) -- ^ See if this predicate matches.+ -> (Int -> a) -- .. and apply fn to the matching index+ -> Int -- Extent of indices to apply to predicate.+ -> IO [IOVector a] -- Chunks containing array elements.++{-# INLINE selectChunkedP #-}+selectChunkedP !fnMatch !fnProduce !len+ = do+ -- Make IORefs that the threads will write their result chunks to.+ -- We start with a chunk size proportial to the number of threads we have,+ -- but the threads themselves can grow the chunks if they run out of space.+ refs <- P.replicateM threads+ $ do vec <- VM.new $ len `div` threads+ newIORef vec++ -- Fire off a thread to fill each chunk.+ gangIO theGang+ $ \thread -> makeChunk (refs !! thread)+ (splitIx thread)+ (splitIx (thread + 1) - 1)++ -- Read the result chunks back from the IORefs.+ -- If a thread had to grow a chunk, then these might not be the same ones+ -- we created back in the first step.+ P.mapM readIORef refs++ where -- See how many threads we have available.+ !threads = gangSize theGang+ !chunkLen = len `quotInt` threads+ !chunkLeftover = len `remInt` threads+++ -- Decide where to split the source array.+ {-# INLINE splitIx #-}+ splitIx thread+ | thread < chunkLeftover = thread * (chunkLen + 1)+ | otherwise = thread * chunkLen + chunkLeftover+++ -- Fill the given chunk with elements selected from this range of indices.+ makeChunk :: IORef (IOVector a) -> Int -> Int -> IO ()+ makeChunk !ref !ixSrc !ixSrcEnd+ = do vecDst <- VM.new (len `div` threads)+ vecDst' <- fillChunk ixSrc ixSrcEnd vecDst 0 (VM.length vecDst - 1)+ writeIORef ref vecDst'+++ -- The main filling loop.+ fillChunk :: Int -> Int -> IOVector a -> Int -> Int -> IO (IOVector a)+ fillChunk !ixSrc !ixSrcEnd !vecDst !ixDst !ixDstEnd+ -- If we've finished selecting elements, then slice the vector down+ -- so it doesn't have any empty space at the end.+ | ixSrc >= ixSrcEnd+ = return $ VM.slice 0 ixDst vecDst++ -- If we've run out of space in the chunk then grow it some more.+ | ixDst >= ixDstEnd+ = do let ixDstEnd' = VM.length vecDst * 2 - 1+ vecDst' <- VM.grow vecDst (ixDstEnd + 1)+ fillChunk (ixSrc + 1) ixSrcEnd vecDst' (ixDst + 1) ixDstEnd'++ -- We've got a maching element, so add it to the chunk.+ | fnMatch ixSrc+ = do VM.unsafeWrite vecDst ixDst (fnProduce ixSrc)+ fillChunk (ixSrc + 1) ixSrcEnd vecDst (ixDst + 1) ixDstEnd++ -- The element doesnt match, so keep going.+ | otherwise+ = fillChunk (ixSrc + 1) ixSrcEnd vecDst ixDst ixDstEnd+
Data/Array/Repa/Index.hs view
@@ -27,7 +27,7 @@ -- | Our index type, used for both shapes and indices. infixl 3 :. data tail :. head- = tail :. head+ = !tail :. !head deriving (Show, Eq, Ord) -- Common dimensions@@ -41,39 +41,42 @@ -- Shape ------------------------------------------------------------------------------------------ instance Shape Z where- {-# INLINE rank #-}+ {-# INLINE [1] rank #-} rank _ = 0 - {-# INLINE zeroDim #-}- zeroDim = Z+ {-# INLINE [1] zeroDim #-}+ zeroDim = Z - {-# INLINE unitDim #-}+ {-# INLINE [1] unitDim #-} unitDim = Z - {-# INLINE intersectDim #-}+ {-# INLINE [1] intersectDim #-} intersectDim _ _ = Z - {-# INLINE addDim #-}+ {-# INLINE [1] addDim #-} addDim _ _ = Z - {-# INLINE size #-}+ {-# INLINE [1] size #-} size _ = 1 - {-# INLINE sizeIsValid #-}+ {-# INLINE [1] sizeIsValid #-} sizeIsValid _ = True - {-# INLINE toIndex #-}+ {-# INLINE [1] toIndex #-} toIndex _ _ = 0 - {-# INLINE fromIndex #-}+ {-# INLINE [1] fromIndex #-} fromIndex _ _ = Z - {-# INLINE inShapeRange #-}+ {-# INLINE [1] inShapeRange #-} inShapeRange Z Z Z = True + {-# NOINLINE listOfShape #-} listOfShape _ = []++ {-# NOINLINE shapeOfList #-} shapeOfList [] = Z shapeOfList _ = error $ stage ++ ".fromList: non-empty list when converting to Z." @@ -82,29 +85,29 @@ instance Shape sh => Shape (sh :. Int) where- {-# INLINE rank #-}+ {-# INLINE [1] rank #-} rank (sh :. _) = rank sh + 1 - {-# INLINE zeroDim #-}+ {-# INLINE [1] zeroDim #-} zeroDim = zeroDim :. 0 - {-# INLINE unitDim #-}+ {-# INLINE [1] unitDim #-} unitDim = unitDim :. 1 - {-# INLINE intersectDim #-}+ {-# INLINE [1] intersectDim #-} intersectDim (sh1 :. n1) (sh2 :. n2) = (intersectDim sh1 sh2 :. (min n1 n2)) - {-# INLINE addDim #-}+ {-# INLINE [1] addDim #-} addDim (sh1 :. n1) (sh2 :. n2) = addDim sh1 sh2 :. (n1 + n2) - {-# INLINE size #-}+ {-# INLINE [1] size #-} size (sh1 :. n) = size sh1 * n - {-# INLINE sizeIsValid #-}+ {-# INLINE [1] sizeIsValid #-} sizeIsValid (sh1 :. n) | size sh1 > 0 = n <= maxBound `div` size sh1@@ -112,29 +115,30 @@ | otherwise = False - {-# INLINE toIndex #-}+ {-# INLINE [1] toIndex #-} toIndex (sh1 :. sh2) (sh1' :. sh2') = toIndex sh1 sh1' * sh2 + sh2' - {-# INLINE fromIndex #-}- fromIndex (ds :. d) n- = fromIndex ds (n `quotInt` d) :. r- where- -- If we assume that the index is in range, there is no point- -- in computing the remainder for the highest dimension since- -- n < d must hold. This saves one remInt per element access which- -- is quite a big deal.- r | rank ds == 0 = n- | otherwise = n `remInt` d+ {-# INLINE [1] fromIndex #-}+ fromIndex (ds :. d) n+ = fromIndex ds (n `quotInt` d) :. r+ where+ -- If we assume that the index is in range, there is no point+ -- in computing the remainder for the highest dimension since+ -- n < d must hold. This saves one remInt per element access which+ -- is quite a big deal.+ r | rank ds == 0 = n+ | otherwise = n `remInt` d - {-# INLINE inShapeRange #-}+ {-# INLINE [1] inShapeRange #-} inShapeRange (zs :. z) (sh1 :. n1) (sh2 :. n2) = (n2 >= z) && (n2 < n1) && (inShapeRange zs sh1 sh2) -+ {-# NOINLINE listOfShape #-} listOfShape (sh :. n) = n : listOfShape sh + {-# NOINLINE shapeOfList #-} shapeOfList xx = case xx of [] -> error $ stage ++ ".toList: empty list when converting to (_ :. Int)"
− Data/Array/Repa/Internals/Base.hs
@@ -1,410 +0,0 @@-{-# LANGUAGE ExplicitForAll, TypeOperators, FlexibleInstances, UndecidableInstances, BangPatterns,- ExistentialQuantification #-}-module Data.Array.Repa.Internals.Base- ( Array (..)- , Region(..)- , Range (..)- , Rect (..)- , Generator(..)- , deepSeqArray, deepSeqArrays-- , singleton, toScalar- , extent, delay-- -- * Predicates- , inRange-- -- * Indexing- , (!), index- , (!?), safeIndex- , unsafeIndex-- -- * Construction- , fromFunction- , fromVector- , fromList- , unsafeFromForeignPtr)-where-import Data.Array.Repa.Index-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Shape as S-import qualified Data.Vector.Unboxed as V-import Data.Vector.Unboxed (Vector)-import Foreign.ForeignPtr-import Foreign.Storable-import System.IO.Unsafe--stage = "Data.Array.Repa.Array"---- Array ------------------------------------------------------------------------- | Repa arrays.-data Array sh a- = Array- { -- | The entire extent of the array.- arrayExtent :: sh-- -- | Arrays can be partitioned into several regions.- , arrayRegions :: [Region sh a] }----- | Defines the values in a region of the array.-data Region sh a- = Region- { -- | The range of elements this region applies to.- regionRange :: Range sh-- -- | How to compute the array elements in this region.- , regionGenerator :: Generator sh a }----- | Represents a range of elements in the array.-data Range sh- -- | Covers the entire array.- = RangeAll-- -- | The union of a possibly disjoint set of rectangles.- | RangeRects- { rangeMatch :: sh -> Bool- , rangeRects :: [Rect sh] }----- | A rectangle\/cube of arbitrary dimension.--- The indices are of the minimum and maximim elements to fill.-data Rect sh- = Rect sh sh---- | Generates array elements for a particular region in the array.-data Generator sh a- -- | Elements are already computed and sitting in this vector.- = GenManifest (Vector a)- -- NOTE: Don't make the vector field strict. If you do then deepSeqing arrays- -- outside of loops won't cause the unboxings to be floated out.-- -- | Elements can be computed using these cursor functions.- | forall cursor- . GenCursor- { -- | Make a cursor to a particular element.- genMakeCursor :: sh -> cursor-- -- | Shift the cursor by an offset, to get to another element.- , genShiftCursor :: sh -> cursor -> cursor-- -- | Load\/compute the element at the given cursor.- , genLoadElem :: cursor -> a }----- DeepSeqs ---------------------------------------------------------------------- | Ensure the structure for an array is fully evaluated.--- As we are in a lazy language, applying the @force@ function to a delayed array doesn't--- actually compute it at that point. Rather, Haskell builds a suspension representing the--- appliction of the @force@ function to that array. Use @deepSeqArray@ to ensure the array--- is actually computed at a particular point in the program.-infixr 0 `deepSeqArray`-deepSeqArray :: Shape sh => Array sh a -> b -> b-{-# INLINE deepSeqArray #-}-deepSeqArray (Array ex rgns) x- = ex `S.deepSeq` rgns `deepSeqRegions` x---- | Like `deepSeqArray` but seqs all the arrays in a list.--- This is specialised up to lists of 4 arrays. Using more in the list will break fusion.-infixr 0 `deepSeqArrays`-deepSeqArrays :: Shape sh => [Array sh a] -> b -> b-{-# INLINE deepSeqArrays #-}-deepSeqArrays as y- = case as of- [] -> y- [a] -> a `deepSeqArray` y- [a1, a2] -> a1 `deepSeqArray` a2 `deepSeqArray` y- [a1, a2, a3] -> a1 `deepSeqArray` a2 `deepSeqArray` a3 `deepSeqArray` y- [a1, a2, a3, a4]-> a1 `deepSeqArray` a2 `deepSeqArray` a3 `deepSeqArray` a4 `deepSeqArray` y- _ -> deepSeqArrays' as y--deepSeqArrays' as' y- = case as' of- [] -> y- x : xs -> x `deepSeqArray` xs `deepSeqArrays` y---- | Ensure the structure for a region is fully evaluated.-infixr 0 `deepSeqRegion`-deepSeqRegion :: Shape sh => Region sh a -> b -> b-{-# INLINE deepSeqRegion #-}-deepSeqRegion (Region range gen) x- = range `deepSeqRange` gen `deepSeqGen` x----- | Ensure the structure for some regions are fully evaluated.-infixr 0 `deepSeqRegions`-deepSeqRegions :: Shape sh => [Region sh a] -> b -> b-{-# INLINE deepSeqRegions #-}-deepSeqRegions rs y- = case rs of- [] -> y- [r] -> r `deepSeqRegion` y- [r1, r2] -> r1 `deepSeqRegion` r2 `deepSeqRegion` y- rs' -> deepSeqRegions' rs' y--deepSeqRegions' rs' y- = case rs' of- [] -> y- x : xs -> x `deepSeqRegion` xs `deepSeqRegions'` y----- | Ensure a range is fully evaluated.-infixr 0 `deepSeqRange`-deepSeqRange :: Shape sh => Range sh -> b -> b-{-# INLINE deepSeqRange #-}-deepSeqRange range x- = case range of- RangeAll -> x- RangeRects f rects -> f `seq` rects `seq` x----- | Ensure a Generator's structure is fully evaluated.-infixr 0 `deepSeqGen`-deepSeqGen :: Shape sh => Generator sh a -> b -> b-{-# INLINE deepSeqGen #-}-deepSeqGen gen x- = case gen of- GenManifest vec -> vec `seq` x- GenCursor{} -> x----- Predicates --------------------------------------------------------------------------------------inRange :: Shape sh => Range sh -> sh -> Bool-{-# INLINE inRange #-}-inRange RangeAll _ = True-inRange (RangeRects fn _) ix = fn ix----- Singletons ---------------------------------------------------------------------------------------- | Wrap a scalar into a singleton array.-singleton :: Elt a => a -> Array Z a-{-# INLINE singleton #-}-singleton = fromFunction Z . const---- | Take the scalar value from a singleton array.-toScalar :: Elt a => Array Z a -> a-{-# INLINE toScalar #-}-toScalar arr = arr ! Z----- Projections --------------------------------------------------------------------------------------- | Take the extent of an array.-extent :: Array sh a -> sh-{-# INLINE extent #-}-extent arr = arrayExtent arr----- | Unpack an array into delayed form.-delay :: (Shape sh, Elt a)- => Array sh a- -> (sh, sh -> a)--{-# INLINE delay #-}-delay arr@(Array sh _)- = (sh, (arr !))----- Indexing ------------------------------------------------------------------------------------------ | Get an indexed element from an array.--- This uses the same level of bounds checking as your Data.Vector installation.-(!), index- :: forall sh a- . (Shape sh, Elt a)- => Array sh a- -> sh- -> a--{-# INLINE (!) #-}-(!) arr ix = index arr ix--{-# INLINE index #-}-index arr ix- = case arr of- Array _ []- -> zero-- Array sh [Region _ gen1]- -> indexGen sh gen1 ix-- Array sh [Region r1 gen1, Region _ gen2]- | inRange r1 ix -> indexGen sh gen1 ix- | otherwise -> indexGen sh gen2 ix-- _ -> index' arr ix--- where {-# INLINE indexGen #-}- indexGen sh gen ix'- = case gen of- GenManifest vec- -> vec V.! (S.toIndex sh ix')-- GenCursor makeCursor _ loadElem- -> loadElem $ makeCursor ix'-- index' (Array sh (Region range gen : rs)) ix'- | inRange range ix = indexGen sh gen ix'- | otherwise = index' (Array sh rs) ix'-- index' (Array _ []) _- = zero------ | Get an indexed element from an array.--- If the element is out of range then `Nothing`.-(!?), safeIndex- :: forall sh a- . (Shape sh, Elt a)- => Array sh a- -> sh- -> Maybe a--{-# INLINE (!?) #-}-(!?) arr ix = safeIndex arr ix---{-# INLINE safeIndex #-}-safeIndex arr ix- = case arr of- Array _ []- -> Nothing-- Array sh [Region _ gen1]- -> indexGen sh gen1 ix-- Array sh [Region r1 gen1, Region r2 gen2]- | inRange r1 ix -> indexGen sh gen1 ix- | inRange r2 ix -> indexGen sh gen2 ix- | otherwise -> Nothing-- _ -> index' arr ix--- where {-# INLINE indexGen #-}- indexGen sh gen ix'- = case gen of- GenManifest vec- -> vec V.!? (S.toIndex sh ix')-- GenCursor makeCursor _ loadElem- -> Just (loadElem $ makeCursor ix')-- index' (Array sh (Region range gen : rs)) ix'- | inRange range ix = indexGen sh gen ix'- | otherwise = index' (Array sh rs) ix'-- index' (Array _ []) _- = Nothing----- | Get an indexed element from an array, without bounds checking.--- This assumes that the regions in the array give full coverage.--- An array with no regions gets zero for every element.-unsafeIndex- :: forall sh a- . (Shape sh, Elt a)- => Array sh a- -> sh- -> a--{-# INLINE unsafeIndex #-}-unsafeIndex arr ix- = case arr of- Array _ []- -> zero-- Array sh [Region _ gen1]- -> unsafeIndexGen sh gen1 ix-- Array sh [Region r1 gen1, Region _ gen2]- | inRange r1 ix -> unsafeIndexGen sh gen1 ix- | otherwise -> unsafeIndexGen sh gen2 ix-- _ -> unsafeIndex' arr ix-- where {-# INLINE unsafeIndexGen #-}- unsafeIndexGen sh gen ix'- = case gen of- GenManifest vec- -> vec `V.unsafeIndex` (S.toIndex sh ix')-- GenCursor makeCursor _ loadElem- -> loadElem $ makeCursor ix'-- unsafeIndex' (Array sh (Region range gen : rs)) ix'- | inRange range ix = unsafeIndexGen sh gen ix'- | otherwise = unsafeIndex' (Array sh rs) ix'-- unsafeIndex' (Array _ []) _- = zero----- Conversions --------------------------------------------------------------------------------------- | Create a `Delayed` array from a function.-fromFunction- :: Shape sh- => sh- -> (sh -> a)- -> Array sh a--{-# INLINE fromFunction #-}-fromFunction sh fnElems- = sh `S.deepSeq`- Array sh [Region- RangeAll- (GenCursor id addDim fnElems)]---- | Create a `Manifest` array from an unboxed `Vector`.--- The elements are in row-major order.-fromVector- :: Shape sh- => sh- -> Vector a- -> Array sh a--{-# INLINE fromVector #-}-fromVector sh vec- = sh `S.deepSeq` vec `seq`- Array sh [Region RangeAll (GenManifest vec)]----- | Convert a list to an array.--- The length of the list must be exactly the `size` of the extent given, else `error`.-fromList- :: (Shape sh, Elt a)- => sh- -> [a]- -> Array sh a--{-# INLINE fromList #-}-fromList sh xx- | V.length vec /= S.size sh- = error $ unlines- [ stage ++ ".fromList: size of array shape does not match size of list"- , " size of shape = " ++ (show $ S.size sh) ++ "\n"- , " size of list = " ++ (show $ V.length vec) ++ "\n" ]-- | otherwise- = Array sh [Region RangeAll (GenManifest vec)]-- where vec = V.fromList xx----- | Convert a `Ptr` to an `Array`. --- The data is used directly, and not copied.--- You promise not to modify the pointed-to data any further.--- -unsafeFromForeignPtr- :: (Shape sh, Elt a, Storable a)- => sh- -> ForeignPtr a - -> Array sh a--unsafeFromForeignPtr sh fptr- = fromFunction sh - (\ix -> unsafePerformIO - $ withForeignPtr fptr- (\ptr -> peekElemOff ptr $ toIndex sh ix))-
− Data/Array/Repa/Internals/Elt.hs
@@ -1,283 +0,0 @@--- | Values that can be stored in Repa Arrays.-{-# LANGUAGE MagicHash, UnboxedTuples, TypeSynonymInstances, FlexibleInstances #-}-module Data.Array.Repa.Internals.Elt- (Elt (..))-where-import GHC.Prim-import GHC.Exts-import GHC.Types-import GHC.Word-import GHC.Int-import Data.Vector.Unboxed----- Note that the touch# function is special because we can pass it boxed or unboxed--- values. The argument type has kind ?, not just * or #.---- | Element types that can be stored in Repa arrays.--- Repa uses `Data.Vector.Unboxed` to store the actual data. The implementation--- of this library is based on type families and picks an efficient, specialised--- representation for every element type. In particular, unboxed vectors of pairs--- are represented as pairs of unboxed vectors.-class (Show a, Unbox a) => Elt a where-- -- | We use this to prevent bindings from being floated inappropriatey.- -- Doing a `seq` sometimes isn't enough, because the GHC simplifier can- -- erase these, and/or still move around the bindings.- touch :: a -> IO ()-- -- | Generic zero value, helpful for debugging.- zero :: a-- -- | Generic one value, helpful for debugging.- one :: a----- Bool ------------------------------------------------------------------------instance Elt Bool where- {-# INLINE touch #-}- touch b- = IO (\state -> case touch# b state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = False-- {-# INLINE one #-}- one = True----- Floating --------------------------------------------------------------------instance Elt Float where- {-# INLINE touch #-}- touch (F# f)- = IO (\state -> case touch# f state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1---instance Elt Double where- {-# INLINE touch #-}- touch (D# d)- = IO (\state -> case touch# d state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1----- Int -------------------------------------------------------------------------instance Elt Int where- {-# INLINE touch #-}- touch (I# i)- = IO (\state -> case touch# i state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1--instance Elt Int8 where- {-# INLINE touch #-}- touch (I8# w)- = IO (\state -> case touch# w state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1---instance Elt Int16 where- {-# INLINE touch #-}- touch (I16# w)- = IO (\state -> case touch# w state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1---instance Elt Int32 where- {-# INLINE touch #-}- touch (I32# w)- = IO (\state -> case touch# w state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1---instance Elt Int64 where- {-# INLINE touch #-}- touch (I64# w)- = IO (\state -> case touch# w state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1----- Word ------------------------------------------------------------------------instance Elt Word where- {-# INLINE touch #-}- touch (W# i)- = IO (\state -> case touch# i state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1---instance Elt Word8 where- {-# INLINE touch #-}- touch (W8# w)- = IO (\state -> case touch# w state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1---instance Elt Word16 where- {-# INLINE touch #-}- touch (W16# w)- = IO (\state -> case touch# w state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1---instance Elt Word32 where- {-# INLINE touch #-}- touch (W32# w)- = IO (\state -> case touch# w state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1---instance Elt Word64 where- {-# INLINE touch #-}- touch (W64# w)- = IO (\state -> case touch# w state of- state' -> (# state', () #))-- {-# INLINE zero #-}- zero = 0-- {-# INLINE one #-}- one = 1----- Tuple -----------------------------------------------------------------------instance (Elt a, Elt b) => Elt (a, b) where- {-# INLINE touch #-}- touch (a, b)- = do touch a- touch b-- {-# INLINE zero #-}- zero = (zero, zero)-- {-# INLINE one #-}- one = (one, one)---instance (Elt a, Elt b, Elt c) => Elt (a, b, c) where- {-# INLINE touch #-}- touch (a, b, c)- = do touch a- touch b- touch c-- {-# INLINE zero #-}- zero = (zero, zero, zero)-- {-# INLINE one #-}- one = (one, one, one)---instance (Elt a, Elt b, Elt c, Elt d) => Elt (a, b, c, d) where- {-# INLINE touch #-}- touch (a, b, c, d)- = do touch a- touch b- touch c- touch d-- {-# INLINE zero #-}- zero = (zero, zero, zero, zero)-- {-# INLINE one #-}- one = (one, one, one, one)---instance (Elt a, Elt b, Elt c, Elt d, Elt e) => Elt (a, b, c, d, e) where- {-# INLINE touch #-}- touch (a, b, c, d, e)- = do touch a- touch b- touch c- touch d- touch e-- {-# INLINE zero #-}- zero = (zero, zero, zero, zero, zero)-- {-# INLINE one #-}- one = (one, one, one, one, one)---instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f) => Elt (a, b, c, d, e, f) where- {-# INLINE touch #-}- touch (a, b, c, d, e, f)- = do touch a- touch b- touch c- touch d- touch e- touch f-- {-# INLINE zero #-}- zero = (zero, zero, zero, zero, zero, zero)-- {-# INLINE one #-}- one = (one, one, one, one, one, one)--
− Data/Array/Repa/Internals/EvalBlockwise.hs
@@ -1,153 +0,0 @@-{-# LANGUAGE BangPatterns #-}---- | Old non-cursored, blockwise filling functions.--- NOTE: this isn't currently used.-module Data.Array.Repa.Internals.EvalBlockwise- ( fillVectorBlockwiseP- , fillVectorBlock- , fillVectorBlockP)-where-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Gang-import Data.Vector.Unboxed.Mutable as VM-import GHC.Base (remInt, quotInt)-import Prelude as P----- Blockwise filling -------------------------------------------------------------------------------fillVectorBlockwiseP- :: Elt a- => IOVector a -- ^ vector to write elements into- -> (Int -> a) -- ^ fn to evaluate an element at the given index- -> Int -- ^ width of image.- -> IO ()--{-# INLINE [0] fillVectorBlockwiseP #-}-fillVectorBlockwiseP !vec !getElemFVBP !imageWidth- = gangIO theGang fillBlock-- where !threads = gangSize theGang- !vecLen = VM.length vec- !imageHeight = vecLen `div` imageWidth- !colChunkLen = imageWidth `quotInt` threads- !colChunkSlack = imageWidth `remInt` threads--- {-# INLINE colIx #-}- colIx !ix- | ix < colChunkSlack = ix * (colChunkLen + 1)- | otherwise = ix * colChunkLen + colChunkSlack--- -- just give one column to each thread- {-# INLINE fillBlock #-}- fillBlock :: Int -> IO ()- fillBlock !ix- = let !x0 = colIx ix- !x1 = colIx (ix + 1)- !y0 = 0- !y1 = imageHeight- in fillVectorBlock vec getElemFVBP imageWidth x0 y0 x1 y1----- Block filling ------------------------------------------------------------------------------------- | Fill a block in a 2D image, in parallel.--- Coordinates given are of the filled edges of the block.--- We divide the block into columns, and give one column to each thread.-fillVectorBlockP- :: Elt a- => IOVector a -- ^ vector to write elements into- -> (Int -> a) -- ^ fn to evaluate an element at the given index.- -> Int -- ^ width of whole image- -> Int -- ^ x0 lower left corner of block to fill- -> Int -- ^ y0 (low x and y value)- -> Int -- ^ x1 upper right corner of block- -> Int -- ^ y1 (high x and y value, last index to fill)- -> IO ()--{-# INLINE [0] fillVectorBlockP #-}-fillVectorBlockP !vec !getElem !imageWidth !x0 !y0 !x1 !y1- = gangIO theGang fillBlock- where !threads = gangSize theGang- !blockWidth = x1 - x0 + 1-- -- All columns have at least this many pixels.- !colChunkLen = blockWidth `quotInt` threads-- -- Extra pixels that we have to divide between some of the threads.- !colChunkSlack = blockWidth `remInt` threads-- -- Get the starting pixel of a column in the image.- {-# INLINE colIx #-}- colIx !ix- | ix < colChunkSlack = x0 + ix * (colChunkLen + 1)- | otherwise = x0 + ix * colChunkLen + colChunkSlack-- -- Give one column to each thread- {-# INLINE fillBlock #-}- fillBlock :: Int -> IO ()- fillBlock !ix- = let !x0' = colIx ix- !x1' = colIx (ix + 1) - 1- !y0' = y0- !y1' = y1- in fillVectorBlock vec getElem imageWidth x0' y0' x1' y1'----- | Fill a block in a 2D image.--- Coordinates given are of the filled edges of the block.-fillVectorBlock- :: Elt a- => IOVector a -- ^ vector to write elements into.- -> (Int -> a) -- ^ fn to evaluate an element at the given index.- -> Int -- ^ width of whole image- -> Int -- ^ x0 lower left corner of block to fill- -> Int -- ^ y0 (low x and y value)- -> Int -- ^ x1 upper right corner of block- -> Int -- ^ y1 (high x and y value, last index to fill)- -> IO ()--{-# INLINE [0] fillVectorBlock #-}-fillVectorBlock !vec !getElemFVB !imageWidth !x0 !y0 !x1 !y1- = do -- putStrLn $ "fillVectorBlock: " P.++ show (x0, y0, x1, y1)- fillBlock ixStart (ixStart + (x1 - x0))- where- -- offset from end of one line to the start of the next.- !ixStart = x0 + y0 * imageWidth- !ixFinal = x1 + y1 * imageWidth-- {-# INLINE fillBlock #-}- fillBlock !ixLineStart !ixLineEnd- | ixLineStart > ixFinal = return ()- | otherwise- = do fillLine4 ixLineStart- fillBlock (ixLineStart + imageWidth) (ixLineEnd + imageWidth)-- where {-# INLINE fillLine4 #-}- fillLine4 !ix- | ix + 4 > ixLineEnd = fillLine1 ix- | otherwise- = do- let d0 = getElemFVB (ix + 0)- let d1 = getElemFVB (ix + 1)- let d2 = getElemFVB (ix + 2)- let d3 = getElemFVB (ix + 3)-- touch d0- touch d1- touch d2- touch d3-- VM.unsafeWrite vec (ix + 0) d0- VM.unsafeWrite vec (ix + 1) d1- VM.unsafeWrite vec (ix + 2) d2- VM.unsafeWrite vec (ix + 3) d3- fillLine4 (ix + 4)-- {-# INLINE fillLine1 #-}- fillLine1 !ix- | ix > ixLineEnd = return ()- | otherwise- = do VM.unsafeWrite vec ix (getElemFVB ix)- fillLine1 (ix + 1)-
− Data/Array/Repa/Internals/EvalChunked.hs
@@ -1,62 +0,0 @@--- | Evaluate a vector by breaking it up into linear chunks and filling each chunk--- in parallel.-{-# LANGUAGE BangPatterns #-}-module Data.Array.Repa.Internals.EvalChunked- ( fillChunkedS- , fillChunkedP)-where-import Data.Array.Repa.Internals.Gang-import GHC.Base (remInt, quotInt)-import Prelude as P----- | Fill something sequentially.-fillChunkedS- :: Int -- ^ Number of elements- -> (Int -> a -> IO ()) -- ^ Update function to write into result buffer- -> (Int -> a) -- ^ Fn to get the value at a given index.- -> IO ()--{-# INLINE [0] fillChunkedS #-}-fillChunkedS !len !write !getElem- = fill 0- where fill !ix- | ix >= len = return ()- | otherwise- = do write ix (getElem ix)- fill (ix + 1)----- | Fill something in parallel.-fillChunkedP- :: Int -- ^ Number of elements- -> (Int -> a -> IO ()) -- ^ Update function to write into result buffer- -> (Int -> a) -- ^ Fn to get the value at a given index.- -> IO ()--{-# INLINE [0] fillChunkedP #-}-fillChunkedP !len !write !getElem- = gangIO theGang- $ \thread -> fill (splitIx thread) (splitIx (thread + 1))-- where- -- Decide now to split the work across the threads.- -- If the length of the vector doesn't divide evenly among the threads,- -- then the first few get an extra element.- !threads = gangSize theGang- !chunkLen = len `quotInt` threads- !chunkLeftover = len `remInt` threads-- {-# INLINE splitIx #-}- splitIx thread- | thread < chunkLeftover = thread * (chunkLen + 1)- | otherwise = thread * chunkLen + chunkLeftover-- -- Evaluate the elements of a single chunk.- {-# INLINE fill #-}- fill !ix !end- | ix >= end = return ()- | otherwise- = do write ix (getElem ix)- fill (ix + 1) end-
− Data/Array/Repa/Internals/EvalCursored.hs
@@ -1,136 +0,0 @@--{-# LANGUAGE BangPatterns, UnboxedTuples #-}-module Data.Array.Repa.Internals.EvalCursored- ( fillCursoredBlock2P- , fillCursoredBlock2 )-where-import Data.Array.Repa.Index-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Gang-import GHC.Base (remInt, quotInt)-import Prelude as P----- Block filling ------------------------------------------------------------------------------------- | Fill a block in a 2D image, in parallel.--- Coordinates given are of the filled edges of the block.--- We divide the block into columns, and give one column to each thread.-fillCursoredBlock2P- :: Elt a- => (Int -> a -> IO ()) -- ^ Update function to write into result buffer- -> (DIM2 -> cursor) -- ^ make a cursor to a particular element- -> (DIM2 -> cursor -> cursor) -- ^ shift the cursor by an offset- -> (cursor -> a) -- ^ fn to evaluate an element at the given index.- -> Int -- ^ width of whole image- -> Int -- ^ x0 lower left corner of block to fill- -> Int -- ^ y0 (low x and y value)- -> Int -- ^ x1 upper right corner of block to fill- -> Int -- ^ y1 (high x and y value, index of last elem to fill)- -> IO ()--{-# INLINE [0] fillCursoredBlock2P #-}-fillCursoredBlock2P- !write- !makeCursorFCB !shiftCursorFCB !getElemFCB- !imageWidth !x0 !y0 !x1 !y1- = gangIO theGang fillBlock- where !threads = gangSize theGang- !blockWidth = x1 - x0 + 1-- -- All columns have at least this many pixels.- !colChunkLen = blockWidth `quotInt` threads-- -- Extra pixels that we have to divide between some of the threads.- !colChunkSlack = blockWidth `remInt` threads-- -- Get the starting pixel of a column in the image.- {-# INLINE colIx #-}- colIx !ix- | ix < colChunkSlack = x0 + ix * (colChunkLen + 1)- | otherwise = x0 + ix * colChunkLen + colChunkSlack-- -- Give one column to each thread- {-# INLINE fillBlock #-}- fillBlock :: Int -> IO ()- fillBlock !ix- = let !x0' = colIx ix- !x1' = colIx (ix + 1) - 1- !y0' = y0- !y1' = y1- in fillCursoredBlock2- write- makeCursorFCB shiftCursorFCB getElemFCB- imageWidth x0' y0' x1' y1'----- | Fill a block in a 2D image.--- Coordinates given are of the filled edges of the block.-fillCursoredBlock2- :: Elt a- => (Int -> a -> IO ()) -- ^ Update function to write into result buffer- -> (DIM2 -> cursor) -- ^ make a cursor to a particular element- -> (DIM2 -> cursor -> cursor) -- ^ shift the cursor by an offset- -> (cursor -> a) -- ^ fn to evaluate an element at the given index.- -> Int -- ^ width of whole image- -> Int -- ^ x0 lower left corner of block to fill- -> Int -- ^ y0 (low x and y value)- -> Int -- ^ x1 upper right corner of block to fill- -> Int -- ^ y1 (high x and y value, index of last elem to fill)- -> IO ()--{-# INLINE [0] fillCursoredBlock2 #-}-fillCursoredBlock2- !write- !makeCursor !shiftCursor !getElem- !imageWidth !x0 !y0 !x1 !y1-- = fillBlock y0-- where {-# INLINE fillBlock #-}- fillBlock !y- | y > y1 = return ()- | otherwise- = do fillLine4 x0- fillBlock (y + 1)-- where {-# INLINE fillLine4 #-}- fillLine4 !x- | x + 4 > x1 = fillLine1 x- | otherwise- = do -- Compute each source cursor based on the previous one so that- -- the variable live ranges in the generated code are shorter.- let srcCur0 = makeCursor (Z :. y :. x)- let srcCur1 = shiftCursor (Z :. 0 :. 1) srcCur0- let srcCur2 = shiftCursor (Z :. 0 :. 1) srcCur1- let srcCur3 = shiftCursor (Z :. 0 :. 1) srcCur2-- -- Get the result value for each cursor.- let val0 = getElem srcCur0- let val1 = getElem srcCur1- let val2 = getElem srcCur2- let val3 = getElem srcCur3-- -- Ensure that we've computed each of the result values before we- -- write into the array. If the backend code generator can't tell- -- our destination array doesn't alias with the source then writing- -- to it can prevent the sharing of intermediate computations.- touch val0- touch val1- touch val2- touch val3-- -- Compute cursor into destination array.- let !dstCur0 = x + y * imageWidth- write (dstCur0) val0- write (dstCur0 + 1) val1- write (dstCur0 + 2) val2- write (dstCur0 + 3) val3- fillLine4 (x + 4)-- {-# INLINE fillLine1 #-}- fillLine1 !x- | x > x1 = return ()- | otherwise- = do write (x + y * imageWidth) (getElem $ makeCursor (Z :. y :. x))- fillLine1 (x + 1)-
− Data/Array/Repa/Internals/EvalReduction.hs
@@ -1,121 +0,0 @@-{-# LANGUAGE BangPatterns #-}-module Data.Array.Repa.Internals.EvalReduction - ( foldS, foldP- , foldAllS, foldAllP)-where-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Gang-import qualified Data.Vector.Unboxed as V-import qualified Data.Vector.Unboxed.Mutable as M-import GHC.Base ( quotInt, divInt )----- | Sequential reduction of a multidimensional array along the innermost dimension.-foldS :: Elt a- => M.IOVector a -- ^ vector to write elements into- -> (Int -> a) -- ^ function to get an element from the given index- -> (a -> a -> a) -- ^ binary associative combination function- -> a -- ^ starting value (typically an identity)- -> Int -- ^ inner dimension (length to fold over)- -> IO ()-{-# INLINE foldS #-}-foldS vec !f !c !r !n = iter 0 0- where- !end = M.length vec-- {-# INLINE iter #-}- iter !sh !sz | sh >= end = return ()- | otherwise =- let !next = sz + n- in M.unsafeWrite vec sh (reduce f c r sz next) >> iter (sh+1) next----- | Parallel reduction of a multidimensional array along the innermost dimension.--- Each output value is computed by a single thread, with the output values--- distributed evenly amongst the available threads.-foldP :: Elt a- => M.IOVector a -- ^ vector to write elements into- -> (Int -> a) -- ^ function to get an element from the given index- -> (a -> a -> a) -- ^ binary associative combination operator - -> a -- ^ starting value. Must be neutral with respect- -- ^ to the operator. eg @0 + a = a@.- -> Int -- ^ inner dimension (length to fold over)- -> IO ()-{-# INLINE foldP #-}-foldP vec !f !c !r !n- = gangIO theGang- $ \tid -> fill (split tid) (split (tid+1))- where- !threads = gangSize theGang- !len = M.length vec- !step = (len + threads - 1) `quotInt` threads-- {-# INLINE split #-}- split !ix = len `min` (ix * step)-- {-# INLINE fill #-}- fill !start !end = iter start (start * n)- where- {-# INLINE iter #-}- iter !sh !sz | sh >= end = return ()- | otherwise =- let !next = sz + n- in M.unsafeWrite vec sh (reduce f c r sz next) >> iter (sh+1) next----- | Sequential reduction of all the elements in an array.-foldAllS :: Elt a- => (Int -> a) -- ^ function to get an element from the given index- -> (a -> a -> a) -- ^ binary associative combining function- -> a -- ^ starting value- -> Int -- ^ number of elements- -> IO a-{-# INLINE foldAllS #-}-foldAllS !f !c !r !len = return $! reduce f c r 0 len----- | Parallel tree reduction of an array to a single value. Each thread takes an--- equally sized chunk of the data and computes a partial sum. The main thread--- then reduces the array of partial sums to the final result.------ We don't require that the initial value be a neutral element, so each thread--- computes a fold1 on its chunk of the data, and the seed element is only--- applied in the final reduction step.----foldAllP :: Elt a- => (Int -> a) -- ^ function to get an element from the given index- -> (a -> a -> a) -- ^ binary associative combining function- -> a -- ^ starting value- -> Int -- ^ number of elements- -> IO a-{-# INLINE foldAllP #-}-foldAllP !f !c !r !len- | len == 0 = return r- | otherwise = do- mvec <- M.unsafeNew chunks- gangIO theGang $ \tid -> fill mvec tid (split tid) (split (tid+1))- vec <- V.unsafeFreeze mvec- return $! V.foldl' c r vec- where- !threads = gangSize theGang- !step = (len + threads - 1) `quotInt` threads- chunks = ((len + step - 1) `divInt` step) `min` threads-- {-# INLINE split #-}- split !ix = len `min` (ix * step)-- {-# INLINE fill #-}- fill !mvec !tid !start !end- | start >= end = return ()- | otherwise = M.unsafeWrite mvec tid (reduce f c (f start) (start+1) end)----- | Sequentially reduce values between the given indices-{-# INLINE reduce #-}-reduce :: (Int -> a) -> (a -> a -> a) -> a -> Int -> Int -> a-reduce !f !c !r !start !end = iter start r- where- {-# INLINE iter #-}- iter !i !z | i >= end = z- | otherwise = iter (i+1) (f i `c` z)-
− Data/Array/Repa/Internals/Forcing.hs
@@ -1,215 +0,0 @@-{-# LANGUAGE BangPatterns #-}-module Data.Array.Repa.Internals.Forcing- ( toVector- , toList- , force, forceWith- , force2, forceWith2)-where-import Data.Array.Repa.Internals.EvalChunked-import Data.Array.Repa.Internals.EvalCursored-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Base-import Data.Array.Repa.Index-import Data.Array.Repa.Shape as S-import qualified Data.Vector.Unboxed as V-import qualified Data.Vector.Unboxed.Mutable as VM-import Data.Vector.Unboxed (Vector)-import System.IO.Unsafe--stage = "Data.Array.Repa.Internals.Forcing"----- Conversions that also force the array ------------------------------------------------------------- | Convert an array to an unboxed `Data.Vector`, forcing it if required.--- The elements come out in row-major order.-toVector- :: (Shape sh, Elt a)- => Array sh a- -> Vector a-{-# INLINE toVector #-}-toVector arr- = case force arr of- Array _ [Region _ (GenManifest vec)] -> vec- _ -> error $ stage ++ ".toVector: force failed"----- | Convert an array to a list, forcing it if required.-toList :: (Shape sh, Elt a)- => Array sh a- -> [a]--{-# INLINE toList #-}-toList arr- = V.toList $ toVector arr----- Forcing ------------------------------------------------------------------------------------------- | Force an array, so that it becomes `Manifest`.--- The array is split into linear chunks and each chunk evaluated in parallel.-force :: (Shape sh, Elt a)- => Array sh a -> Array sh a--{-# INLINE [2] force #-}-force arr- = unsafePerformIO- $ do (sh, vec) <- forceIO arr- return $ sh `seq` vec `seq`- Array sh [Region RangeAll (GenManifest vec)]-- where forceIO arr'- = case arr' of- -- Don't force an already forced array.- Array sh [Region RangeAll (GenManifest vec)]- -> return (sh, vec)-- Array sh _- -> do mvec <- VM.unsafeNew (S.size sh)- forceWith (VM.unsafeWrite mvec) arr'- vec <- V.unsafeFreeze mvec- return (sh, vec)----- | Force an array, passing elements to the provided update function.--- Provide something like @(Foreign.Ptr.pokeElemOff ptr)@ to write elements into a buffer.--- The array is split into linear chunks and each chunk is evaluated in parallel.-forceWith- :: (Shape sh, Elt a)- => (Int -> a -> IO ())- -> Array sh a- -> IO ()--{-# INLINE [2] forceWith #-} -forceWith !update arr@(Array sh _)- = fillChunkedP - (S.size sh)- update- (\ix -> arr `unsafeIndex` fromIndex sh ix)----- | Force an array, so that it becomes `Manifest`.--- This forcing function is specialised for DIM2 arrays, and does blockwise filling.-force2 :: Elt a => Array DIM2 a -> Array DIM2 a-{-# INLINE [2] force2 #-}-force2 arr- = unsafePerformIO- $ do (sh, vec) <- forceIO2 arr- return $ sh `seq` vec `seq`- Array sh [Region RangeAll (GenManifest vec)]-- where forceIO2 arr'- = arr' `deepSeqArray`- case arr' of- -- Don't force an already forced array.- Array sh [Region RangeAll (GenManifest vec)]- -> return (sh, vec)-- -- Create a vector to hold the new array and load in the regions.- Array sh _- -> do mvec <- VM.new (S.size sh)- forceWith2 (VM.unsafeWrite mvec) arr'- vec <- V.unsafeFreeze mvec- return (sh, vec)----- | Force an array, passing elements to the provided update function.--- Provide something like @(Foreign.Ptr.pokeElemOff ptr)@ to write elements into a buffer.--- This forcing function is specialised for DIM2 arrays, and does blockwise filling.-forceWith2- :: Elt a- => (Int -> a -> IO ())- -> Array DIM2 a- -> IO ()--{-# INLINE [2] forceWith2 #-}-forceWith2 !write arr- = arr `deepSeqArray`- case arr of- -- If the array is already manifest then copy it into the buffer.- -- We don't need a particular traversal order just for a copy.- Array _ [Region RangeAll (GenManifest _)]- -> forceWith write arr-- -- NOTE We must specialise this for common numbers of regions so that- -- we get fusion for them. If we just have the last case (arbitrary- -- region list) then the worker won't fuse with the filling /- -- evaluation code.- Array sh [r1]- -> do fillRegion2P write sh r1-- Array sh [r1, r2]- -> do fillRegion2P write sh r1- fillRegion2P write sh r2-- Array sh regions- -> do mapM_ (fillRegion2P write sh) regions----- FillRegion2P -------------------------------------------------------------------------------------- | Fill an array region into a vector.--- This is specialised for DIM2 regions.--- The region is evaluated in parallel in a blockwise manner, where each block is--- evaluated independently and in a separate thread. For delayed or cursored regions--- access their source elements from the local neighbourhood, this specialised version--- should given better cache performance than plain `fillRegionP`.----fillRegion2P- :: Elt a- => (Int -> a -> IO ()) -- ^ Update function to write into result buffer- -> DIM2 -- ^ Extent of entire array.- -> Region DIM2 a -- ^ Region to fill.- -> IO ()--{-# INLINE [1] fillRegion2P #-}-fillRegion2P write sh@(_ :. height :. width) (Region range gen)- = write `seq` height `seq` width `seq`- case range of- RangeAll- -> fillRect2 write sh gen- (Rect (Z :. 0 :. 0)- (Z :. height - 1 :. width - 1))-- RangeRects _ [r1]- -> do fillRect2 write sh gen r1-- RangeRects _ [r1, r2]- -> do fillRect2 write sh gen r1- fillRect2 write sh gen r2-- RangeRects _ [r1, r2, r3]- -> do fillRect2 write sh gen r1- fillRect2 write sh gen r2- fillRect2 write sh gen r3-- RangeRects _ [r1, r2, r3, r4]- -> do fillRect2 write sh gen r1- fillRect2 write sh gen r2- fillRect2 write sh gen r3- fillRect2 write sh gen r4-- RangeRects _ rects- -> mapM_ (fillRect2 write sh gen) rects----- | Fill a rectangle in a vector.-fillRect2- :: Elt a- => (Int -> a -> IO ()) -- ^ Update function to write into result buffer- -> DIM2 -- ^ Extent of entire array.- -> Generator DIM2 a -- ^ Generator for array elements.- -> Rect DIM2 -- ^ Rectangle to fill.- -> IO ()--{-# INLINE fillRect2 #-}-fillRect2 write sh@(_ :. _ :. width) gen (Rect (Z :. y0 :. x0) (Z :. y1 :. x1))- = write `seq` width `seq` y0 `seq` x0 `seq` y1 `seq` x1 `seq`- case gen of- GenManifest vec- -> fillCursoredBlock2P write- id addDim (\ix -> vec `V.unsafeIndex` toIndex sh ix)- width x0 y0 x1 y1-- -- Cursor based arrays.- GenCursor makeCursor shiftCursor loadElem- -> fillCursoredBlock2P write- makeCursor shiftCursor loadElem- width x0 y0 x1 y1
− Data/Array/Repa/Internals/Gang.hs
@@ -1,249 +0,0 @@-{-# LANGUAGE CPP #-}---- | Gang Primitives.--- Based on DPH code by Roman Leshchinskiy------ Gang primitives.----#define TRACE_GANG 0--module Data.Array.Repa.Internals.Gang- ( Gang, seqGang, forkGang, gangSize, gangIO, gangST, traceGang, traceGangST- , theGang)-where-import GHC.IO-import GHC.ST-import GHC.Conc (forkOn)--import Control.Concurrent.MVar-import Control.Exception (assert)--import Control.Monad (zipWithM, zipWithM_)-import GHC.Conc (numCapabilities)-import System.IO--#if TRACE_GANG-import GHC.Exts (traceEvent)-import System.Time ( ClockTime(..), getClockTime )-#endif---- TheGang ------------------------------------------------------------------------------------------- | The gang is shared by all computations.-theGang :: Gang-{-# NOINLINE theGang #-}-theGang = unsafePerformIO $ forkGang numCapabilities----- Requests ------------------------------------------------------------------------------------------ | The 'Req' type encapsulates work requests for individual members of a gang.-data Req- -- | Instruct the worker to run the given action then signal it's done- -- by writing to the MVar.- = ReqDo (Int -> IO ()) (MVar ())-- -- | Tell the worker that we're shutting the gang down. The worker should- -- signal that it's received the request down by writing to the MVar- -- before returning to its caller (forkGang)- | ReqShutdown (MVar ())----- | Create a new request for the given action.-newReq :: (Int -> IO ()) -> IO Req-newReq p- = do mv <- newEmptyMVar- return $ ReqDo p mv----- | Block until a thread request has been executed.--- NOTE: only one thread can wait for the request.-waitReq :: Req -> IO ()-waitReq req- = case req of- ReqDo _ varDone -> takeMVar varDone- ReqShutdown varDone -> takeMVar varDone----- Gang --------------------------------------------------------------------------------------------- | A 'Gang' is a group of threads which execute arbitrary work requests.--- To get the gang to do work, write Req-uest values to its MVars-data Gang- = Gang !Int -- Number of 'Gang' threads- [MVar Req] -- One 'MVar' per thread- (MVar Bool) -- Indicates whether the 'Gang' is busy---instance Show Gang where- showsPrec p (Gang n _ _)- = showString "<<"- . showsPrec p n- . showString " threads>>"----- | A sequential gang has no threads.-seqGang :: Gang -> Gang-seqGang (Gang n _ mv) = Gang n [] mv----- | The worker thread of a 'Gang'.--- The threads blocks on the MVar waiting for a work request.-gangWorker :: Int -> MVar Req -> IO ()-gangWorker threadId varReq- = do traceGang $ "Worker " ++ show threadId ++ " waiting for request."- req <- takeMVar varReq-- case req of- ReqDo action varDone- -> do traceGang $ "Worker " ++ show threadId ++ " begin"- start <- getGangTime- action threadId- end <- getGangTime- traceGang $ "Worker " ++ show threadId ++ " end (" ++ diffTime start end ++ ")"-- putMVar varDone ()- gangWorker threadId varReq-- ReqShutdown varDone- -> do traceGang $ "Worker " ++ show threadId ++ " shutting down."- putMVar varDone ()----- | Finaliser for worker threads.--- We want to shutdown the corresponding thread when it's MVar becomes unreachable.--- Without this Repa programs can complain about "Blocked indefinitely on an MVar"--- because worker threads are still blocked on the request MVars when the program ends.--- Whether the finalizer is called or not is very racey. It happens about 1 in 10 runs--- when for the repa-edgedetect benchmark, and less often with the others.------ We're relying on the comment in System.Mem.Weak that says--- "If there are no other threads to run, the runtime system will check for runnable--- finalizers before declaring the system to be deadlocked."------ If we were creating and destroying the gang cleanly we wouldn't need this, but theGang--- is created with a top-level unsafePerformIO. Hacks beget hacks beget hacks...----finaliseWorker :: MVar Req -> IO ()-finaliseWorker varReq- = do varDone <- newEmptyMVar- putMVar varReq (ReqShutdown varDone)- takeMVar varDone- return ()----- | Fork a 'Gang' with the given number of threads (at least 1).-forkGang :: Int -> IO Gang-forkGang n- = assert (n > 0)- $ do- -- Create the vars we'll use to issue work requests.- mvs <- sequence . replicate n $ newEmptyMVar-- -- Add finalisers so we can shut the workers down cleanly if they become unreachable.- mapM_ (\var -> addMVarFinalizer var (finaliseWorker var)) mvs-- -- Create all the worker threads- zipWithM_ forkOn [0..]- $ zipWith gangWorker [0 .. n-1] mvs-- -- The gang is currently idle.- busy <- newMVar False-- return $ Gang n mvs busy----- | The number of threads in the 'Gang'.-gangSize :: Gang -> Int-gangSize (Gang n _ _) = n----- | Issue work requests for the 'Gang' and wait until they have been executed.--- If the gang is already busy then just run the action in the--- requesting thread.------ TODO: We might want to print a configurable warning that this is happening.----gangIO :: Gang- -> (Int -> IO ())- -> IO ()--{-# NOINLINE gangIO #-}-gangIO (Gang n mvs busy) p- = do traceGang "gangIO: issuing work requests (SEQ_IF_GANG_BUSY)"- b <- swapMVar busy True-- traceGang $ "gangIO: gang is currently " ++ (if b then "busy" else "idle")- if b- then do- hPutStr stderr- $ unlines [ "Data.Array.Repa: Performing nested parallel computation sequentially."- , " You've probably called the 'force' function while another instance was"- , " already running. This can happen if the second version was suspended due"- , " to lazy evaluation. Use 'deepSeqArray' to ensure that each array is fully"- , " evaluated before you 'force' the next one."- , "" ]-- mapM_ p [0 .. n-1]-- else do- parIO n mvs p- _ <- swapMVar busy False- return ()----- | Issue some requests to the worker threads and wait for them to complete.-parIO :: Int -- ^ Number of threads in the gang.- -> [MVar Req] -- ^ Request vars for worker threads.- -> (Int -> IO ()) -- ^ Action to run in all the workers, it's given the ix of- -- the particular worker thread it's running on.- -> IO ()--parIO n mvs p- = do traceGang "parIO: begin"-- start <- getGangTime- reqs <- sequence . replicate n $ newReq p-- traceGang "parIO: issuing requests"- _ <- zipWithM putMVar mvs reqs-- traceGang "parIO: waiting for requests to complete"- mapM_ waitReq reqs- end <- getGangTime-- traceGang $ "parIO: end " ++ diffTime start end----- | Same as 'gangIO' but in the 'ST' monad.-gangST :: Gang -> (Int -> ST s ()) -> ST s ()-gangST g p = unsafeIOToST . gangIO g $ unsafeSTToIO . p----- Tracing -----------------------------------------------------------------------------------------#if TRACE_GANG-getGangTime :: IO Integer-getGangTime- = do TOD sec pico <- getClockTime- return (pico + sec * 1000000000000)--diffTime :: Integer -> Integer -> String-diffTime x y = show (y-x)--traceGang :: String -> IO ()-traceGang s- = do t <- getGangTime- traceEvent $ show t ++ " @ " ++ s--#else-getGangTime :: IO ()-getGangTime = return ()--diffTime :: () -> () -> String-diffTime _ _ = ""--traceGang :: String -> IO ()-traceGang _ = return ()--#endif--traceGangST :: String -> ST s ()-traceGangST s = unsafeIOToST (traceGang s)-
− Data/Array/Repa/Internals/Select.hs
@@ -1,118 +0,0 @@-{-# LANGUAGE BangPatterns, ExplicitForAll, ScopedTypeVariables, PatternGuards #-}-module Data.Array.Repa.Internals.Select- (selectChunkedS, selectChunkedP)-where-import Data.Array.Repa.Internals.Gang-import Data.Array.Repa.Shape-import Data.Vector.Unboxed as V-import Data.Vector.Unboxed.Mutable as VM-import GHC.Base (remInt, quotInt)-import Prelude as P-import Control.Monad as P-import Data.IORef---- | Select indices matching a predicate-selectChunkedS- :: (Shape sh, Unbox a)- => (sh -> Bool) -- ^ See if this predicate matches.- -> (sh -> a) -- ^ .. and apply fn to the matching index- -> IOVector a -- ^ .. then write the result into the vector.- -> sh -- ^ Extent of indices to apply to predicate.- -> IO Int -- ^ Number of elements written to destination array.--{-# INLINE selectChunkedS #-}-selectChunkedS match produce !vDst !shSize- = fill 0 0- where lenSrc = size shSize- lenDst = VM.length vDst-- fill !nSrc !nDst- | nSrc >= lenSrc = return nDst- | nDst >= lenDst = return nDst-- | ixSrc <- fromIndex shSize nSrc- , match ixSrc- = do VM.unsafeWrite vDst nDst (produce ixSrc)- fill (nSrc + 1) (nDst + 1)-- | otherwise- = fill (nSrc + 1) nDst----- | Select indices matching a predicate, in parallel.--- The array is chunked up, with one chunk being given to each thread.--- The number of elements in the result array depends on how many threads--- you're running the program with.-selectChunkedP- :: forall a- . Unbox a- => (Int -> Bool) -- ^ See if this predicate matches.- -> (Int -> a) -- .. and apply fn to the matching index- -> Int -- Extent of indices to apply to predicate.- -> IO [IOVector a] -- Chunks containing array elements.--{-# INLINE selectChunkedP #-}-selectChunkedP !match !produce !len- = do- -- Make IORefs that the threads will write their result chunks to.- -- We start with a chunk size proportial to the number of threads we have,- -- but the threads themselves can grow the chunks if they run out of space.- refs <- P.replicateM threads- $ do vec <- VM.new $ len `div` threads- newIORef vec-- -- Fire off a thread to fill each chunk.- gangIO theGang- $ \thread -> makeChunk (refs !! thread)- (splitIx thread)- (splitIx (thread + 1) - 1)-- -- Read the result chunks back from the IORefs.- -- If a thread had to grow a chunk, then these might not be the same ones- -- we created back in the first step.- P.mapM readIORef refs-- where -- See how many threads we have available.- !threads = gangSize theGang- !chunkLen = len `quotInt` threads- !chunkLeftover = len `remInt` threads--- -- Decide where to split the source array.- {-# INLINE splitIx #-}- splitIx thread- | thread < chunkLeftover = thread * (chunkLen + 1)- | otherwise = thread * chunkLen + chunkLeftover--- -- Fill the given chunk with elements selected from this range of indices.- makeChunk :: IORef (IOVector a) -> Int -> Int -> IO ()- makeChunk !ref !ixSrc !ixSrcEnd- = do vecDst <- VM.new (len `div` threads)- vecDst' <- fillChunk ixSrc ixSrcEnd vecDst 0 (VM.length vecDst - 1)- writeIORef ref vecDst'--- -- The main filling loop.- fillChunk :: Int -> Int -> IOVector a -> Int -> Int -> IO (IOVector a)- fillChunk !ixSrc !ixSrcEnd !vecDst !ixDst !ixDstEnd- -- If we've finished selecting elements, then slice the vector down- -- so it doesn't have any empty space at the end.- | ixSrc >= ixSrcEnd- = return $ VM.slice 0 ixDst vecDst-- -- If we've run out of space in the chunk then grow it some more.- | ixDst >= ixDstEnd- = do let ixDstEnd' = VM.length vecDst * 2 - 1- vecDst' <- VM.grow vecDst (ixDstEnd + 1)- fillChunk (ixSrc + 1) ixSrcEnd vecDst' (ixDst + 1) ixDstEnd'-- -- We've got a maching element, so add it to the chunk.- | match ixSrc- = do VM.unsafeWrite vecDst ixDst (produce ixSrc)- fillChunk (ixSrc + 1) ixSrcEnd vecDst (ixDst + 1) ixDstEnd-- -- The element doesnt match, so keep going.- | otherwise- = fillChunk (ixSrc + 1) ixSrcEnd vecDst ixDst ixDstEnd-
Data/Array/Repa/Operators/IndexSpace.hs view
@@ -1,4 +1,3 @@-{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE TypeOperators, ExplicitForAll, FlexibleContexts #-} module Data.Array.Repa.Operators.IndexSpace@@ -7,61 +6,49 @@ , transpose , extend , slice- , backpermute- , backpermuteDft)+ , backpermute, unsafeBackpermute+ , backpermuteDft, unsafeBackpermuteDft) where import Data.Array.Repa.Index import Data.Array.Repa.Slice-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Base-import Data.Array.Repa.Operators.Traverse+import Data.Array.Repa.Base+import Data.Array.Repa.Repr.Delayed+import Data.Array.Repa.Operators.Traversal import Data.Array.Repa.Shape as S import Prelude hiding ((++)) import qualified Prelude as P stage = "Data.Array.Repa.Operators.IndexSpace" --- Index space transformations --------------------------------------------------------------------+-- Index space transformations ------------------------------------------------ -- | Impose a new shape on the elements of an array. -- The new extent must be the same size as the original, else `error`.------ TODO: This only works for arrays with a single region.----reshape :: (Shape sh, Shape sh', Elt a)- => sh'- -> Array sh a- -> Array sh' a--{-# INLINE reshape #-}-reshape sh' arr- | not $ S.size sh' == S.size (extent arr)- = error $ stage P.++ ".reshape: reshaped array will not match size of the original"--reshape sh' (Array sh [Region RangeAll gen])- = Array sh' [Region RangeAll gen']- where gen' = case gen of- GenManifest vec- -> GenManifest vec-- GenCursor makeCursor _ loadElem- -> GenCursor- id- addDim- (loadElem . makeCursor . fromIndex sh . toIndex sh')+reshape :: (Shape sh2, Shape sh1+ , Repr r1 e)+ => sh2+ -> Array r1 sh1 e+ -> Array D sh2 e -reshape _ _- = error $ stage P.++ ".reshape: can't reshape a partitioned array"+{-# INLINE [3] reshape #-}+reshape sh2 arr+ | not $ S.size sh2 == S.size (extent arr)+ = error + $ stage P.++ ".reshape: reshaped array will not match size of the original" +reshape sh2 arr+ = fromFunction sh2 + $ unsafeIndex arr . fromIndex (extent arr) . toIndex sh2+ -- | Append two arrays.--- append, (++)- :: (Shape sh, Elt a)- => Array (sh :. Int) a- -> Array (sh :. Int) a- -> Array (sh :. Int) a+ :: ( Shape sh+ , Repr r1 e, Repr r2 e)+ => Array r1 (sh :. Int) e+ -> Array r2 (sh :. Int) e+ -> Array D (sh :. Int) e -{-# INLINE append #-}+{-# INLINE [3] append #-} append arr1 arr2 = unsafeTraverse2 arr1 arr2 fnExtent fnElem where@@ -81,11 +68,12 @@ -- | Transpose the lowest two dimensions of an array. -- Transposing an array twice yields the original. transpose- :: (Shape sh, Elt a)- => Array (sh :. Int :. Int) a- -> Array (sh :. Int :. Int) a+ :: ( Shape sh+ , Repr r e)+ => Array r (sh :. Int :. Int) e+ -> Array D (sh :. Int :. Int) e -{-# INLINE transpose #-}+{-# INLINE [3] transpose #-} transpose arr = unsafeTraverse arr (\(sh :. m :. n) -> (sh :. n :.m))@@ -93,19 +81,18 @@ -- | Extend an array, according to a given slice specification.--- (used to be called replicate). extend :: ( Slice sl , Shape (FullShape sl) , Shape (SliceShape sl)- , Elt e)+ , Repr r e) => sl- -> Array (SliceShape sl) e- -> Array (FullShape sl) e+ -> Array r (SliceShape sl) e+ -> Array D (FullShape sl) e -{-# INLINE extend #-}+{-# INLINE [3] extend #-} extend sl arr- = backpermute+ = unsafeBackpermute (fullOfSlice sl (extent arr)) (sliceOfFull sl) arr@@ -114,14 +101,14 @@ slice :: ( Slice sl , Shape (FullShape sl) , Shape (SliceShape sl)- , Elt e)- => Array (FullShape sl) e+ , Repr r e)+ => Array r (FullShape sl) e -> sl- -> Array (SliceShape sl) e+ -> Array D (SliceShape sl) e -{-# INLINE slice #-}+{-# INLINE [3] slice #-} slice arr sl- = backpermute+ = unsafeBackpermute (sliceOfFull sl (extent arr)) (fullOfSlice sl) arr@@ -129,37 +116,51 @@ -- | Backwards permutation of an array's elements. -- The result array has the same extent as the original.-backpermute- :: forall sh sh' a- . (Shape sh, Shape sh', Elt a)- => sh' -- ^ Extent of result array.- -> (sh' -> sh) -- ^ Function mapping each index in the result array- -- to an index of the source array.- -> Array sh a -- ^ Source array.- -> Array sh' a+backpermute, unsafeBackpermute+ :: forall r sh1 sh2 e+ . ( Shape sh1, Shape sh2+ , Repr r e)+ => sh2 -- ^ Extent of result array.+ -> (sh2 -> sh1) -- ^ Function mapping each index in the result array+ -- to an index of the source array.+ -> Array r sh1 e -- ^ Source array.+ -> Array D sh2 e -{-# INLINE backpermute #-}+{-# INLINE [3] backpermute #-} backpermute newExtent perm arr = traverse arr (const newExtent) (. perm) +{-# INLINE [3] unsafeBackpermute #-}+unsafeBackpermute newExtent perm arr+ = unsafeTraverse arr (const newExtent) (. perm) + -- | Default backwards permutation of an array's elements. -- If the function returns `Nothing` then the value at that index is taken -- from the default array (@arrDft@)-backpermuteDft- :: forall sh sh' a- . (Shape sh, Shape sh', Elt a)- => Array sh' a -- ^ Default values (@arrDft@)- -> (sh' -> Maybe sh) -- ^ Function mapping each index in the result array- -- to an index in the source array.- -> Array sh a -- ^ Source array.- -> Array sh' a+backpermuteDft, unsafeBackpermuteDft+ :: forall r0 r1 sh1 sh2 e+ . ( Shape sh1, Shape sh2+ , Repr r0 e, Repr r1 e)+ => Array r0 sh2 e -- ^ Default values (@arrDft@)+ -> (sh2 -> Maybe sh1) -- ^ Function mapping each index in the result array+ -- to an index in the source array.+ -> Array r1 sh1 e -- ^ Source array.+ -> Array D sh2 e -{-# INLINE backpermuteDft #-}+{-# INLINE [3] backpermuteDft #-} backpermuteDft arrDft fnIndex arrSrc = fromFunction (extent arrDft) fnElem where fnElem ix = case fnIndex ix of- Just ix' -> arrSrc ! ix'- Nothing -> arrDft ! ix+ Just ix' -> arrSrc `index` ix'+ Nothing -> arrDft `index` ix++{-# INLINE [3] unsafeBackpermuteDft #-}+unsafeBackpermuteDft arrDft fnIndex arrSrc+ = fromFunction (extent arrDft) fnElem+ where fnElem ix+ = case fnIndex ix of+ Just ix' -> arrSrc `unsafeIndex` ix'+ Nothing -> arrDft `unsafeIndex` ix
Data/Array/Repa/Operators/Interleave.hs view
@@ -1,5 +1,4 @@-{-# OPTIONS_HADDOCK hide #-}-{-# LANGUAGE TypeOperators, PatternGuards #-}+{-# LANGUAGE TypeOperators, ExplicitForAll, FlexibleContexts #-} module Data.Array.Repa.Operators.Interleave ( interleave2@@ -7,11 +6,13 @@ , interleave4) where import Data.Array.Repa.Index-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Base-import Data.Array.Repa.Operators.Traverse-import Data.Array.Repa.Shape as S+import Data.Array.Repa.Base+import Data.Array.Repa.Repr.Delayed+import Data.Array.Repa.Operators.Traversal+import Data.Array.Repa.Shape as S+import Prelude hiding ((++)) +-- Interleave ----------------------------------------------------------------- -- | Interleave the elements of two arrays. -- All the input arrays must have the same extent, else `error`. -- The lowest dimension of the result array is twice the size of the inputs.@@ -22,12 +23,13 @@ -- @ -- interleave2- :: (Shape sh, Elt a)- => Array (sh :. Int) a- -> Array (sh :. Int) a- -> Array (sh :. Int) a+ :: (Shape sh+ , Repr r1 a, Repr r2 a)+ => Array r1 (sh :. Int) a+ -> Array r2 (sh :. Int) a+ -> Array D (sh :. Int) a -{-# INLINE interleave2 #-}+{-# INLINE [3] interleave2 #-} interleave2 arr1 arr2 = arr1 `deepSeqArray` arr2 `deepSeqArray` unsafeTraverse2 arr1 arr2 shapeFn elemFn@@ -49,13 +51,14 @@ -- | Interleave the elements of three arrays. interleave3- :: (Shape sh, Elt a)- => Array (sh :. Int) a- -> Array (sh :. Int) a- -> Array (sh :. Int) a- -> Array (sh :. Int) a+ :: ( Shape sh+ , Repr r1 a, Repr r2 a, Repr r3 a)+ => Array r1 (sh :. Int) a+ -> Array r2 (sh :. Int) a+ -> Array r3 (sh :. Int) a+ -> Array D (sh :. Int) a -{-# INLINE interleave3 #-}+{-# INLINE [3] interleave3 #-} interleave3 arr1 arr2 arr3 = arr1 `deepSeqArray` arr2 `deepSeqArray` arr3 `deepSeqArray` unsafeTraverse3 arr1 arr2 arr3 shapeFn elemFn@@ -79,14 +82,15 @@ -- | Interleave the elements of four arrays. interleave4- :: (Shape sh, Elt a)- => Array (sh :. Int) a- -> Array (sh :. Int) a- -> Array (sh :. Int) a- -> Array (sh :. Int) a- -> Array (sh :. Int) a+ :: ( Shape sh+ , Repr r1 a, Repr r2 a, Repr r3 a, Repr r4 a)+ => Array r1 (sh :. Int) a+ -> Array r2 (sh :. Int) a+ -> Array r3 (sh :. Int) a+ -> Array r4 (sh :. Int) a+ -> Array D (sh :. Int) a -{-# INLINE interleave4 #-}+{-# INLINE [3] interleave4 #-} interleave4 arr1 arr2 arr3 arr4 = arr1 `deepSeqArray` arr2 `deepSeqArray` arr3 `deepSeqArray` arr4 `deepSeqArray` unsafeTraverse4 arr1 arr2 arr3 arr4 shapeFn elemFn@@ -108,4 +112,3 @@ 2 -> get3 (sh :. ix `div` 4) 3 -> get4 (sh :. ix `div` 4) _ -> error "Data.Array.Repa.interleave4: this never happens :-P"-
Data/Array/Repa/Operators/Mapping.hs view
@@ -1,98 +1,57 @@-{-# OPTIONS_HADDOCK hide #-}-{-# LANGUAGE NoMonomorphismRestriction, PatternGuards #-}+{-# LANGUAGE FunctionalDependencies, UndecidableInstances #-} module Data.Array.Repa.Operators.Mapping- ( map- , zipWith- , (+^)- , (-^)- , (*^)- , (/^))+ ( -- * Generic maps+ map+ , zipWith+ , (+^), (-^), (*^), (/^)++ -- * Combining maps+ , Combine(..)) where-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Base-import Data.Array.Repa.Shape as S-import qualified Data.Vector.Unboxed as V-import qualified Prelude as P-import Prelude (($), (.), (+), (*), (+), (/), (-))+import Data.Array.Repa.Shape+import Data.Array.Repa.Base+import Data.Array.Repa.Repr.ByteString+import Data.Array.Repa.Repr.Cursored+import Data.Array.Repa.Repr.Delayed+import Data.Array.Repa.Repr.ForeignPtr+import Data.Array.Repa.Repr.Partitioned+import Data.Array.Repa.Repr.Unboxed+import Data.Array.Repa.Repr.Undefined+import Prelude hiding (map, zipWith)+import Foreign.Storable+import Data.Word --- | Apply a worker function to each element of an array, yielding a new array with the same extent.------ This is specialised for arrays of up to four regions, using more breaks fusion.+-- | Apply a worker function to each element of an array, +-- yielding a new array with the same extent. ---map :: (Shape sh, Elt a, Elt b)- => (a -> b)- -> Array sh a- -> Array sh b--{-# INLINE map #-}-map f (Array sh regions)- = Array sh (mapRegions regions)-- where {-# INLINE mapRegions #-}- mapRegions rs- = case rs of- [] -> []- [r] -> [mapRegion r]- [r1, r2] -> [mapRegion r1, mapRegion r2]- [r1, r2, r3] -> [mapRegion r1, mapRegion r2, mapRegion r3]- [r1, r2, r3, r4] -> [mapRegion r1, mapRegion r2, mapRegion r3, mapRegion r4]- _ -> mapRegions' rs-- mapRegions' rs- = case rs of- [] -> []- (r : rs') -> mapRegion r : mapRegions' rs'-- {-# INLINE mapRegion #-}- mapRegion (Region range gen)- = Region range (mapGen gen)-- {-# INLINE mapGen #-}- mapGen gen- = case gen of- GenManifest vec- -> GenCursor- P.id- addDim- (\ix -> f $ V.unsafeIndex vec $ S.toIndex sh ix)-- GenCursor makeCursor shiftCursor loadElem- -> GenCursor makeCursor shiftCursor (f . loadElem)+map :: (Shape sh, Repr r a)+ => (a -> b) -> Array r sh a -> Array D sh b+{-# INLINE [4] map #-}+map f arr+ = case delay arr of+ ADelayed sh g -> ADelayed sh (f . g) +-- ZipWith -------------------------------------------------------------------- -- | Combine two arrays, element-wise, with a binary operator. -- If the extent of the two array arguments differ, -- then the resulting array's extent is their intersection. ---zipWith :: (Shape sh, Elt a, Elt b, Elt c)- => (a -> b -> c)- -> Array sh a- -> Array sh b- -> Array sh c--{-# INLINE zipWith #-}+zipWith :: (Shape sh, Repr r1 a, Repr r2 b)+ => (a -> b -> c)+ -> Array r1 sh a -> Array r2 sh b+ -> Array D sh c+{-# INLINE [3] zipWith #-} zipWith f arr1 arr2- | Array sh2 [_] <- arr1- , Array sh1 [ Region g21 (GenCursor make21 _ load21)- , Region g22 (GenCursor make22 _ load22)] <- arr2-- = let {-# INLINE load21' #-}- load21' ix = f (arr1 `unsafeIndex` ix) (load21 $ make21 ix)-- {-# INLINE load22' #-}- load22' ix = f (arr1 `unsafeIndex` ix) (load22 $ make22 ix)-- in Array (S.intersectDim sh1 sh2)- [ Region g21 (GenCursor P.id addDim load21')- , Region g22 (GenCursor P.id addDim load22') ]+ = arr1 `deepSeqArray` arr2 `deepSeqArray`+ let + {-# INLINE get #-}+ get ix = f (arr1 `unsafeIndex` ix) (arr2 `unsafeIndex` ix) - | P.otherwise- = let {-# INLINE getElem' #-}- getElem' ix = f (arr1 `unsafeIndex` ix) (arr2 `unsafeIndex` ix)- in fromFunction- (S.intersectDim (extent arr1) (extent arr2))- getElem'+ in fromFunction + (intersectDim (extent arr1) (extent arr2)) + get {-# INLINE (+^) #-}@@ -107,3 +66,109 @@ {-# INLINE (/^) #-} (/^) = zipWith (/) +++-- Combine --------------------------------------------------------------------+-- | Combining versions of @map@ and @zipWith@ that preserve the representation+-- of cursored and partitioned arrays. +--+-- For cursored (@C@) arrays, the cursoring of the source array is preserved.+--+-- For partitioned (@P@) arrays, the worker function is fused with each array+-- partition separately, instead of treating the whole array as a single+-- bulk object. +--+-- Preserving the cursored and\/or paritioned representation of an array +-- is will make follow-on computation more efficient than if the array was+-- converted to a vanilla Delayed (@D@) array as with plain `map` and `zipWith`.+--+-- If the source array is not cursored or partitioned then `cmap` and +-- `czipWith` are identical to the plain functions.+--+class Combine r1 a r2 b | r1 -> r2 where++ -- | Combining @map@.+ cmap :: Shape sh + => (a -> b) + -> Array r1 sh a + -> Array r2 sh b++ -- | Combining @zipWith@.+ -- If you have a cursored or partitioned source array then use that as+ -- the third argument (corresponding to @r1@ here)+ czipWith+ :: (Shape sh, Repr r c)+ => (c -> a -> b)+ -> Array r sh c+ -> Array r1 sh a+ -> Array r2 sh b+++-- ByteString -------------------------+instance Combine B Word8 D b where+ cmap = map+ czipWith = zipWith+++-- Cursored ---------------------------+instance Combine C a C b where+ {-# INLINE [4] cmap #-}+ cmap f (ACursored sh makec shiftc loadc)+ = ACursored sh makec shiftc (f . loadc)++ {-# INLINE [3] czipWith #-}+ czipWith f arr1 (ACursored sh makec shiftc loadc)+ = let {-# INLINE makec' #-}+ makec' ix = (ix, makec ix)++ {-# INLINE shiftc' #-}+ shiftc' off (ix, cur) = (addDim off ix, shiftc off cur)++ {-# INLINE load' #-}+ load' (ix, cur) = f (arr1 `unsafeIndex` ix) (loadc cur)++ in ACursored + (intersectDim (extent arr1) sh)+ makec' shiftc' load'+++-- Delayed ----------------------------+instance Combine D a D b where+ cmap = map+ czipWith = zipWith+++-- ForeignPtr -------------------------+instance Storable a => Combine F a D b where+ cmap = map+ czipWith = zipWith+++-- Partitioned ------------------------+instance (Combine r11 a r21 b+ , Combine r12 a r22 b)+ => Combine (P r11 r12) a (P r21 r22) b where++ {-# INLINE [4] cmap #-}+ cmap f (APart sh range arr1 arr2)+ = APart sh range (cmap f arr1) (cmap f arr2)++ {-# INLINE [3] czipWith #-}+ czipWith f arr1 (APart sh range arr21 arr22)+ = APart sh range (czipWith f arr1 arr21)+ (czipWith f arr1 arr22)+++-- Unboxed ----------------------------+instance Unbox a => Combine U a D b where+ cmap = map+ czipWith = zipWith+++-- Undefined --------------------------+instance Combine X a D b where+ cmap = map+ czipWith = zipWith+++
− Data/Array/Repa/Operators/Modify.hs
@@ -1,53 +0,0 @@-{-# OPTIONS_HADDOCK hide #-}--module Data.Array.Repa.Operators.Modify - ( -- * Bulk updates- (//))-where-import Data.Array.Repa.Shape-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Base--{--stage :: String-stage = "Data.Array.Repa.Operators.Modify"--}---- Bulk updates ------------------------------------------------------------------- | For each pair @(sh, a)@ from the list of index/value pairs, replace the--- element at position @sh@ by @a@.------ > update <5,9,2,7> [(2,1),(0,3),(2,8)] = <3,9,8,7>----{-# INLINE (//) #-}-(//) :: (Shape sh, Elt a) => Array sh a -> [(sh,a)] -> Array sh a-(//) arr us - = fromFunction- (extent arr) - (\sh -> case lookup sh us of- Just a -> a- Nothing -> index arr sh)--{---- For each pair @(sh, a)@ from the array of index/value pairs, replace the--- element at position @sh@ by @a@.------ > update <5,9,2,7> <(2,1),(0,3),(2,8)> = <3,9,8,7>----{-# INLINE update #-}-update :: Shape sh- => Array sh a -- ^ initial array- -> Array sh (sh, a) -- ^ array of shape/value pairs- -> Array sh a-update _arr _us = error $ stage ++ ".update: not defined yet"----- Same as 'update', but without bounds checks----{-# INLINE unsafeUpdate #-}-unsafeUpdate :: Shape sh- => Array sh a- -> Array sh (sh, a)- -> Array sh a-unsafeUpdate _arr _us = error $ stage ++ ".unsafeUpdate: not defined yet"--}
Data/Array/Repa/Operators/Reduction.hs view
@@ -1,82 +1,141 @@-{-# OPTIONS_HADDOCK hide #-}-{-# LANGUAGE BangPatterns, ExplicitForAll, TypeOperators #-}+{-# LANGUAGE BangPatterns, ExplicitForAll, TypeOperators, MagicHash #-} module Data.Array.Repa.Operators.Reduction- ( fold, foldAll- , sum, sumAll)+ ( foldS, foldP+ , foldAllS, foldAllP+ , sumS, sumP+ , sumAllS, sumAllP) where+import Data.Array.Repa.Base import Data.Array.Repa.Index-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Base+import Data.Array.Repa.Eval.Elt+import Data.Array.Repa.Repr.Unboxed import Data.Array.Repa.Shape as S import qualified Data.Vector.Unboxed as V import qualified Data.Vector.Unboxed.Mutable as M import Prelude hiding (sum)--import Data.Array.Repa.Internals.EvalReduction+import qualified Data.Array.Repa.Eval.Reduction as E import System.IO.Unsafe+import GHC.Exts +-- foldS ----------------------------------------------------------------------+-- | Sequential reduction of the innermost dimension of an arbitrary rank array.+--+-- Combine this with `transpose` to fold any other dimension.+foldS :: (Shape sh, Elt a, Unbox a, Repr r a)+ => (a -> a -> a)+ -> a+ -> Array r (sh :. Int) a+ -> Array U sh a+{-# INLINE [2] foldS #-}+foldS f z arr+ = let sh@(sz :. n') = extent arr+ !(I# n) = n'+ in unsafePerformIO+ $ do mvec <- M.unsafeNew (S.size sz)+ E.foldS mvec (\ix -> arr `unsafeIndex` fromIndex sh (I# ix)) f z n+ !vec <- V.unsafeFreeze mvec+ return $ fromUnboxed sz vec --- | Reduction of the innermost dimension of an arbitrary rank array. The first--- argument needs to be an /associative/ operator. The starting element must--- be neutral with respect to the operator, for example @0@ is neutral with--- respect to @(+)@ as @0 + a = a@. These restrictions are required to support--- parallel evaluation, as the starting element may be used multiple--- times depending on the number of threads. --- Combine this with `transpose` to fold any other dimension.-fold :: (Shape sh, Elt a)+-- | Parallel reduction of the innermost dimension of an arbitray rank array.+--+-- The first argument needs to be an associative sequential operator.+-- The starting element must be neutral with respect to the operator, for+-- example @0@ is neutral with respect to @(+)@ as @0 + a = a@.+-- These restrictions are required to support parallel evaluation, as the+-- starting element may be used multiple times depending on the number of threads.+foldP :: (Shape sh, Elt a, Unbox a, Repr r a) => (a -> a -> a) -> a- -> Array (sh :. Int) a- -> Array sh a-{-# INLINE [1] fold #-}-fold f z arr + -> Array r (sh :. Int) a+ -> Array U sh a+{-# INLINE [2] foldP #-}+foldP f z arr = let sh@(sz :. n) = extent arr in case rank sh of- -- specialise rank-1 arrays, else one thread does all the work. We can't- -- match against the shape constructor, otherwise type error: (sz ~ Z)+ -- specialise rank-1 arrays, else one thread does all the work.+ -- We can't match against the shape constructor,+ -- otherwise type error: (sz ~ Z) --- 1 -> let !x = V.singleton $ foldAll f z arr- in Array sz [Region RangeAll (GenManifest x)]+ 1 -> let !vec = V.singleton $ foldAllP f z arr+ in fromUnboxed sz vec _ -> unsafePerformIO $ do mvec <- M.unsafeNew (S.size sz)- foldP mvec (\ix -> arr `unsafeIndex` fromIndex sh ix) f z n+ E.foldP mvec (\ix -> arr `unsafeIndex` fromIndex sh ix) f z n !vec <- V.unsafeFreeze mvec- return $ Array sz [Region RangeAll (GenManifest vec)]+ return $ fromUnboxed sz vec --- | Reduction of an array of arbitrary rank to a single scalar value. The first--- argument needs to be an /associative/ operator. The starting element must--- be neutral with respect to the operator, for example @0@ is neutral with--- respect to @(+)@ as @0 + a = a@. These restrictions are required to support--- parallel evaluation, as the starting element may be used multiple--- times depending on the number of threads.-foldAll :: (Shape sh, Elt a)+-- foldAll --------------------------------------------------------------------+-- | Sequential reduction of an array of arbitrary rank to a single scalar value.+--+foldAllS :: (Shape sh, Elt a, Unbox a, Repr r a) => (a -> a -> a) -> a- -> Array sh a+ -> Array r sh a -> a-{-# INLINE [1] foldAll #-}-foldAll f z arr +{-# INLINE [2] foldAllS #-}+foldAllS f z arr + = arr `deepSeqArray`+ let !ex = extent arr+ !(I# n) = size ex+ in E.foldAllS + (\ix -> arr `unsafeIndex` fromIndex ex (I# ix))+ f z n +++-- | Parallel reduction of an array of arbitrary rank to a single scalar value.+--+-- The first argument needs to be an associative sequential operator.+-- The starting element must be neutral with respect to the operator,+-- for example @0@ is neutral with respect to @(+)@ as @0 + a = a@.+-- These restrictions are required to support parallel evaluation, as the+-- starting element may be used multiple times depending on the number of threads.+foldAllP :: (Shape sh, Elt a, Unbox a, Repr r a)+ => (a -> a -> a)+ -> a+ -> Array r sh a+ -> a+{-# INLINE [2] foldAllP #-}+foldAllP f z arr = let sh = extent arr n = size sh- in unsafePerformIO $ foldAllP (\ix -> arr `unsafeIndex` fromIndex sh ix) f z n+ in unsafePerformIO + $ E.foldAllP (\ix -> arr `unsafeIndex` fromIndex sh ix) f z n --- | Sum the innermost dimension of an array.-sum :: (Shape sh, Elt a, Num a)- => Array (sh :. Int) a- -> Array sh a-{-# INLINE sum #-}-sum arr = fold (+) 0 arr+-- sum ------------------------------------------------------------------------+-- | Sequential sum the innermost dimension of an array.+sumS :: (Shape sh, Num a, Elt a, Unbox a, Repr r a)+ => Array r (sh :. Int) a+ -> Array U sh a+{-# INLINE [4] sumS #-}+sumS = foldS (+) 0 --- | Sum all the elements of an array.-sumAll :: (Shape sh, Elt a, Num a)- => Array sh a+-- | Sequential sum the innermost dimension of an array.+sumP :: (Shape sh, Num a, Elt a, Unbox a, Repr r a)+ => Array r (sh :. Int) a+ -> Array U sh a+{-# INLINE [4] sumP #-}+sumP = foldP (+) 0+++-- sumAll ---------------------------------------------------------------------+-- | Sequential sum of all the elements of an array.+sumAllS :: (Shape sh, Elt a, Unbox a, Num a, Repr r a)+ => Array r sh a -> a-{-# INLINE sumAll #-}-sumAll arr = foldAll (+) 0 arr+{-# INLINE [4] sumAllS #-}+sumAllS = foldAllS (+) 0+++-- | Parallel sum all the elements of an array.+sumAllP :: (Shape sh, Elt a, Unbox a, Num a, Repr r a)+ => Array r sh a+ -> a+{-# INLINE [4] sumAllP #-}+sumAllP = foldAllP (+) 0
− Data/Array/Repa/Operators/Select.hs
@@ -1,44 +0,0 @@-{-# OPTIONS_HADDOCK hide #-}-{-# LANGUAGE BangPatterns #-}--module Data.Array.Repa.Operators.Select- (select)-where-import Data.Array.Repa.Index-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Base-import Data.Array.Repa.Internals.Select-import qualified Data.Vector.Unboxed as V-import System.IO.Unsafe----- | Produce an array by applying a predicate to a range of integers.--- If the predicate matches, then use the second function to generate--- the element.------ This is a low-level function helpful for writing filtering operations on arrays.--- Use the integer as the index into the array you're filtering.----select :: Elt a- => (Int -> Bool) -- ^ If the Int matches this predicate,- -> (Int -> a) -- ^ ... then pass it to this fn to produce a value- -> Int -- ^ Range between 0 and this maximum.- -> Array DIM1 a -- ^ Array containing produced values.--{-# INLINE select #-}-select match produce len- = unsafePerformIO- $ do (sh, vec) <- selectIO- return $ sh `seq` vec `seq`- Array sh [Region RangeAll (GenManifest vec)]-- where {-# INLINE selectIO #-}- selectIO- = do vecs <- selectChunkedP match produce len- vecs' <- mapM V.unsafeFreeze vecs-- -- TODO: avoid copy.- let result = V.concat vecs'-- return (Z :. V.length result, result)-
+ Data/Array/Repa/Operators/Selection.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE BangPatterns #-}+module Data.Array.Repa.Operators.Selection+ (select)+where+import Data.Array.Repa.Index+import Data.Array.Repa.Base+import Data.Array.Repa.Eval.Selection+import Data.Array.Repa.Repr.Unboxed as U+import qualified Data.Vector.Unboxed as V+import System.IO.Unsafe+++-- | Produce an array by applying a predicate to a range of integers.+-- If the predicate matches, then use the second function to generate+-- the element.+--+-- * This is a low-level function helpful for writing filtering+-- operations on arrays.+--+-- * Use the integer as the index into the array you're filtering.+--+select :: Unbox a+ => (Int -> Bool) -- ^ If the Int matches this predicate,+ -> (Int -> a) -- ^ ... then pass it to this fn to produce a value+ -> Int -- ^ Range between 0 and this maximum.+ -> Array U DIM1 a -- ^ Array containing produced values.++{-# INLINE [2] select #-}+select match produce len+ = unsafePerformIO+ $ do (sh, vec) <- selectIO+ return $ sh `seq` vec `seq`+ fromUnboxed sh vec++ where {-# INLINE selectIO #-}+ selectIO+ = do vecs <- selectChunkedP match produce len+ vecs' <- mapM V.unsafeFreeze vecs++ -- TODO: avoid copy somehow.+ let result = V.concat vecs'++ return (Z :. V.length result, result)
+ Data/Array/Repa/Operators/Traversal.hs view
@@ -0,0 +1,120 @@+-- Generic Traversal+module Data.Array.Repa.Operators.Traversal+ ( traverse, unsafeTraverse+ , traverse2, unsafeTraverse2+ , traverse3, unsafeTraverse3+ , traverse4, unsafeTraverse4)+where+import Data.Array.Repa.Base+import Data.Array.Repa.Shape+import Data.Array.Repa.Repr.Delayed+++-- | Unstructured traversal.+traverse, unsafeTraverse+ :: forall r sh sh' a b+ . (Shape sh, Shape sh', Repr r a)+ => Array r sh a -- ^ Source array.+ -> (sh -> sh') -- ^ Function to produce the extent of the result.+ -> ((sh -> a) -> sh' -> b) -- ^ Function to produce elements of the result.+ -- It is passed a lookup function to get elements of the source.+ -> Array D sh' b++{-# INLINE [4] traverse #-}+traverse arr transExtent newElem+ = arr `deepSeqArray` + fromFunction (transExtent (extent arr)) (newElem (index arr))++{-# INLINE [4] unsafeTraverse #-}+unsafeTraverse arr transExtent newElem+ = arr `deepSeqArray`+ fromFunction (transExtent (extent arr)) (newElem (unsafeIndex arr))+++-- | Unstructured traversal over two arrays at once.+traverse2, unsafeTraverse2+ :: forall r1 r2 sh sh' sh'' a b c+ . ( Shape sh, Shape sh', Shape sh''+ , Repr r1 a, Repr r2 b)+ => Array r1 sh a -- ^ First source array.+ -> Array r2 sh' b -- ^ Second source array.+ -> (sh -> sh' -> sh'') -- ^ Function to produce the extent of the result.+ -> ((sh -> a) -> (sh' -> b)+ -> (sh'' -> c)) -- ^ Function to produce elements of the result.+ -- It is passed lookup functions to get elements of the+ -- source arrays.+ -> Array D sh'' c++{-# INLINE [4] traverse2 #-}+traverse2 arrA arrB transExtent newElem+ = arrA `deepSeqArray` arrB `deepSeqArray`+ fromFunction (transExtent (extent arrA) (extent arrB))+ (newElem (index arrA) (index arrB))++{-# INLINE [4] unsafeTraverse2 #-}+unsafeTraverse2 arrA arrB transExtent newElem+ = arrA `deepSeqArray` arrB `deepSeqArray`+ fromFunction (transExtent (extent arrA) (extent arrB))+ (newElem (unsafeIndex arrA) (unsafeIndex arrB))+++-- | Unstructured traversal over three arrays at once.+traverse3, unsafeTraverse3+ :: forall r1 r2 r3+ sh1 sh2 sh3 sh4+ a b c d+ . ( Shape sh1, Shape sh2, Shape sh3, Shape sh4+ , Repr r1 a, Repr r2 b, Repr r3 c)+ => Array r1 sh1 a+ -> Array r2 sh2 b+ -> Array r3 sh3 c+ -> (sh1 -> sh2 -> sh3 -> sh4)+ -> ( (sh1 -> a) -> (sh2 -> b)+ -> (sh3 -> c)+ -> sh4 -> d )+ -> Array D sh4 d++{-# INLINE [4] traverse3 #-}+traverse3 arrA arrB arrC transExtent newElem+ = arrA `deepSeqArray` arrB `deepSeqArray` arrC `deepSeqArray`+ fromFunction (transExtent (extent arrA) (extent arrB) (extent arrC))+ (newElem (index arrA) (index arrB) (index arrC))++{-# INLINE [4] unsafeTraverse3 #-}+unsafeTraverse3 arrA arrB arrC transExtent newElem+ = arrA `deepSeqArray` arrB `deepSeqArray` arrC `deepSeqArray`+ fromFunction (transExtent (extent arrA) (extent arrB) (extent arrC))+ (newElem (unsafeIndex arrA) (unsafeIndex arrB) (unsafeIndex arrC))+++-- | Unstructured traversal over four arrays at once.+traverse4, unsafeTraverse4+ :: forall r1 r2 r3 r4+ sh1 sh2 sh3 sh4 sh5+ a b c d e+ . ( Shape sh1, Shape sh2, Shape sh3, Shape sh4, Shape sh5+ , Repr r1 a, Repr r2 b, Repr r3 c, Repr r4 d)+ => Array r1 sh1 a+ -> Array r2 sh2 b+ -> Array r3 sh3 c+ -> Array r4 sh4 d+ -> (sh1 -> sh2 -> sh3 -> sh4 -> sh5 )+ -> ( (sh1 -> a) -> (sh2 -> b)+ -> (sh3 -> c) -> (sh4 -> d)+ -> sh5 -> e )+ -> Array D sh5 e++{-# INLINE [4] traverse4 #-}+traverse4 arrA arrB arrC arrD transExtent newElem+ = arrA `deepSeqArray` arrB `deepSeqArray` arrC `deepSeqArray` arrD `deepSeqArray`+ fromFunction (transExtent (extent arrA) (extent arrB) (extent arrC) (extent arrD))+ (newElem (index arrA) (index arrB) (index arrC) (index arrD))+++{-# INLINE [4] unsafeTraverse4 #-}+unsafeTraverse4 arrA arrB arrC arrD transExtent newElem+ = arrA `deepSeqArray` arrB `deepSeqArray` arrC `deepSeqArray` arrD `deepSeqArray`+ fromFunction (transExtent (extent arrA) (extent arrB) (extent arrC) (extent arrD))+ (newElem (unsafeIndex arrA) (unsafeIndex arrB) (unsafeIndex arrC) (unsafeIndex arrD))++
− Data/Array/Repa/Operators/Traverse.hs
@@ -1,126 +0,0 @@-{-# OPTIONS_HADDOCK hide #-}-{-# LANGUAGE ExplicitForAll #-}--module Data.Array.Repa.Operators.Traverse- ( traverse, unsafeTraverse- , traverse2, unsafeTraverse2- , traverse3, unsafeTraverse3- , traverse4, unsafeTraverse4)-where-import Data.Array.Repa.Internals.Elt-import Data.Array.Repa.Internals.Base-import Data.Array.Repa.Shape as S---- Generic Traversal -------------------------------------------------------------------------------- | Unstructured traversal.-traverse- :: forall sh sh' a b- . (Shape sh, Shape sh', Elt a)- => Array sh a -- ^ Source array.- -> (sh -> sh') -- ^ Function to produce the extent of the result.- -> ((sh -> a) -> sh' -> b) -- ^ Function to produce elements of the result.- -- It is passed a lookup function to get elements of the source.- -> Array sh' b--{-# INLINE traverse #-}-traverse arr transExtent newElem- = arr `deepSeqArray`- fromFunction (transExtent (extent arr)) (newElem (arr !))---{-# INLINE unsafeTraverse #-}-unsafeTraverse arr transExtent newElem- = arr `deepSeqArray`- fromFunction (transExtent (extent arr)) (newElem (unsafeIndex arr))----- | Unstructured traversal over two arrays at once.-traverse2, unsafeTraverse2- :: forall sh sh' sh'' a b c- . ( Shape sh, Shape sh', Shape sh''- , Elt a, Elt b)- => Array sh a -- ^ First source array.- -> Array sh' b -- ^ Second source array.- -> (sh -> sh' -> sh'') -- ^ Function to produce the extent of the result.- -> ((sh -> a) -> (sh' -> b)- -> (sh'' -> c)) -- ^ Function to produce elements of the result.- -- It is passed lookup functions to get elements of the- -- source arrays.- -> Array sh'' c--{-# INLINE traverse2 #-}-traverse2 arrA arrB transExtent newElem- = arrA `deepSeqArray` arrB `deepSeqArray`- fromFunction- (transExtent (extent arrA) (extent arrB))- (newElem (arrA !) (arrB !))--{-# INLINE unsafeTraverse2 #-}-unsafeTraverse2 arrA arrB transExtent newElem- = arrA `deepSeqArray` arrB `deepSeqArray`- fromFunction- (transExtent (extent arrA) (extent arrB))- (newElem (unsafeIndex arrA) (unsafeIndex arrB))----- | Unstructured traversal over three arrays at once.-traverse3, unsafeTraverse3- :: forall sh1 sh2 sh3 sh4- a b c d- . ( Shape sh1, Shape sh2, Shape sh3, Shape sh4- , Elt a, Elt b, Elt c)- => Array sh1 a- -> Array sh2 b- -> Array sh3 c- -> (sh1 -> sh2 -> sh3 -> sh4)- -> ( (sh1 -> a) -> (sh2 -> b)- -> (sh3 -> c)- -> sh4 -> d )- -> Array sh4 d--{-# INLINE traverse3 #-}-traverse3 arrA arrB arrC transExtent newElem- = arrA `deepSeqArray` arrB `deepSeqArray` arrC `deepSeqArray`- fromFunction- (transExtent (extent arrA) (extent arrB) (extent arrC))- (newElem (arrA !) (arrB !) (arrC !))--{-# INLINE unsafeTraverse3 #-}-unsafeTraverse3 arrA arrB arrC transExtent newElem- = arrA `deepSeqArray` arrB `deepSeqArray` arrC `deepSeqArray`- fromFunction- (transExtent (extent arrA) (extent arrB) (extent arrC))- (newElem (unsafeIndex arrA) (unsafeIndex arrB) (unsafeIndex arrC))----- | Unstructured traversal over four arrays at once.-traverse4, unsafeTraverse4- :: forall sh1 sh2 sh3 sh4 sh5- a b c d e- . ( Shape sh1, Shape sh2, Shape sh3, Shape sh4, Shape sh5- , Elt a, Elt b, Elt c, Elt d)- => Array sh1 a- -> Array sh2 b- -> Array sh3 c- -> Array sh4 d- -> (sh1 -> sh2 -> sh3 -> sh4 -> sh5 )- -> ( (sh1 -> a) -> (sh2 -> b)- -> (sh3 -> c) -> (sh4 -> d)- -> sh5 -> e )- -> Array sh5 e--{-# INLINE traverse4 #-}-traverse4 arrA arrB arrC arrD transExtent newElem- = arrA `deepSeqArray` arrB `deepSeqArray` arrC `deepSeqArray` arrD `deepSeqArray`- fromFunction- (transExtent (extent arrA) (extent arrB) (extent arrC) (extent arrD))- (newElem (arrA !) (arrB !) (arrC !) (arrD !))---{-# INLINE unsafeTraverse4 #-}-unsafeTraverse4 arrA arrB arrC arrD transExtent newElem- = arrA `deepSeqArray` arrB `deepSeqArray` arrC `deepSeqArray` arrD `deepSeqArray`- fromFunction- (transExtent (extent arrA) (extent arrB) (extent arrC) (extent arrD))- (newElem (unsafeIndex arrA) (unsafeIndex arrB) (unsafeIndex arrC) (unsafeIndex arrD))-
− Data/Array/Repa/Properties.hs
@@ -1,115 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}--module Data.Array.Repa.Properties- ( props_DataArrayRepaIndex- , props_DataArrayRepa)-where-import Data.Array.Repa as R-import Data.Array.Repa.Arbitrary-import qualified Data.Array.Repa.Shape as S-import qualified Data.Vector.Unboxed as V-import Control.Monad-import Test.QuickCheck-import Prelude as P hiding (compare)--stage :: String-stage = "Data.Array.Repa.Properties"--compare :: (Eq a, Show a) => a -> a -> Property-compare ans ref = printTestCase message (ref == ans)- where- message = unlines ["*** Expected:", show ref- ,"*** Received:", show ans ]----- Data.Array.Repa.Index ----------------------------------------------------------------------------- | QuickCheck properties for "Data.Array.Repa.Index".-props_DataArrayRepaIndex :: [(String, Property)]-props_DataArrayRepaIndex- = [(stage P.++ "." P.++ name, test) | (name, test)- <- [ ("toIndexFromIndex/DIM1", property prop_toIndexFromIndex_DIM1)- , ("toIndexFromIndex/DIM2", property prop_toIndexFromIndex_DIM2) ]]--prop_toIndexFromIndex_DIM1 sh ix- = (sizeIsValid sh)- ==> (inShape sh ix)- ==> fromIndex sh (toIndex sh ix) `compare` (ix :: DIM1)--prop_toIndexFromIndex_DIM2- = forAll arbitraryShape $ \(sh :: DIM2) ->- forAll (genInShape2 sh) $ \(ix :: DIM2) ->- fromIndex sh (toIndex sh ix) `compare` ix------- Data.Array.Repa ----------------------------------------------------------------------------------- | QuickCheck properties for "Data.Array.Repa" and its children.-props_DataArrayRepa :: [(String, Property)]-props_DataArrayRepa- = props_DataArrayRepaIndex- P.++ [(stage P.++ "." P.++ name, test) | (name, test)- <- [ ("id_force/DIM5", property prop_id_force_DIM5)- , ("id_toScalarUnit", property prop_id_toScalarUnit)- , ("id_toListFromList/DIM3", property prop_id_toListFromList_DIM3)- , ("id_transpose/DIM4", property prop_id_transpose_DIM4)- , ("reshapeTransposeSize/DIM3", property prop_reshapeTranspose_DIM3)- , ("appendIsAppend/DIM3", property prop_appendIsAppend_DIM3)- , ("sumIsSum/DIM3", property prop_sumIsSum_DIM3)- , ("sumAllIsSum/DIM3", property prop_sumAllIsSum_DIM3) ]]----- The Eq instance uses fold and zipWith.-prop_id_force_DIM5- = forAll (arbitrarySmallArray 10) $ \(arr :: Array DIM5 Int) ->- force arr `compare` arr--prop_id_toScalarUnit (x :: Int)- = toScalar (singleton x) `compare` x---- Conversions -------------------------prop_id_toListFromList_DIM3- = forAll (arbitrarySmallShape 10) $ \(sh :: DIM3) ->- forAll (arbitraryListOfLength (S.size sh)) $ \(xx :: [Int]) ->- toList (fromList sh xx) `compare` xx---- Index Space Transforms --------------prop_id_transpose_DIM4- = forAll (arbitrarySmallArray 20) $ \(arr :: Array DIM3 Int) ->- transpose (transpose arr) `compare` arr---- A reshaped array has the same size and sum as the original-prop_reshapeTranspose_DIM3- = forAll (arbitrarySmallArray 20) $ \(arr :: Array DIM3 Int) ->- let arr' = transpose arr- sh' = extent arr'- in (S.size (extent (reshape sh' arr)) `compare` S.size (extent arr))- .&&. (sumAll arr' `compare` sumAll arr)--prop_appendIsAppend_DIM3- = forAll (arbitrarySmallArray 20) $ \(arr1 :: Array DIM3 Int) ->- sumAll (append arr1 arr1) `compare` (2 * sumAll arr1)---- Reductions ---------------------------prop_sumIsSum_DIM3- = forAll (arbitrarySmallArray 20) $ \(arr :: Array DIM3 Int) ->- let sh :. sz = extent arr- elemFn ix = V.foldl' (+) 0- $ V.map (\i -> arr ! (ix :. i))- (V.enumFromTo 0 (sz-1))- in- R.fold (+) 0 arr `compare` fromFunction sh elemFn--prop_sumAllIsSum_DIM3- = forAll (arbitrarySmallShape 20) $ \(sh :: DIM3) ->- forAll (arbitraryListOfLength (S.size sh)) $ \(xx :: [Int]) ->- sumAll (fromList sh xx) `compare` P.sum xx----- Utils -------------------------------------------------------------------------------------------genInShape2 :: DIM2 -> Gen DIM2-genInShape2 (Z :. yMax :. xMax)- = do y <- liftM (`mod` yMax) $ arbitrary- x <- liftM (`mod` xMax) $ arbitrary- return $ Z :. y :. x-
+ Data/Array/Repa/Repr/ByteString.hs view
@@ -0,0 +1,57 @@++module Data.Array.Repa.Repr.ByteString+ ( B, Array (..)+ , fromByteString, toByteString)+where+import Data.Array.Repa.Shape+import Data.Array.Repa.Base+import Data.Array.Repa.Repr.Delayed+import Data.Word+import qualified Data.ByteString as B+import qualified Data.ByteString.Unsafe as BU+import Data.ByteString (ByteString)+++-- | Strict ByteStrings arrays are represented as ForeignPtr buffers of Word8+data B+data instance Array B sh Word8+ = AByteString sh !ByteString+ +deriving instance Show sh+ => Show (Array B sh Word8)+++-- Repr -----------------------------------------------------------------------+-- | Read elements from a `ByteString`.+instance Repr B Word8 where+ {-# INLINE linearIndex #-}+ linearIndex (AByteString _ bs) ix+ = bs `B.index` ix++ {-# INLINE unsafeLinearIndex #-}+ unsafeLinearIndex (AByteString _ bs) ix+ = bs `BU.unsafeIndex` ix++ {-# INLINE extent #-}+ extent (AByteString sh _)+ = sh++ {-# INLINE deepSeqArray #-}+ deepSeqArray (AByteString sh bs) x + = sh `deepSeq` bs `seq` x+++-- Conversions ----------------------------------------------------------------+-- | O(1). Wrap a `ByteString` as an array.+fromByteString+ :: Shape sh+ => sh -> ByteString -> Array B sh Word8+{-# INLINE fromByteString #-}+fromByteString sh bs+ = AByteString sh bs+++-- | O(1). Unpack a `ByteString` from an array.+toByteString :: Array B sh Word8 -> ByteString+{-# INLINE toByteString #-}+toByteString (AByteString _ bs) = bs
+ Data/Array/Repa/Repr/Cursored.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE MagicHash #-}+module Data.Array.Repa.Repr.Cursored+ ( C, Array (..)+ , makeCursored)+where+import Data.Array.Repa.Base+import Data.Array.Repa.Shape+import Data.Array.Repa.Index+import Data.Array.Repa.Repr.Delayed+import Data.Array.Repa.Repr.Undefined+import Data.Array.Repa.Eval.Fill+import Data.Array.Repa.Eval.Elt+import Data.Array.Repa.Eval.Cursored+import GHC.Exts++-- | Cursored Arrays.+-- These are produced by Repa's stencil functions, and help the fusion+-- framework to share index compuations between array elements.+--+-- The basic idea is described in ``Efficient Parallel Stencil Convolution'',+-- Ben Lippmeier and Gabriele Keller, Haskell 2011 -- though the underlying+-- array representation has changed since this paper was published.+data C++data instance Array C sh e+ = forall cursor. ACursored+ { cursoredExtent :: sh + + -- | Make a cursor to a particular element.+ , makeCursor :: sh -> cursor++ -- | Shift the cursor by an offset, to get to another element.+ , shiftCursor :: sh -> cursor -> cursor++ -- | Load\/compute the element at the given cursor.+ , loadCursor :: cursor -> e }+++-- Repr -----------------------------------------------------------------------+-- | Compute elements of a cursored array.+instance Repr C a where+ {-# INLINE index #-}+ index (ACursored _ makec _ loadc)+ = loadc . makec++ {-# INLINE unsafeIndex #-}+ unsafeIndex = index+ + {-# INLINE linearIndex #-}+ linearIndex (ACursored sh makec _ loadc)+ = loadc . makec . fromIndex sh++ {-# INLINE extent #-}+ extent (ACursored sh _ _ _)+ = sh+ + {-# INLINE deepSeqArray #-}+ deepSeqArray (ACursored sh makec shiftc loadc) y+ = sh `deepSeq` makec `seq` shiftc `seq` loadc `seq` y+++-- Fill -----------------------------------------------------------------------+-- | Compute all elements in an rank-2 array. +instance (Fillable r2 e, Elt e) => Fill C r2 DIM2 e where+ {-# INLINE fillP #-}+ fillP (ACursored (Z :. h :. w) makec shiftc loadc) marr+ = fillCursoredBlock2P + (unsafeWriteMArr marr) + makec shiftc loadc+ w 0 0 (w - 1) (h - 1) ++ {-# INLINE fillS #-}+ fillS (ACursored (Z :. (I# h) :. (I# w)) makec shiftc loadc) marr+ = fillCursoredBlock2S + (unsafeWriteMArr marr) + makec shiftc loadc+ w 0# 0# (w -# 1#) (h -# 1#) +++-- | Compute a range of elements in a rank-2 array.+instance (Fillable r2 e, Elt e) => FillRange C r2 DIM2 e where+ {-# INLINE fillRangeP #-}+ fillRangeP (ACursored (Z :. _h :. w) makec shiftc loadc) marr+ (Z :. y0 :. x0) (Z :. y1 :. x1)+ = fillCursoredBlock2P + (unsafeWriteMArr marr) + makec shiftc loadc+ w x0 y0 x1 y1++ {-# INLINE fillRangeS #-}+ fillRangeS (ACursored (Z :. _h :. (I# w)) makec shiftc loadc) marr+ (Z :. (I# y0) :. (I# x0)) + (Z :. (I# y1) :. (I# x1))+ = fillCursoredBlock2S+ (unsafeWriteMArr marr) + makec shiftc loadc+ w x0 y0 x1 y1+ +-- Conversions ----------------------------------------------------------------+-- | Define a new cursored array.+makeCursored + :: sh+ -> (sh -> cursor) -- ^ Create a cursor for an index.+ -> (sh -> cursor -> cursor) -- ^ Shift a cursor by an offset.+ -> (cursor -> e) -- ^ Compute the element at the cursor.+ -> Array C sh e++{-# INLINE makeCursored #-}+makeCursored = ACursored
+ Data/Array/Repa/Repr/Delayed.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE MagicHash #-}+module Data.Array.Repa.Repr.Delayed+ ( D, Array(..)+ , fromFunction, toFunction+ , delay)+where+import Data.Array.Repa.Eval.Elt+import Data.Array.Repa.Eval.Cursored+import Data.Array.Repa.Eval.Chunked+import Data.Array.Repa.Eval.Fill+import Data.Array.Repa.Index+import Data.Array.Repa.Shape+import Data.Array.Repa.Base+import GHC.Exts++-- | Delayed arrays are represented as functions from the index to element value.+data D+data instance Array D sh e+ = ADelayed + sh + (sh -> e) +++-- Repr -----------------------------------------------------------------------+-- | Compute elements of a delayed array.+instance Repr D a where+ {-# INLINE index #-}+ index (ADelayed _ f) ix = f ix++ {-# INLINE linearIndex #-}+ linearIndex (ADelayed sh f) ix = f (fromIndex sh ix)++ {-# INLINE extent #-}+ extent (ADelayed sh _)+ = sh++ {-# INLINE deepSeqArray #-}+ deepSeqArray (ADelayed sh f) y+ = sh `deepSeq` f `seq` y+++-- Fill -----------------------------------------------------------------------+-- | Compute all elements in an array.+instance (Fillable r2 e, Shape sh) => Fill D r2 sh e where+ {-# INLINE [4] fillP #-}+ fillP (ADelayed sh getElem) marr+ = fillChunkedP (size sh) (unsafeWriteMArr marr) (getElem . fromIndex sh) ++ {-# INLINE [4] fillS #-}+ fillS (ADelayed sh getElem) marr+ = fillChunkedS (size sh) (unsafeWriteMArr marr) (getElem . fromIndex sh)+++-- | Compute a range of elements in a rank-2 array.+instance (Fillable r2 e, Elt e) => FillRange D r2 DIM2 e where+ {-# INLINE [1] fillRangeP #-}+ fillRangeP (ADelayed (Z :. _h :. w) getElem) marr+ (Z :. y0 :. x0) (Z :. y1 :. x1)+ = fillBlock2P (unsafeWriteMArr marr) + getElem+ w x0 y0 x1 y1++ {-# INLINE [1] fillRangeS #-}+ fillRangeS (ADelayed (Z :. _h :. (I# w)) getElem) marr+ (Z :. (I# y0) :. (I# x0)) (Z :. (I# y1) :. (I# x1))+ = fillBlock2S (unsafeWriteMArr marr) + getElem+ w x0 y0 x1 y1+++-- Conversions ----------------------------------------------------------------+-- | O(1). Wrap a function as a delayed array.+fromFunction :: sh -> (sh -> a) -> Array D sh a+{-# INLINE fromFunction #-}+fromFunction sh f + = ADelayed sh f +++-- | O(1). Produce the extent of an array and a function to retrieve an arbitrary element.+toFunction + :: (Shape sh, Repr r1 a)+ => Array r1 sh a -> (sh, sh -> a)+{-# INLINE toFunction #-}+toFunction arr+ = case delay arr of+ ADelayed sh f -> (sh, f)+++-- | O(1). Delay an array.+-- This wraps the internal representation to be a function from+-- indices to elements, so consumers don't need to worry about+-- what the previous representation was.+--+delay :: (Shape sh, Repr r e)+ => Array r sh e -> Array D sh e+{-# INLINE delay #-}+delay arr = ADelayed (extent arr) (index arr)++
+ Data/Array/Repa/Repr/ForeignPtr.hs view
@@ -0,0 +1,111 @@++module Data.Array.Repa.Repr.ForeignPtr+ ( F, Array (..)+ , fromForeignPtr, toForeignPtr+ , computeIntoS, computeIntoP)+where+import Data.Array.Repa.Shape+import Data.Array.Repa.Base+import Data.Array.Repa.Eval.Fill+import Data.Array.Repa.Repr.Delayed+import Foreign.Storable+import Foreign.ForeignPtr+import Foreign.Marshal.Alloc+import System.IO.Unsafe++-- | Arrays represented as foreign buffers in the C heap.+data F+data instance Array F sh e+ = AForeignPtr !sh !Int !(ForeignPtr e)++-- Repr -----------------------------------------------------------------------+-- | Read elements from a foreign buffer.+instance Storable a => Repr F a where+ {-# INLINE linearIndex #-}+ linearIndex (AForeignPtr _ len fptr) ix+ | ix < len + = unsafePerformIO + $ withForeignPtr fptr+ $ \ptr -> peekElemOff ptr ix+ + | otherwise+ = error "Repa: foreign array index out of bounds"++ {-# INLINE unsafeLinearIndex #-}+ unsafeLinearIndex (AForeignPtr _ _ fptr) ix+ = unsafePerformIO+ $ withForeignPtr fptr + $ \ptr -> peekElemOff ptr ix++ {-# INLINE extent #-}+ extent (AForeignPtr sh _ _)+ = sh++ {-# INLINE deepSeqArray #-}+ deepSeqArray (AForeignPtr sh len fptr) x + = sh `deepSeq` len `seq` fptr `seq` x+++-- Fill -----------------------------------------------------------------------+-- | Filling of foreign buffers.+instance Storable e => Fillable F e where+ data MArr F e + = FPArr !Int !(ForeignPtr e)++ {-# INLINE newMArr #-}+ newMArr n+ = do let (proxy :: e) = undefined+ ptr <- mallocBytes (sizeOf proxy * n)+ _ <- peek ptr `asTypeOf` return proxy+ + fptr <- newForeignPtr finalizerFree ptr+ return $ FPArr n fptr++ {-# INLINE unsafeWriteMArr #-}+ unsafeWriteMArr (FPArr _ fptr) !ix !x+ = withForeignPtr fptr+ $ \ptr -> pokeElemOff ptr ix x++ {-# INLINE unsafeFreezeMArr #-}+ unsafeFreezeMArr !sh (FPArr len fptr) + = return $ AForeignPtr sh len fptr+++-- Conversions ----------------------------------------------------------------+-- | O(1). Wrap a `ForeignPtr` as an array.+fromForeignPtr+ :: Shape sh+ => sh -> ForeignPtr e -> Array F sh e+{-# INLINE fromForeignPtr #-}+fromForeignPtr !sh !fptr+ = AForeignPtr sh (size sh) fptr+++-- | O(1). Unpack a `ForeignPtr` from an array.+toForeignPtr :: Array F sh e -> ForeignPtr e+{-# INLINE toForeignPtr #-}+toForeignPtr (AForeignPtr _ _ fptr)+ = fptr+++-- | Compute an array sequentially and write the elements into a foreign+-- buffer without intermediate copying. If you want to copy a+-- pre-existing manifest array to a foreign buffer then `delay` it first.+computeIntoS+ :: Fill r1 F sh e+ => ForeignPtr e -> Array r1 sh e -> IO ()+{-# INLINE computeIntoS #-}+computeIntoS !fptr !arr+ = fillS arr (FPArr 0 fptr)+++-- | Compute an array in parallel and write the elements into a foreign+-- buffer without intermediate copying. If you want to copy a+-- pre-existing manifest array to a foreign buffer then `delay` it first.+computeIntoP+ :: Fill r1 F sh e+ => ForeignPtr e -> Array r1 sh e -> IO ()+{-# INLINE computeIntoP #-}+computeIntoP !fptr !arr+ = fillP arr (FPArr 0 fptr)+
+ Data/Array/Repa/Repr/Partitioned.hs view
@@ -0,0 +1,82 @@+++module Data.Array.Repa.Repr.Partitioned+ ( P, Array (..)+ , Range(..)+ , inRange)+where+import Data.Array.Repa.Base+import Data.Array.Repa.Shape+import Data.Array.Repa.Eval+import Data.Array.Repa.Repr.Delayed+import Data.Array.Repa.Repr.Undefined+++-- | Partitioned arrays.+-- The last partition takes priority+--+-- These are produced by Repa's support functions and allow arrays to be defined+-- using a different element function for each partition.+--+-- The basic idea is described in ``Efficient Parallel Stencil Convolution'',+-- Ben Lippmeier and Gabriele Keller, Haskell 2011 -- though the underlying+-- array representation has changed since this paper was published.+--+data P r1 r2++data instance Array (P r1 r2) sh e+ = APart sh -- size of the whole array+ (Range sh) (Array r1 sh e) -- if in range use this array+ (Array r2 sh e) -- otherwise use this array++data Range sh+ = Range sh sh -- indices defining the range+ (sh -> Bool) -- predicate to check whether were in range++-- | Check whether an index is within the given range.+{-# INLINE inRange #-}+inRange :: Range sh -> sh -> Bool+inRange (Range _ _ p) ix+ = p ix+++-- Repr -----------------------------------------------------------------------+-- | Read elements from a partitioned array.+instance (Repr r1 e, Repr r2 e) => Repr (P r1 r2) e where+ {-# INLINE index #-}+ index (APart _ range arr1 arr2) ix+ | inRange range ix = index arr1 ix+ | otherwise = index arr2 ix++ {-# INLINE linearIndex #-}+ linearIndex arr@(APart sh _ _ _) ix+ = index arr $ fromIndex sh ix++ {-# INLINE extent #-}+ extent (APart sh _ _ _) + = sh++ {-# INLINE deepSeqArray #-}+ deepSeqArray (APart sh range arr1 arr2) y+ = sh `deepSeq` range `deepSeqRange` arr1 `deepSeqArray` arr2 `deepSeqArray` y+++{-# INLINE deepSeqRange #-}+deepSeqRange :: Shape sh => Range sh -> b -> b+deepSeqRange (Range low high f) y+ = low `deepSeq` high `deepSeq` f `seq` y+++-- Fill -----------------------------------------------------------------------+instance ( FillRange r1 r3 sh e, Fill r2 r3 sh e+ , Fillable r3 e)+ => Fill (P r1 r2) r3 sh e where+ {-# INLINE fillP #-}+ fillP (APart _ (Range ix10 ix11 _) arr1 arr2) marr+ = do fillRangeP arr1 marr ix10 ix11+ fillP arr2 marr++ {-# INLINE fillS #-}+ fillS (APart _ (Range ix10 ix11 _) arr1 arr2) marr+ = do fillRangeS arr1 marr ix10 ix11+ fillS arr2 marr
+ Data/Array/Repa/Repr/Unboxed.hs view
@@ -0,0 +1,233 @@++module Data.Array.Repa.Repr.Unboxed+ ( U, U.Unbox, Array (..)+ , computeUnboxedS, computeUnboxedP+ , fromListUnboxed+ , fromUnboxed, toUnboxed+ + , zip, zip3, zip4, zip5, zip6+ , unzip, unzip3, unzip4, unzip5, unzip6)+where+import Data.Array.Repa.Shape as R+import Data.Array.Repa.Base as R+import Data.Array.Repa.Eval as R+import Data.Array.Repa.Repr.Delayed as R+import qualified Data.Vector.Unboxed as U+import qualified Data.Vector.Unboxed.Mutable as UM+import Control.Monad+import Prelude hiding (zip, zip3, unzip, unzip3)++-- | Unboxed arrays are represented as unboxed vectors.+--+-- The implementation of `Data.Vector.Unboxed` is based on type families and+-- picks an efficient, specialised representation for every element type. In+-- particular, unboxed vectors of pairs are represented as pairs of unboxed+-- vectors. This is the most efficient representation for numerical data.+--+data U+data instance U.Unbox e => Array U sh e+ = AUnboxed sh !(U.Vector e)+ +deriving instance (Show sh, Show e, U.Unbox e)+ => Show (Array U sh e)++-- Repr -----------------------------------------------------------------------+-- | Read elements from an unboxed vector array.+instance U.Unbox a => Repr U a where+ {-# INLINE linearIndex #-}+ linearIndex (AUnboxed _ vec) ix+ = vec U.! ix++ {-# INLINE unsafeLinearIndex #-}+ unsafeLinearIndex (AUnboxed _ vec) ix+ = vec `U.unsafeIndex` ix++ {-# INLINE extent #-}+ extent (AUnboxed sh _)+ = sh++ {-# INLINE deepSeqArray #-}+ deepSeqArray (AUnboxed sh vec) x + = sh `deepSeq` vec `seq` x+++-- Fill -----------------------------------------------------------------------+-- | Filling of unboxed vector arrays.+instance U.Unbox e => Fillable U e where+ data MArr U e + = UMArr (UM.IOVector e)++ {-# INLINE newMArr #-}+ newMArr n+ = liftM UMArr (UM.new n)++ {-# INLINE unsafeWriteMArr #-}+ unsafeWriteMArr (UMArr v) ix+ = UM.unsafeWrite v ix++ {-# INLINE unsafeFreezeMArr #-}+ unsafeFreezeMArr sh (UMArr mvec) + = do vec <- U.unsafeFreeze mvec+ return $ AUnboxed sh vec+++-- Conversions ----------------------------------------------------------------+-- | Sequential computation of array elements..+--+-- * This is an alias for `computeS` with a more specific type.+--+computeUnboxedS+ :: Fill r1 U sh e+ => Array r1 sh e -> Array U sh e+{-# INLINE computeUnboxedS #-}+computeUnboxedS = computeS+++-- | Parallel computation of array elements.+--+-- * This is an alias for `computeP` with a more specific type.+--+computeUnboxedP+ :: Fill r1 U sh e+ => Array r1 sh e -> Array U sh e+{-# INLINE computeUnboxedP #-}+computeUnboxedP = computeP+++-- | O(n). Convert a list to an unboxed vector array.+-- +-- * This is an alias for `fromList` with a more specific type.+--+fromListUnboxed+ :: (Shape sh, U.Unbox a)+ => sh -> [a] -> Array U sh a+{-# INLINE fromListUnboxed #-}+fromListUnboxed = R.fromList+++-- | O(1). Wrap an unboxed vector as an array.+fromUnboxed+ :: (Shape sh, U.Unbox e)+ => sh -> U.Vector e -> Array U sh e+{-# INLINE fromUnboxed #-}+fromUnboxed sh vec+ = AUnboxed sh vec+++-- | O(1). Unpack an unboxed vector from an array.+toUnboxed+ :: U.Unbox e+ => Array U sh e -> U.Vector e+{-# INLINE toUnboxed #-}+toUnboxed (AUnboxed _ vec)+ = vec++-- Zip ------------------------------------------------------------------------+-- | O(1). Zip some unboxed arrays.+-- The shapes must be identical else `error`.+zip :: (Shape sh, U.Unbox a, U.Unbox b)+ => Array U sh a -> Array U sh b+ -> Array U sh (a, b)+{-# INLINE zip #-}+zip (AUnboxed sh1 vec1) (AUnboxed sh2 vec2)+ | sh1 /= sh2 = error "Repa: zip array shapes not identical"+ | otherwise = AUnboxed sh1 (U.zip vec1 vec2)+++-- | O(1). Zip some unboxed arrays.+-- The shapes must be identical else `error`.+zip3 :: (Shape sh, U.Unbox a, U.Unbox b, U.Unbox c)+ => Array U sh a -> Array U sh b -> Array U sh c+ -> Array U sh (a, b, c)+{-# INLINE zip3 #-}+zip3 (AUnboxed sh1 vec1) (AUnboxed sh2 vec2) (AUnboxed sh3 vec3)+ | sh1 /= sh2 || sh1 /= sh3+ = error "Repa: zip array shapes not identical"+ | otherwise = AUnboxed sh1 (U.zip3 vec1 vec2 vec3)+++-- | O(1). Zip some unboxed arrays.+-- The shapes must be identical else `error`.+zip4 :: (Shape sh, U.Unbox a, U.Unbox b, U.Unbox c, U.Unbox d)+ => Array U sh a -> Array U sh b -> Array U sh c -> Array U sh d+ -> Array U sh (a, b, c, d)+{-# INLINE zip4 #-}+zip4 (AUnboxed sh1 vec1) (AUnboxed sh2 vec2) (AUnboxed sh3 vec3) (AUnboxed sh4 vec4)+ | sh1 /= sh2 || sh1 /= sh3 || sh1 /= sh4+ = error "Repa: zip array shapes not identical"+ | otherwise = AUnboxed sh1 (U.zip4 vec1 vec2 vec3 vec4)+++-- | O(1). Zip some unboxed arrays.+-- The shapes must be identical else `error`.+zip5 :: (Shape sh, U.Unbox a, U.Unbox b, U.Unbox c, U.Unbox d, U.Unbox e)+ => Array U sh a -> Array U sh b -> Array U sh c -> Array U sh d -> Array U sh e+ -> Array U sh (a, b, c, d, e)+{-# INLINE zip5 #-}+zip5 (AUnboxed sh1 vec1) (AUnboxed sh2 vec2) (AUnboxed sh3 vec3) (AUnboxed sh4 vec4) (AUnboxed sh5 vec5)+ | sh1 /= sh2 || sh1 /= sh3 || sh1 /= sh4 || sh1 /= sh5+ = error "Repa: zip array shapes not identical"+ | otherwise = AUnboxed sh1 (U.zip5 vec1 vec2 vec3 vec4 vec5)+++-- | O(1). Zip some unboxed arrays.+-- The shapes must be identical else `error`.+zip6 :: (Shape sh, U.Unbox a, U.Unbox b, U.Unbox c, U.Unbox d, U.Unbox e, U.Unbox f)+ => Array U sh a -> Array U sh b -> Array U sh c -> Array U sh d -> Array U sh e -> Array U sh f+ -> Array U sh (a, b, c, d, e, f)+{-# INLINE zip6 #-}+zip6 (AUnboxed sh1 vec1) (AUnboxed sh2 vec2) (AUnboxed sh3 vec3) (AUnboxed sh4 vec4) (AUnboxed sh5 vec5) (AUnboxed sh6 vec6)+ | sh1 /= sh2 || sh1 /= sh3 || sh1 /= sh4 || sh1 /= sh5 || sh1 /= sh6+ = error "Repa: zip array shapes not identical"+ | otherwise = AUnboxed sh1 (U.zip6 vec1 vec2 vec3 vec4 vec5 vec6)+ ++-- Unzip ----------------------------------------------------------------------+-- | O(1). Unzip an unboxed array.+unzip :: (U.Unbox a, U.Unbox b)+ => Array U sh (a, b)+ -> (Array U sh a, Array U sh b)+{-# INLINE unzip #-}+unzip (AUnboxed sh vec)+ = let (as, bs) = U.unzip vec+ in (AUnboxed sh as, AUnboxed sh bs)+++-- | O(1). Unzip an unboxed array.+unzip3 :: (U.Unbox a, U.Unbox b, U.Unbox c)+ => Array U sh (a, b, c)+ -> (Array U sh a, Array U sh b, Array U sh c)+{-# INLINE unzip3 #-}+unzip3 (AUnboxed sh vec)+ = let (as, bs, cs) = U.unzip3 vec+ in (AUnboxed sh as, AUnboxed sh bs, AUnboxed sh cs)+++-- | O(1). Unzip an unboxed array.+unzip4 :: (U.Unbox a, U.Unbox b, U.Unbox c, U.Unbox d)+ => Array U sh (a, b, c, d)+ -> (Array U sh a, Array U sh b, Array U sh c, Array U sh d)+{-# INLINE unzip4 #-}+unzip4 (AUnboxed sh vec)+ = let (as, bs, cs, ds) = U.unzip4 vec+ in (AUnboxed sh as, AUnboxed sh bs, AUnboxed sh cs, AUnboxed sh ds)+++-- | O(1). Unzip an unboxed array.+unzip5 :: (U.Unbox a, U.Unbox b, U.Unbox c, U.Unbox d, U.Unbox e)+ => Array U sh (a, b, c, d, e)+ -> (Array U sh a, Array U sh b, Array U sh c, Array U sh d, Array U sh e)+{-# INLINE unzip5 #-}+unzip5 (AUnboxed sh vec)+ = let (as, bs, cs, ds, es) = U.unzip5 vec+ in (AUnboxed sh as, AUnboxed sh bs, AUnboxed sh cs, AUnboxed sh ds, AUnboxed sh es)+++-- | O(1). Unzip an unboxed array.+unzip6 :: (U.Unbox a, U.Unbox b, U.Unbox c, U.Unbox d, U.Unbox e, U.Unbox f)+ => Array U sh (a, b, c, d, e, f)+ -> (Array U sh a, Array U sh b, Array U sh c, Array U sh d, Array U sh e, Array U sh f)+{-# INLINE unzip6 #-}+unzip6 (AUnboxed sh vec)+ = let (as, bs, cs, ds, es, fs) = U.unzip6 vec+ in (AUnboxed sh as, AUnboxed sh bs, AUnboxed sh cs, AUnboxed sh ds, AUnboxed sh es, AUnboxed sh fs)
+ Data/Array/Repa/Repr/Undefined.hs view
@@ -0,0 +1,41 @@++module Data.Array.Repa.Repr.Undefined+ ( X, Array (..))+where+import Data.Array.Repa.Base+import Data.Array.Repa.Shape+import Data.Array.Repa.Eval.Fill+++-- | An array with undefined elements.+-- +-- * This is normally used as the last representation in a partitioned array, +-- as the previous partitions are expected to provide full coverage.+data X+data instance Array X sh e+ = AUndefined sh+++-- | Undefined array elements. Inspecting them yields `error`.+--+instance Repr X e where+ {-# INLINE deepSeqArray #-}+ deepSeqArray _ x+ = x++ {-# INLINE extent #-}+ extent (AUndefined sh) + = sh++ {-# INLINE index #-}+ index (AUndefined _) _ = error "Repa: array element is undefined."+ + {-# INLINE linearIndex #-}+ linearIndex (AUndefined _) _ = error "Repa: array element is undefined."+ ++instance (Shape sh, Fillable r2 e, Num e) => Fill X r2 sh e where+ fillS _ _ = return ()+ fillP _ _ = return ()++
+ Data/Array/Repa/Repr/Vector.hs view
@@ -0,0 +1,112 @@++module Data.Array.Repa.Repr.Vector+ ( V, Array (..)+ , computeVectorS, computeVectorP+ , fromListVector+ , fromVector+ , toVector)+where+import Data.Array.Repa.Shape+import Data.Array.Repa.Base+import Data.Array.Repa.Eval+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as VM+import Control.Monad++-- | Arrays represented as boxed vectors.+--+-- This representation should only be used when your element type doesn't+-- have an `Unbox` instsance. If it does, then use the Unboxed `U`+-- representation will be faster.+data V+data instance Array V sh e+ = AVector sh !(V.Vector e)+ +deriving instance (Show sh, Show e)+ => Show (Array V sh e)++-- Repr -----------------------------------------------------------------------+-- | Read elements from a boxed vector array.+instance Repr V a where+ {-# INLINE linearIndex #-}+ linearIndex (AVector _ vec) ix+ = vec V.! ix++ {-# INLINE unsafeLinearIndex #-}+ unsafeLinearIndex (AVector _ vec) ix+ = vec `V.unsafeIndex` ix++ {-# INLINE extent #-}+ extent (AVector sh _)+ = sh++ {-# INLINE deepSeqArray #-}+ deepSeqArray (AVector sh vec) x + = sh `deepSeq` vec `seq` x+++-- Fill -----------------------------------------------------------------------+-- | Filling of boxed vector arrays.+instance Fillable V e where+ data MArr V e + = MVec (VM.IOVector e)++ {-# INLINE newMArr #-}+ newMArr n+ = liftM MVec (VM.new n)++ {-# INLINE unsafeWriteMArr #-}+ unsafeWriteMArr (MVec v) ix+ = VM.unsafeWrite v ix++ {-# INLINE unsafeFreezeMArr #-}+ unsafeFreezeMArr sh (MVec mvec) + = do vec <- V.unsafeFreeze mvec+ return $ AVector sh vec+++-- Conversions ----------------------------------------------------------------+-- | Sequential computation of array elements.+--+-- * This is an alias for `compute` with a more specific type.+--+computeVectorS+ :: Fill r1 V sh e+ => Array r1 sh e -> Array V sh e+{-# INLINE computeVectorS #-}+computeVectorS = computeS+++-- | Parallel computation of array elements.+computeVectorP+ :: Fill r1 V sh e+ => Array r1 sh e -> Array V sh e+{-# INLINE computeVectorP #-}+computeVectorP = computeP+++-- | O(n). Convert a list to a boxed vector array.+--+-- * This is an alias for `fromList` with a more specific type.+--+fromListVector :: Shape sh => sh -> [a] -> Array V sh a+{-# INLINE fromListVector #-}+fromListVector = fromList+++-- | O(1). Wrap a boxed vector as an array.+fromVector+ :: Shape sh+ => sh -> V.Vector e -> Array V sh e+{-# INLINE fromVector #-}+fromVector sh vec+ = AVector sh vec+++-- | O(1). Unpack a boxed vector from an array.+toVector :: Array V sh e -> V.Vector e+{-# INLINE toVector #-}+toVector (AVector _ vec)+ = vec++
Data/Array/Repa/Shape.hs view
@@ -7,7 +7,7 @@ , showShape ) where --- Shape ------------------------------------------------------------------------------------------+-- Shape ---------------------------------------------------------------------- -- | Class of types that can be used as array shapes and indices. class Eq sh => Shape sh where
Data/Array/Repa/Slice.hs view
@@ -10,7 +10,7 @@ , Slice (..)) where import Data.Array.Repa.Index-import Prelude hiding (replicate, drop)+import Prelude hiding (replicate, drop) -- | Select all indices at a certain position.@@ -47,37 +47,37 @@ instance Slice Z where- {-# INLINE sliceOfFull #-}+ {-# INLINE [1] sliceOfFull #-} sliceOfFull _ _ = Z - {-# INLINE fullOfSlice #-}+ {-# INLINE [1] fullOfSlice #-} fullOfSlice _ _ = Z instance Slice (Any sh) where- {-# INLINE sliceOfFull #-}+ {-# INLINE [1] sliceOfFull #-} sliceOfFull _ sh = sh - {-# INLINE fullOfSlice #-}+ {-# INLINE [1] fullOfSlice #-} fullOfSlice _ sh = sh instance Slice sl => Slice (sl :. Int) where- {-# INLINE sliceOfFull #-}+ {-# INLINE [1] sliceOfFull #-} sliceOfFull (fsl :. _) (ssl :. _) = sliceOfFull fsl ssl - {-# INLINE fullOfSlice #-}+ {-# INLINE [1] fullOfSlice #-} fullOfSlice (fsl :. n) ssl = fullOfSlice fsl ssl :. n instance Slice sl => Slice (sl :. All) where- {-# INLINE sliceOfFull #-}+ {-# INLINE [1] sliceOfFull #-} sliceOfFull (fsl :. All) (ssl :. s) = sliceOfFull fsl ssl :. s - {-# INLINE fullOfSlice #-}+ {-# INLINE [1] fullOfSlice #-} fullOfSlice (fsl :. All) (ssl :. s) = fullOfSlice fsl ssl :. s
Data/Array/Repa/Specialised/Dim2.hs view
@@ -7,7 +7,9 @@ , clampToBorder2 , makeBordered2) where-import Data.Array.Repa+import Data.Array.Repa.Index+import Data.Array.Repa.Repr.Partitioned+import Data.Array.Repa.Repr.Undefined -- | Check if an index lies inside the given extent.@@ -63,19 +65,22 @@ | otherwise = sh :. y :. x --- | Make a 2D partitioned array given two generators, one to produce elements in the--- border region, and one to produce values in the internal region.+-- | Make a 2D partitioned array from two others, one to produce the elements+-- in the internal region, and one to produce elements in the border region.+-- The two arrays must have the same extent. -- The border must be the same width on all sides.+--+-- TODO: Check arrays have same extent.+-- makeBordered2- :: Elt a- => DIM2 -- ^ Extent of array.+ :: DIM2 -- ^ Extent of array. -> Int -- ^ Width of border.- -> Generator DIM2 a -- ^ Generator for border elements.- -> Generator DIM2 a -- ^ Generator for internal elements.- -> Array DIM2 a+ -> Array r1 DIM2 a -- ^ Array for internal elements.+ -> Array r2 DIM2 a -- ^ Array for border elements.+ -> Array (P r1 (P r2 (P r2 (P r2 (P r2 X))))) DIM2 a {-# INLINE makeBordered2 #-}-makeBordered2 sh@(_ :. aHeight :. aWidth) borderWidth genInternal genBorder+makeBordered2 sh@(_ :. aHeight :. aWidth) borderWidth arrInternal arrBorder = let -- minimum and maximum indicies of values in the inner part of the image. !xMin = borderWidth@@ -83,26 +88,22 @@ !xMax = aWidth - borderWidth - 1 !yMax = aHeight - borderWidth - 1 - -- | Range of values where some of the data needed by the stencil is outside the image.- rectsBorder- = [ Rect (Z :. 0 :. 0) (Z :. yMin -1 :. aWidth - 1) -- bot- , Rect (Z :. yMax + 1 :. 0) (Z :. aHeight - 1 :. aWidth - 1) -- top- , Rect (Z :. yMin :. 0) (Z :. yMax :. xMin - 1) -- left- , Rect (Z :. yMin :. xMax + 1) (Z :. yMax :. aWidth - 1) ] -- right - {-# INLINE inBorder #-}- inBorder = not . inInternal-- -- Range of values where we don't need to worry about the border- rectsInternal- = [ Rect (Z :. yMin :. xMin) (Z :. yMax :. xMax ) ]- {-# INLINE inInternal #-} inInternal (Z :. y :. x) = x >= xMin && x <= xMax && y >= yMin && y <= yMax - in Array sh- [ Region (RangeRects inBorder rectsBorder) genInternal- , Region (RangeRects inInternal rectsInternal) genBorder ]+ {-# INLINE inBorder #-}+ inBorder = not . inInternal + in + -- internal region+ APart sh (Range (Z :. yMin :. xMin) (Z :. yMax :. xMax ) inInternal) arrInternal++ -- border regions+ $ APart sh (Range (Z :. 0 :. 0) (Z :. yMin -1 :. aWidth - 1) inBorder) arrBorder+ $ APart sh (Range (Z :. yMax + 1 :. 0) (Z :. aHeight - 1 :. aWidth - 1) inBorder) arrBorder+ $ APart sh (Range (Z :. yMin :. 0) (Z :. yMax :. xMin - 1) inBorder) arrBorder+ $ APart sh (Range (Z :. yMin :. xMax + 1) (Z :. yMax :. aWidth - 1) inBorder) arrBorder+ $ AUndefined sh
Data/Array/Repa/Stencil.hs view
@@ -4,267 +4,16 @@ -- | Efficient computation of stencil based convolutions. ----- This is specialised for stencils up to 7x7.--- Due to limitations in the GHC optimiser, using larger stencils doesn't work, and will yield `error`--- at runtime. We can probably increase the limit if required -- just ask.------ The focus of the stencil is in the center of the 7x7 tile, which has coordinates (0, 0).--- All coefficients in the stencil must fit in the tile, so they can be given X,Y coordinates up to--- +/- 3 positions. The stencil can be any shape, and need not be symmetric -- provided it fits in the 7x7 tile.--- module Data.Array.Repa.Stencil ( Stencil (..) , Boundary (..) -- * Stencil creation.- , makeStencil, makeStencil2-- -- * Stencil operators.- , mapStencil2, forStencil2- , mapStencilFrom2, forStencilFrom2-- -- From Data.Array.Repa.Stencil.Template- , stencil2)+ , makeStencil) where-import Data.Array.Repa as R-import Data.Array.Repa.Internals.Base as R+import Data.Array.Repa+import Data.Array.Repa.Base import Data.Array.Repa.Stencil.Base import Data.Array.Repa.Stencil.Template import Data.Array.Repa.Specialised.Dim2-import qualified Data.Array.Repa.Shape as S-import qualified Data.Vector.Unboxed as V-import Data.List as List-import GHC.Exts-import GHC.Base-import Debug.Trace---- | A index into the flat array.--- Should be abstract outside the stencil modules.-data Cursor- = Cursor Int----- Wrappers ------------------------------------------------------------------------------------------ | Like `mapStencil2` but with the parameters flipped.-forStencil2- :: Elt a- => Boundary a- -> Array DIM2 a- -> Stencil DIM2 a- -> Array DIM2 a--{-# INLINE forStencil2 #-}-forStencil2 boundary arr stencil- = mapStencil2 boundary stencil arr----- | Like `mapStencilFrom2` but with the parameters flipped.-forStencilFrom2- :: (Elt a, Elt b)- => Boundary a- -> Array DIM2 b- -> (b -> a)- -> Stencil DIM2 a- -> Array DIM2 a--{-# INLINE forStencilFrom2 #-}-forStencilFrom2 boundary arr from stencil- = mapStencilFrom2 boundary stencil arr from----- | Apply a stencil to every element of a 2D array.--- The array must be manifest else `error`.-mapStencil2- :: Elt a- => Boundary a- -> Stencil DIM2 a- -> Array DIM2 a- -> Array DIM2 a--{-# INLINE mapStencil2 #-}-mapStencil2 boundary stencil arr- = mapStencilFrom2 boundary stencil arr id--------------------------------------------------------------------------------------------------------- | Apply a stencil to every element of a 2D array.--- The array must be manifest else `error`.-mapStencilFrom2- :: (Elt a, Elt b)- => Boundary a -- ^ How to handle the boundary of the array.- -> Stencil DIM2 a -- ^ Stencil to apply.- -> Array DIM2 b -- ^ Array to apply stencil to.- -> (b -> a) -- ^ Apply this function to values read from the array before- -- transforming them with the stencil.- -> Array DIM2 a--{-# INLINE mapStencilFrom2 #-}-mapStencilFrom2 boundary stencil@(StencilStatic sExtent zero load) arr preConvert- = let (_ :. aHeight :. aWidth) = extent arr- (_ :. sHeight :. sWidth) = sExtent-- sHeight2 = sHeight `div` 2- sWidth2 = sWidth `div` 2-- -- minimum and maximum indicies of values in the inner part of the image.- !xMin = sWidth2- !yMin = sHeight2- !xMax = aWidth - sWidth2 - 1- !yMax = aHeight - sHeight2 - 1-- -- Rectangles ------------------------ -- range of values where we don't need to worry about the border- rectsInternal- = [ Rect (Z :. yMin :. xMin) (Z :. yMax :. xMax ) ]-- {-# INLINE inInternal #-}- inInternal (Z :. y :. x)- = x >= xMin && x <= xMax- && y >= yMin && y <= yMax--- -- range of values where some of the data needed by the stencil is outside the image.- rectsBorder- = [ Rect (Z :. 0 :. 0) (Z :. yMin -1 :. aWidth - 1) -- bot- , Rect (Z :. yMax + 1 :. 0) (Z :. aHeight - 1 :. aWidth - 1) -- top- , Rect (Z :. yMin :. 0) (Z :. yMax :. xMin - 1) -- left- , Rect (Z :. yMin :. xMax + 1) (Z :. yMax :. aWidth - 1) ] -- right-- {-# INLINE inBorder #-}- inBorder = not . inInternal--- -- Cursor functions ----------------- {-# INLINE makeCursor' #-}- makeCursor' (Z :. y :. x)- = Cursor (x + y * aWidth)-- {-# INLINE shiftCursor' #-}- shiftCursor' ix (Cursor off)- = Cursor- $ case ix of- Z :. y :. x -> off + y * aWidth + x-- {-# INLINE getInner' #-}- getInner' cur- = unsafeAppStencilCursor2 shiftCursor' stencil- arr preConvert cur-- {-# INLINE getBorder' #-}- getBorder' cur- = case boundary of- BoundConst c -> c- BoundClamp -> unsafeAppStencilCursor2_clamp addDim stencil- arr preConvert cur-- in Array (extent arr)- [ Region (RangeRects inBorder rectsBorder)- (GenCursor id addDim getBorder')-- , Region (RangeRects inInternal rectsInternal)- (GenCursor makeCursor' shiftCursor' getInner') ]---unsafeAppStencilCursor2- :: (Elt a, Elt b)- => (DIM2 -> Cursor -> Cursor)- -> Stencil DIM2 a- -> Array DIM2 b- -> (b -> a)- -> Cursor- -> a--{-# INLINE [1] unsafeAppStencilCursor2 #-}-unsafeAppStencilCursor2 shift- stencil@(StencilStatic sExtent zero load)- arr@(Array aExtent [Region RangeAll (GenManifest vec)]) preConvert- cur@(Cursor off)-- | _ :. sHeight :. sWidth <- sExtent- , _ :. aHeight :. aWidth <- aExtent- , sHeight <= 7, sWidth <= 7- = let- -- Get data from the manifest array.- {-# INLINE [0] getData #-}- getData (Cursor cur) = preConvert $ vec `V.unsafeIndex` cur-- -- Build a function to pass data from the array to our stencil.- {-# INLINE oload #-}- oload oy ox- = let !cur' = shift (Z :. oy :. ox) cur- in load (Z :. oy :. ox) (getData cur')-- in template7x7 oload zero----- | Like above, but clamp out of bounds array values to the closest real value.-unsafeAppStencilCursor2_clamp- :: forall a b. (Elt a, Elt b)- => (DIM2 -> DIM2 -> DIM2)- -> Stencil DIM2 a- -> Array DIM2 b- -> (b -> a)- -> DIM2- -> a--{-# INLINE [1] unsafeAppStencilCursor2_clamp #-}-unsafeAppStencilCursor2_clamp shift- stencil@(StencilStatic sExtent zero load)- arr@(Array aExtent [Region RangeAll (GenManifest vec)]) preConvert- cur-- | _ :. sHeight :. sWidth <- sExtent- , _ :. aHeight :. aWidth <- aExtent- , sHeight <= 7, sWidth <= 7- = let- -- Get data from the manifest array.- {-# INLINE [0] getData #-}- getData :: DIM2 -> a- getData (Z :. y :. x)- = wrapLoadX x y-- -- TODO: Inlining this into above makes SpecConstr choke- wrapLoadX :: Int -> Int -> a- wrapLoadX !x !y- | x < 0 = wrapLoadY 0 y- | x >= aWidth = wrapLoadY (aWidth - 1) y- | otherwise = wrapLoadY x y-- {-# INLINE wrapLoadY #-}- wrapLoadY :: Int -> Int -> a- wrapLoadY !x !y- | y < 0 = loadXY x 0- | y >= aHeight = loadXY x (aHeight - 1)- | otherwise = loadXY x y-- {-# INLINE loadXY #-}- loadXY :: Int -> Int -> a- loadXY !x !y- = preConvert $ vec `V.unsafeIndex` (x + y * aWidth)-- -- Build a function to pass data from the array to our stencil.- {-# INLINE oload #-}- oload oy ox- = let !cur' = shift (Z :. oy :. ox) cur- in load (Z :. oy :. ox) (getData cur')-- in template7x7 oload zero------ | Data template for stencils up to 7x7.-template7x7- :: (Int -> Int -> a -> a)- -> a -> a--{-# INLINE [1] template7x7 #-}-template7x7 f zero- = f (-3) (-3) $ f (-3) (-2) $ f (-3) (-1) $ f (-3) 0 $ f (-3) 1 $ f (-3) 2 $ f (-3) 3- $ f (-2) (-3) $ f (-2) (-2) $ f (-2) (-1) $ f (-2) 0 $ f (-2) 1 $ f (-2) 2 $ f (-2) 3- $ f (-1) (-3) $ f (-1) (-2) $ f (-1) (-1) $ f (-1) 0 $ f (-1) 1 $ f (-1) 2 $ f (-1) 3- $ f 0 (-3) $ f 0 (-2) $ f 0 (-1) $ f 0 0 $ f 0 1 $ f 0 2 $ f 0 3- $ f 1 (-3) $ f 1 (-2) $ f 1 (-1) $ f 1 0 $ f 1 1 $ f 1 2 $ f 1 3- $ f 2 (-3) $ f 2 (-2) $ f 2 (-1) $ f 2 0 $ f 2 1 $ f 2 2 $ f 2 3- $ f 3 (-3) $ f 3 (-2) $ f 3 (-1) $ f 3 0 $ f 3 1 $ f 3 2 $ f 3 3- $ zero
Data/Array/Repa/Stencil/Base.hs view
@@ -5,7 +5,6 @@ , Stencil (..) , makeStencil, makeStencil2) where-import Data.Array.Repa.Internals.Elt import Data.Array.Repa.Index -- | How to handle the case when the stencil lies partly outside the array.@@ -18,8 +17,8 @@ deriving (Show) --- | Represents a convolution stencil that we can apply to array. Only statically known stencils--- are supported right now.+-- | Represents a convolution stencil that we can apply to array.+-- Only statically known stencils are supported right now. data Stencil sh a -- | Static stencils are used when the coefficients are fixed,@@ -32,7 +31,7 @@ -- | Make a stencil from a function yielding coefficients at each index. makeStencil- :: (Elt a, Num a)+ :: Num a => sh -- ^ Extent of stencil. -> (sh -> Maybe a) -- ^ Get the coefficient at this index. -> Stencil sh a@@ -48,7 +47,7 @@ -- | Wrapper for `makeStencil` that requires a DIM2 stencil. makeStencil2- :: (Elt a, Num a)+ :: Num a => Int -> Int -- ^ extent of stencil -> (DIM2 -> Maybe a) -- ^ Get the coefficient at this index. -> Stencil DIM2 a
+ Data/Array/Repa/Stencil/Dim2.hs view
@@ -0,0 +1,228 @@+-- This is specialised for stencils up to 7x7.+-- Due to limitations in the GHC optimiser, using larger stencils doesn't+-- work, and will yield `error` at runtime. We can probably increase the+-- limit if required -- just ask.+--+-- The focus of the stencil is in the center of the 7x7 tile, which has+-- coordinates (0, 0). All coefficients in the stencil must fit in the tile,+-- so they can be given X,Y coordinates up to +/- 3 positions.+-- The stencil can be any shape, and need not be symmetric -- provided it+-- fits in the 7x7 tile.+--+module Data.Array.Repa.Stencil.Dim2+ ( + -- * Stencil creation+ makeStencil2, stencil2++ -- * Stencil operators+ , PC5, mapStencil2, forStencil2)+where+import Data.Array.Repa+import Data.Array.Repa.Repr.Cursored+import Data.Array.Repa.Repr.Partitioned+import Data.Array.Repa.Repr.Undefined+import Data.Array.Repa.Stencil.Base+import Data.Array.Repa.Stencil.Template++-- | A index into the flat array.+-- Should be abstract outside the stencil modules.+data Cursor+ = Cursor Int++type PC5 = P C (P D (P D (P D (P D X))))+++-- Wrappers -------------------------------------------------------------------+-- | Like `mapStencil2` but with the parameters flipped.+forStencil2+ :: Repr r a+ => Boundary a+ -> Array r DIM2 a+ -> Stencil DIM2 a+ -> Array PC5 DIM2 a++{-# INLINE forStencil2 #-}+forStencil2 boundary arr stencil+ = mapStencil2 boundary stencil arr+++-------------------------------------------------------------------------------+-- | Apply a stencil to every element of a 2D array.+mapStencil2+ :: Repr r a+ => Boundary a -- ^ How to handle the boundary of the array.+ -> Stencil DIM2 a -- ^ Stencil to apply.+ -> Array r DIM2 a -- ^ Array to apply stencil to.+ -> Array PC5 DIM2 a++{-# INLINE mapStencil2 #-}+mapStencil2 boundary stencil@(StencilStatic sExtent _zero _load) arr+ = let sh = extent arr+ (_ :. aHeight :. aWidth) = sh+ (_ :. sHeight :. sWidth) = sExtent++ sHeight2 = sHeight `div` 2+ sWidth2 = sWidth `div` 2++ -- minimum and maximum indicies of values in the inner part of the image.+ !xMin = sWidth2+ !yMin = sHeight2+ !xMax = aWidth - sWidth2 - 1+ !yMax = aHeight - sHeight2 - 1++ {-# INLINE inInternal #-}+ inInternal (Z :. y :. x)+ = x >= xMin && x <= xMax+ && y >= yMin && y <= yMax++ {-# INLINE inBorder #-}+ inBorder = not . inInternal++ -- Cursor functions ----------------+ {-# INLINE makec #-}+ makec (Z :. y :. x)+ = Cursor (x + y * aWidth)++ {-# INLINE shiftc #-}+ shiftc ix (Cursor off)+ = Cursor+ $ case ix of+ Z :. y :. x -> off + y * aWidth + x++ {-# INLINE getInner' #-}+ getInner' cur+ = unsafeAppStencilCursor2 shiftc stencil arr cur++ {-# INLINE getBorder' #-}+ getBorder' ix+ = case boundary of+ BoundConst c -> c+ BoundClamp -> unsafeAppStencilCursor2_clamp addDim stencil+ arr ix++ {-# INLINE arrInternal #-}+ arrInternal = makeCursored (extent arr) makec shiftc getInner' + + {-# INLINE arrBorder #-}+ arrBorder = fromFunction (extent arr) getBorder'++ in+ -- internal region+ APart sh (Range (Z :. yMin :. xMin) (Z :. yMax :. xMax ) inInternal) arrInternal++ -- border regions+ $ APart sh (Range (Z :. 0 :. 0) (Z :. yMin -1 :. aWidth - 1) inBorder) arrBorder+ $ APart sh (Range (Z :. yMax + 1 :. 0) (Z :. aHeight - 1 :. aWidth - 1) inBorder) arrBorder+ $ APart sh (Range (Z :. yMin :. 0) (Z :. yMax :. xMin - 1) inBorder) arrBorder+ $ APart sh (Range (Z :. yMin :. xMax + 1) (Z :. yMax :. aWidth - 1) inBorder) arrBorder+ $ AUndefined sh+++unsafeAppStencilCursor2+ :: Repr r a+ => (DIM2 -> Cursor -> Cursor)+ -> Stencil DIM2 a+ -> Array r DIM2 a+ -> Cursor+ -> a++{-# INLINE unsafeAppStencilCursor2 #-}+unsafeAppStencilCursor2 shift+ (StencilStatic sExtent zero loads)+ arr cur0++ | _ :. sHeight :. sWidth <- sExtent+ , sHeight <= 7, sWidth <= 7+ = let+ -- Get data from the manifest array.+ {-# INLINE getData #-}+ getData (Cursor cur) = arr `unsafeLinearIndex` cur++ -- Build a function to pass data from the array to our stencil.+ {-# INLINE oload #-}+ oload oy ox+ = let !cur' = shift (Z :. oy :. ox) cur0+ in loads (Z :. oy :. ox) (getData cur')++ in template7x7 oload zero++ | otherwise+ = error $ unlines + [ "mapStencil2: Your stencil is too big for this method."+ , " It must fit within a 7x7 tile to be compiled statically." ]+++-- | Like above, but clamp out of bounds array values to the closest real value.+unsafeAppStencilCursor2_clamp+ :: forall r a+ . Repr r a+ => (DIM2 -> DIM2 -> DIM2)+ -> Stencil DIM2 a+ -> Array r DIM2 a+ -> DIM2+ -> a++{-# INLINE unsafeAppStencilCursor2_clamp #-}+unsafeAppStencilCursor2_clamp shift+ (StencilStatic sExtent zero loads)+ arr cur++ | _ :. sHeight :. sWidth <- sExtent+ , _ :. aHeight :. aWidth <- extent arr+ , sHeight <= 7, sWidth <= 7+ = let+ -- Get data from the manifest array.+ {-# INLINE getData #-}+ getData :: DIM2 -> a+ getData (Z :. y :. x)+ = wrapLoadX x y++ -- TODO: Inlining this into above makes SpecConstr choke+ wrapLoadX :: Int -> Int -> a+ wrapLoadX !x !y+ | x < 0 = wrapLoadY 0 y+ | x >= aWidth = wrapLoadY (aWidth - 1) y+ | otherwise = wrapLoadY x y++ {-# INLINE wrapLoadY #-}+ wrapLoadY :: Int -> Int -> a+ wrapLoadY !x !y+ | y < 0 = loadXY x 0+ | y >= aHeight = loadXY x (aHeight - 1)+ | otherwise = loadXY x y++ {-# INLINE loadXY #-}+ loadXY :: Int -> Int -> a+ loadXY !x !y+ = arr `unsafeIndex` (Z :. y :. x)++ -- Build a function to pass data from the array to our stencil.+ {-# INLINE oload #-}+ oload oy ox+ = let !cur' = shift (Z :. oy :. ox) cur+ in loads (Z :. oy :. ox) (getData cur')++ in template7x7 oload zero++ | otherwise+ = error $ unlines + [ "mapStencil2: Your stencil is too big for this method."+ , " It must fit within a 7x7 tile to be compiled statically." ]+++-- | Data template for stencils up to 7x7.+template7x7+ :: (Int -> Int -> a -> a)+ -> a -> a++{-# INLINE template7x7 #-}+template7x7 f zero+ = f (-3) (-3) $ f (-3) (-2) $ f (-3) (-1) $ f (-3) 0 $ f (-3) 1 $ f (-3) 2 $ f (-3) 3+ $ f (-2) (-3) $ f (-2) (-2) $ f (-2) (-1) $ f (-2) 0 $ f (-2) 1 $ f (-2) 2 $ f (-2) 3+ $ f (-1) (-3) $ f (-1) (-2) $ f (-1) (-1) $ f (-1) 0 $ f (-1) 1 $ f (-1) 2 $ f (-1) 3+ $ f 0 (-3) $ f 0 (-2) $ f 0 (-1) $ f 0 0 $ f 0 1 $ f 0 2 $ f 0 3+ $ f 1 (-3) $ f 1 (-2) $ f 1 (-1) $ f 1 0 $ f 1 1 $ f 1 2 $ f 1 3+ $ f 2 (-3) $ f 2 (-2) $ f 2 (-1) $ f 2 0 $ f 2 1 $ f 2 2 $ f 2 3+ $ f 3 (-3) $ f 3 (-2) $ f 3 (-1) $ f 3 0 $ f 3 1 $ f 3 2 $ f 3 3+ $ zero+
Data/Array/Repa/Stencil/Template.hs view
@@ -81,14 +81,17 @@ let fnCoeffs = LamE [VarP ix'] $ CaseE (VarE (mkName "ix"))- $ [ Match (InfixP (InfixP z' (mkName ":.") (LitP (IntegerL oy))) (mkName ":.") (LitP (IntegerL ox)))+ $ [ Match (InfixP (InfixP z' (mkName ":.") (LitP (IntegerL oy)))+ (mkName ":.") (LitP (IntegerL ox))) (NormalB $ ConE (mkName "Just") `AppE` LitE (IntegerL v)) [] | (oy, ox, v) <- coeffs ] ++ [Match WildP (NormalB $ ConE (mkName "Nothing")) []] return- $ AppE (VarE (mkName "makeStencil2") `AppE` (LitE (IntegerL sizeX)) `AppE` (LitE (IntegerL sizeY)))+ $ AppE (VarE (mkName "makeStencil2") + `AppE` (LitE (IntegerL sizeX)) + `AppE` (LitE (IntegerL sizeY))) $ LetE [ PragmaD (InlineP (mkName "coeffs") (InlineSpec True False Nothing)) , ValD (VarP coeffs') (NormalB fnCoeffs) [] ] (VarE (mkName "coeffs"))
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2010, University of New South Wales.+Copyright (c) 2010-2012, University of New South Wales. All rights reserved. Redistribution and use in source and binary forms, with or without
repa.cabal view
@@ -1,5 +1,5 @@ Name: repa-Version: 2.2.0.1+Version: 3.0.0.1 License: BSD3 License-file: LICENSE Author: The DPH Team@@ -23,11 +23,12 @@ Library Build-Depends: - base == 4.4.*,+ base == 4.5.*, ghc-prim == 0.2.*, vector == 0.9.*,+ bytestring == 0.9.*, QuickCheck >= 2.3 && < 2.5,- template-haskell >= 2.5 && < 2.7+ template-haskell >= 2.5 && < 2.8 ghc-options: -Wall -fno-warn-missing-signatures@@ -35,32 +36,52 @@ -funbox-strict-fields -fcpr-off + extensions:+ NoMonomorphismRestriction+ ExplicitForAll+ EmptyDataDecls+ BangPatterns+ TypeFamilies+ MultiParamTypeClasses+ FlexibleInstances+ FlexibleContexts+ StandaloneDeriving+ ScopedTypeVariables+ PatternGuards+ Exposed-modules:- Data.Array.Repa+ Data.Array.Repa.Eval.Gang+ Data.Array.Repa.Operators.IndexSpace+ Data.Array.Repa.Operators.Interleave+ Data.Array.Repa.Operators.Mapping+ Data.Array.Repa.Operators.Reduction+ Data.Array.Repa.Operators.Selection+ Data.Array.Repa.Operators.Traversal+ Data.Array.Repa.Repr.ByteString+ Data.Array.Repa.Repr.Cursored+ Data.Array.Repa.Repr.Delayed+ Data.Array.Repa.Repr.ForeignPtr+ Data.Array.Repa.Repr.Partitioned+ Data.Array.Repa.Repr.Unboxed+ Data.Array.Repa.Repr.Undefined+ Data.Array.Repa.Repr.Vector+ Data.Array.Repa.Specialised.Dim2+ Data.Array.Repa.Stencil.Dim2+ Data.Array.Repa.Eval Data.Array.Repa.Index Data.Array.Repa.Shape Data.Array.Repa.Slice Data.Array.Repa.Stencil- Data.Array.Repa.Arbitrary- Data.Array.Repa.Properties- Data.Array.Repa.Specialised.Dim2+ Data.Array.Repa Other-modules:- Data.Array.Repa.Operators.IndexSpace- Data.Array.Repa.Operators.Traverse- Data.Array.Repa.Operators.Interleave- Data.Array.Repa.Operators.Mapping- Data.Array.Repa.Operators.Modify- Data.Array.Repa.Operators.Reduction- Data.Array.Repa.Operators.Select- Data.Array.Repa.Internals.Elt- Data.Array.Repa.Internals.Base- Data.Array.Repa.Internals.Gang- Data.Array.Repa.Internals.EvalChunked- Data.Array.Repa.Internals.EvalBlockwise- Data.Array.Repa.Internals.EvalCursored- Data.Array.Repa.Internals.EvalReduction- Data.Array.Repa.Internals.Forcing- Data.Array.Repa.Internals.Select+ Data.Array.Repa.Eval.Chunked+ Data.Array.Repa.Eval.Cursored+ Data.Array.Repa.Eval.Elt+ Data.Array.Repa.Eval.Fill+ Data.Array.Repa.Eval.Reduction+ Data.Array.Repa.Eval.Selection Data.Array.Repa.Stencil.Base Data.Array.Repa.Stencil.Template+ Data.Array.Repa.Base+