repa-array-4.1.0.1: Data/Repa/Array/Meta.hs
-- | 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)