fdad621118fa786ca8669bf45c2d1844b50f79d3
[packages/dph.git] / dph-lifted-vseg / Data / Array / Parallel.hs
1 {-# LANGUAGE ParallelArrays #-}
2 {-# OPTIONS_GHC -fvectorise #-}
3
4 -- | User level interface to vectorised parallel arrays.
5 --
6 -- /WARNING:/ In the current implementation, the functionality provided in
7 -- this module is tied to the vectoriser pass of GHC, invoked by `-fvectorise`.
8 -- These functions will not work at all in unvectorised code. To operate on
9 -- parallel arrays in unvectorised code, use the functions in
10 -- "Data.Array.Parallel.PArray" and convert between array representations by
11 -- using `fromPArrayP` and `toPArrayP` from /vectorised/ code.
12 --
13 -- The semantic difference between standard Haskell arrays (aka "lazy
14 -- arrays") and parallel arrays (aka "strict arrays") is that the evaluation
15 -- of two different elements of a lazy array is independent, whereas in a
16 -- strict array either non or all elements are evaluated.
17 -- In other words, when a parallel array is evaluated to WHNF, all its elements
18 -- will be evaluated to WHNF. The name parallel array indicates that all array
19 -- elements may, in general, be evaluated to WHNF in parallel without any
20 -- need to resort to speculative evaluation. This parallel evaluation
21 -- semantics is also beneficial in the sequential case, as it facilitates
22 -- loop-based array processing as known from classic array-based languages,
23 -- such as Fortran.
24 --
25 -- The interface of this module is essentially a variant of the list
26 -- component of the Prelude, but also includes some functions (such as
27 -- permutations) that are not provided for lists. The following list of
28 -- operations are not supported on parallel arrays, as they would require the
29 -- infinite parallel arrays: `iterate', `repeat', and `cycle'.
30 --
31 -- UGLY HACK ALERT: Same ugly hack as in 'base:GHC.PArr'! We could do without in this module by
32 -- using the type synonym 'PArr' instead of '[::]', but that would lead to
33 -- significantly worse error message for end users.
34 --
35 module Data.Array.Parallel
36 ( module Data.Array.Parallel.Prelude
37
38 -- * Conversions
39 , fromPArrayP
40 , toPArrayP
41 , fromNestedPArrayP
42
43 -- * Constructors
44 , emptyP
45 , singletonP
46 , replicateP
47 , appendP, (+:+)
48 , concatP
49
50 -- * Projections
51 , lengthP
52 , indexP, (!:)
53 , sliceP
54
55 -- * Traversals
56 , mapP
57 , zipWithP
58
59 -- * Filtering
60 , filterP
61
62 -- * Ziping and Unzipping
63 , zipP
64 , unzipP)
65 where
66 -- Primitives needed by the vectoriser.
67 import Data.Array.Parallel.Prim ()
68
69 import Data.Array.Parallel.PArr
70 import Data.Array.Parallel.Prelude
71 import Data.Array.Parallel.Prelude.Int
72 import Data.Array.Parallel.Lifted
73 import Data.Array.Parallel.PArray.PData.Base (PArray(..))
74 import Prelude hiding (Int)
75
76
77 -------------------------------------------------------------------------------
78 -- IMPORTANT:
79 -- We only define the signatures of operations on parallel arrays, and give
80 -- and bodies that convince GHC that these functions don't just diverge.
81 -- The vectoriser rewrites them to entirely the code given in the VECTORISE
82 -- pragmas.
83 --
84 -- The functions must be eta-expanded, so the right of the binding is
85 -- something of the final return type. The vectoriser takes the type of the
86 -- body to determine what PA dictionary to pass.
87 --
88 -- We also put bangs (!) on the arguments to indicate to the GHC strictness
89 -- analyser that these paramters will really be used in the vectorised code.
90 --
91 -- This won't work: mapP = undefined
92 -- You need this: mapP !_ !_ = [::]
93 --
94 -- The bindings have NOINLINE pragmas because we never want to use the
95 -- actual body code (because it's fake anyway).
96 --
97
98 -- Conversions ----------------------------------------------------------------
99 -- | O(1). Convert between `PArray` and [::] array representations.
100 fromPArrayP :: PArray a -> [:a:]
101 fromPArrayP !_ = emptyP
102 {-# NOINLINE fromPArrayP #-}
103 {-# VECTORISE fromPArrayP = fromPArrayPP #-}
104
105
106 -- | O(1). Convert between `PArray` and [::] array representations.
107 toPArrayP :: [:a:] -> PArray a
108 toPArrayP !_ = PArray 0# (error "toPArrayP: unvectorised")
109 {-# NOINLINE toPArrayP #-}
110 {-# VECTORISE toPArrayP = toPArrayPP #-}
111
112
113 -- | O(1). Convert between `PArray` and [::] array representations.
114 fromNestedPArrayP :: PArray (PArray a) -> [:[:a:]:]
115 fromNestedPArrayP !_ = emptyP
116 {-# NOINLINE fromNestedPArrayP #-}
117 {-# VECTORISE fromNestedPArrayP = fromNestedPArrayPP #-}
118
119
120 -- Constructors ---------------------------------------------------------------
121 -- | Construct an empty array, with no elements.
122 emptyP :: [:a:]
123 emptyP = emptyPArr
124 {-# NOINLINE emptyP #-}
125 {-# VECTORISE emptyP = emptyPP #-}
126
127
128 -- | Construct an array with a single element.
129 singletonP :: a -> [:a:]
130 singletonP = singletonPArr
131 {-# NOINLINE singletonP #-}
132 {-# VECTORISE singletonP = singletonPP #-}
133
134
135 -- | Construct an array by replicating the given element some number of times.
136 replicateP :: Int -> a -> [:a:]
137 replicateP = replicatePArr
138 {-# NOINLINE replicateP #-}
139 {-# VECTORISE replicateP = replicatePP #-}
140
141
142 -- | Append two arrays.
143 appendP, (+:+) :: [:a:] -> [:a:] -> [:a:]
144 (+:+) !_ !_ = emptyP
145 {-# NOINLINE (+:+) #-}
146 {-# VECTORISE (+:+) = appendPP #-}
147
148 appendP !_ !_ = emptyP
149 {-# NOINLINE appendP #-}
150 {-# VECTORISE appendP = appendPP #-}
151
152
153 -- | Concatenate an array of arrays.
154 concatP :: [:[:a:]:] -> [:a:]
155 concatP !_ = emptyP
156 {-# NOINLINE concatP #-}
157 {-# VECTORISE concatP = concatPP #-}
158
159
160 -- Projections ----------------------------------------------------------------
161 -- | Take the length of an array.
162 lengthP :: [:a:] -> Int
163 lengthP = lengthPArr
164 {-# NOINLINE lengthP #-}
165 {-# VECTORISE lengthP = lengthPP #-}
166
167 -- | Lookup a single element from the source array.
168 indexP, (!:) :: [:a:] -> Int -> a
169 (!:) = indexPArr
170 {-# NOINLINE (!:) #-}
171 {-# VECTORISE (!:) = indexPP #-}
172
173 indexP = indexPArr
174 {-# NOINLINE indexP #-}
175 {-# VECTORISE indexP = indexPP #-}
176
177
178 -- | Extract a slice from an array.
179 sliceP :: Int -> Int -> [:a:] -> [:a:]
180 sliceP !_ !_ !_ = emptyP
181 {-# NOINLINE sliceP #-}
182 {-# VECTORISE sliceP = slicePP #-}
183
184
185 -- Traversals -----------------------------------------------------------------
186 -- | Apply a worker function to every element of an array.
187 mapP :: (a -> b) -> [:a:] -> [:b:]
188 mapP !_ !_ = emptyP
189 {-# NOINLINE mapP #-}
190 {-# VECTORISE mapP = mapPP #-}
191
192 -- | Apply a worker function to every pair of two arrays.
193 zipWithP :: (a -> b -> c) -> [:a:] -> [:b:] -> [:c:]
194 zipWithP !_ !_ !_ = emptyP
195 {-# NOINLINE zipWithP #-}
196 {-# VECTORISE zipWithP = zipWithPP #-}
197
198
199 -- Filtering -----------------------------------------------------------------
200 -- | Filter an array, keeping only those elements that match the given predicate.
201 filterP :: (a -> Bool) -> [:a:] -> [:a:]
202 filterP !_ !_ = emptyP
203 {-# NOINLINE filterP #-}
204 {-# VECTORISE filterP = filterPP #-}
205
206
207 -- Zipping and Unzipping ------------------------------------------------------
208 -- | Zip a pair of arrays into an array of pairs.
209 zipP :: [:a:] -> [:b:] -> [:(a, b):]
210 zipP !_ !_ = emptyP
211 {-# NOINLINE zipP #-}
212 {-# VECTORISE zipP = zipPP #-}
213
214
215 -- | Unzip an array of pairs into a pair of arrays.
216 unzipP :: [:(a, b):] -> ([:a:], [:b:])
217 unzipP !_ = (emptyP, emptyP)
218 {-# NOINLINE unzipP #-}
219 {-# VECTORISE unzipP = unzipPP #-}