-- | Meta arrays either generate elements on the fly, -- or wrap an inner array to provide an extra features. -- -- === Delayed layouts -- -- Delayed layouts represent the elements of an array by a function that -- computes those elements on demand. -- -- * `D` -- Functions from indices to elements. -- -- === Index-space layouts -- -- Index-space produce the corresponding index for each element of the array, -- rather than real data. They can be used to define an array shape -- without needing to provide element data. -- -- * `L` -- Linear spaces. -- -- * `RW` -- RowWise spaces. -- -- === Combining layouts -- -- Combining layouts combine existing layouts into new ones. -- -- * `W` -- Windowed arrays. -- -- * `E` -- Dense arrays. -- -- * `T2` -- Tupled arrays. -- -- === Array fusion -- -- Array fusion is achieved via the delayed (`D`) layout -- and the `computeS` function. For example: -- -- @ -- > import Data.Repa.Array -- > computeS U $ A.map (+ 1) $ A.map (* 2) $ fromList U [1 .. 100 :: Int] -- @ -- -- Lets look at the result of the first `map`: -- -- @ -- > :type A.map (* 2) $ fromList U [1 .. 100 :: Int] -- A.map (* 2) $ fromList U [1 .. 100 :: Int] -- :: Array (D U) Int -- @ -- -- In the type @Array (D U) Int@, the outer `D` indicates that the array -- is represented as a function that computes each element on demand. -- -- Applying a second `map` layers another element-producing function on top: -- -- @ -- > :type A.map (+ 1) $ A.map (* 2) $ fromList U [1 .. 100 :: Int] -- A.map (+ 1) $ A.map (* 2) $ fromList U [1 .. 100 :: Int] -- :: Array (D (D U)) Int -- @ -- -- At runtime, indexing into an array of the above type involves calling -- the outer @D@-elayed function, which calls the inner @D@-elayed function, -- which retrieves source data from the inner @U@-nboxed array. Although -- this works, indexing into a deep stack of delayed arrays can be quite -- expensive. -- -- To fully evaluate a delayed array, use the `computeS` function, -- which computes each element of the array sequentially. We pass @computeS@ -- the name of the desired result layout, in this case we use `U` to indicate -- an unboxed array of values: -- -- @ -- > :type computeS U $ A.map (+ 1) $ A.map (* 2) $ fromList U [1 .. 100 :: Int] -- computeS U $ A.map (+ 1) $ A.map (* 2) $ fromList U [1 .. 100 :: Int] -- :: Array U Int -- @ -- -- At runtime, each element of the result will be computed by first reading -- the source element, applying @(*2)@ to it, then applying @(+1)@ to it, -- then writing to the result array. Array \"fusion\" is achieved by the fact -- that result of applying @(*2)@ to an element is used directly, without -- writing it to an intermediate buffer. -- -- An added bonus is that during compilation, the GHC simplifier will inline -- the definitions of `map` and `computeS`, then eliminate the intermediate -- function calls. In the compiled code all intermediate values will be stored -- unboxed in registers, without any overhead due to boxing or laziness. -- -- When used correctly, array fusion allows Repa programs to run as fast as -- equivalents in C or Fortran. However, without fusion the programs typically -- run 10-20x slower (so remember apply `computeS` to delayed arrays). -- module Data.Repa.Array.Meta ( -- * Delayed arrays D(..) , fromFunction , toFunction , delay , map , D2(..) , delay2 , map2 -- * Linear spaces , L(..) , linear -- * RowWise spaces , RW(..) , rowWise -- * Windowed arrays , W(..) , Windowable (..) , windowed , entire , tail, init -- * Dense arrays , E (..) , vector , matrix , cube -- * Tupled arrays , T2(..) , tup2 , untup2) where import Data.Repa.Array.Meta.Delayed import Data.Repa.Array.Meta.Delayed2 import Data.Repa.Array.Meta.Dense import Data.Repa.Array.Meta.Linear import Data.Repa.Array.Meta.RowWise import Data.Repa.Array.Meta.Tuple import Data.Repa.Array.Meta.Window import Prelude hiding (map, tail, init)