ac03aee4406fe9342ea97466399c341c1d0ea991
[packages/dph.git] / dph-lifted-vseg / Data / Array / Parallel / PArray / PData / Nested.hs
1 {-# LANGUAGE
2 CPP,
3 BangPatterns,
4 TypeFamilies,
5 FlexibleInstances, FlexibleContexts,
6 MultiParamTypeClasses,
7 StandaloneDeriving,
8 ExistentialQuantification,
9 UndecidableInstances,
10 ParallelListComp #-}
11
12 {-# OPTIONS -fno-spec-constr #-}
13
14 #include "fusion-phases.h"
15
16 module Data.Array.Parallel.PArray.PData.Nested
17 ( PData(..)
18 , mkPNested
19 , pnested_vsegids
20 , pnested_pseglens
21 , pnested_psegstarts
22 , pnested_psegsrcids
23
24 -- * Testing functions. TODO: move these somewhere else
25 , validIx
26 , validLen
27 , validBool
28
29 -- * Functions derived from PR primops
30 , concatPR
31 , unconcatPR
32 , concatlPR
33 , slicelPR
34 , appendlPR)
35 where
36 import Data.Array.Parallel.PArray.PData.Base
37 import Data.Array.Parallel.Base
38
39 import qualified Data.IntSet as IS
40 import qualified Data.Array.Parallel.Unlifted as U
41 import qualified Data.Vector as V
42 import qualified Data.Vector.Unboxed as VU
43 import Text.PrettyPrint
44
45
46 -- Nested arrays --------------------------------------------------------------
47
48 data instance PData Int
49 = PInt (U.Array Int)
50
51 -- TODO: Using plain V.Vector for the psegdata field means that operations on
52 -- this field aren't parallelised. In particular, when we append two
53 -- psegdata fields during appPR or combinePR this runs sequentially
54 --
55 data instance PData (PArray a)
56 = PNested
57 { pnested_uvsegd :: !U.VSegd
58 -- ^ Virtual segmentation descriptor.
59 -- Defines a virtual nested array based on physical data.
60
61 , pnested_psegdata :: !(V.Vector (PData a)) }
62
63 -- TODO: we shouldn't be using these directly.
64 pnested_vsegids = U.takeVSegidsOfVSegd . pnested_uvsegd
65 pnested_pseglens = U.lengthsSSegd . U.takeSSegdOfVSegd . pnested_uvsegd
66 pnested_psegstarts = U.startsSSegd . U.takeSSegdOfVSegd . pnested_uvsegd
67 pnested_psegsrcids = U.sourcesSSegd . U.takeSSegdOfVSegd . pnested_uvsegd
68
69 mkPNested vsegids pseglens psegstarts psegsrcids psegdata
70 = PNested
71 (U.mkVSegd vsegids
72 $ U.mkSSegd psegstarts psegsrcids
73 $ U.lengthsToSegd pseglens)
74 psegdata
75
76 -- | Pretty print the physical representation of a nested array
77 instance PprPhysical (PData a) => PprPhysical (PData (PArray a)) where
78 pprp (PNested uvsegd pdata)
79 = text "PNested"
80 $+$ (nest 4 $ vcat
81 $ pprp uvsegd
82 : [ int n <> colon <> text " " <> pprp pd
83 | n <- [0..]
84 | pd <- V.toList pdata])
85
86
87 instance (PR a, PprVirtual (PData a)) => PprVirtual (PData (PArray a)) where
88 pprv arr
89 = lbrack <> hcat (punctuate comma (map pprv $ V.toList $ toVectorPR arr)) <> rbrack
90
91
92 deriving instance Show (PData a)
93 => Show (PData (PArray a))
94
95
96 -- Testing --------------------------------------------------------------------
97 -- TODO: shift this stuff into dph-base
98 validIx :: String -> Int -> Int -> Bool
99 validIx str len ix
100 = check str len ix (ix >= 0 && ix < len)
101
102 validLen :: String -> Int -> Int -> Bool
103 validLen str len ix
104 = checkLen str len ix (ix >= 0 && ix <= len)
105
106 -- TODO: slurp debug flag from base
107 validBool :: String -> Bool -> Bool
108 validBool str b
109 = if b then True
110 else error $ "validBool check failed -- " ++ str
111
112
113 -- Constructors ---------------------------------------------------------------
114 -- | Flatten a nested array into its segment descriptor and data.
115 --
116 -- WARNING: Doing this to replicated arrays can cause index overflow.
117 -- See the warning in `unsafeMaterializeUVSegd`.
118 --
119 unsafeFlattenPR :: PR a => PData (PArray a) -> (U.Segd, PData a)
120 {-# INLINE unsafeFlattenPR #-}
121 unsafeFlattenPR arr@(PNested uvsegd _)
122 = ( U.demoteToSegdOfVSegd uvsegd
123 , concatPR arr)
124
125
126 instance U.Elt (Int, Int, Int)
127
128 -- PR Instances ---------------------------------------------------------------
129 instance PR a => PR (PArray a) where
130
131 -- TODO: make this check all sub arrays as well
132 -- TODO: ensure that all psegdata arrays are referenced from some psegsrc.
133 -- TODO: shift segd checks into associated modules.
134 {-# INLINE_PDATA validPR #-}
135 validPR arr
136 = let
137 vsegids = pnested_vsegids arr
138 pseglens = pnested_pseglens arr
139 psegstarts = pnested_psegstarts arr
140 psegsrcs = pnested_psegsrcids arr
141 psegdata = pnested_psegdata arr
142
143
144 -- The lengths of the pseglens, psegstarts and psegsrcs fields must all be the same
145 fieldLensOK
146 = validBool "nested array field lengths not identical"
147 $ and
148 [ U.length psegstarts == U.length pseglens
149 , U.length psegsrcs == U.length pseglens ]
150
151 -- Every vseg must reference a valid pseg.
152 vsegsRefOK
153 = validBool "nested array vseg doesn't ref pseg"
154 $ U.and
155 $ U.map (\vseg -> vseg < U.length pseglens) vsegids
156
157
158 -- Every pseg source id must point to a flat data array
159 psegsrcsRefOK
160 = validBool "nested array psegsrc doesn't ref flat array"
161 $ U.and
162 $ U.map (\srcid -> srcid < V.length psegdata) psegsrcs
163
164 -- Every physical segment must be a valid slice of the corresponding flat array.
165 --
166 -- We allow psegs with len 0, start 0 even if the flat array is empty.
167 -- This occurs with [ [] ].
168 --
169 -- As a generalistion of above, we allow segments with len 0, start <= srclen.
170 -- This occurs when there is an empty array as the last segment
171 -- For example:
172 -- [ [5, 4, 3, 2] [ ] ].
173 -- PNested vsegids: [0,1]
174 -- pseglens: [4,0]
175 -- psegstarts: [0,4] -- last '4' here is <= length of flat array
176 -- psegsrcs: [0,0]
177 -- PInt [5, 4, 3, 2]
178 --
179 psegSlicesOK
180 = validBool "nested array pseg slices are invalid"
181 $ U.and
182 $ U.zipWith3
183 (\len start srcid
184 -> let srclen = lengthPR (psegdata V.! srcid)
185 in and [ (len == 0 && start <= srclen)
186 || validIx "nested array psegstart " srclen start
187 , validLen "nested array pseglen " srclen (start + len)])
188 pseglens psegstarts psegsrcs
189
190 -- Every pseg must be referenced by some vseg.
191 vsegs = IS.fromList $ U.toList vsegids
192 psegsReffedOK
193 = validBool "nested array pseg not reffed by vseg"
194 $ (U.length pseglens == 0)
195 || (U.and $ U.map (flip IS.member vsegs)
196 $ U.enumFromTo 0 (U.length pseglens - 1))
197
198 in and [ fieldLensOK
199 , vsegsRefOK
200 , psegsrcsRefOK
201 , psegSlicesOK
202 , psegsReffedOK ]
203
204
205 {-# INLINE_PDATA emptyPR #-}
206 emptyPR = PNested U.emptyVSegd V.empty
207
208
209 {-# INLINE_PDATA nfPR #-}
210 nfPR = error "nfPR[PArray]: not defined yet"
211
212
213 {-# INLINE_PDATA lengthPR #-}
214 lengthPR (PNested uvsegd _)
215 = U.lengthOfVSegd uvsegd
216
217
218 -- When replicating an array we use the source as the single physical
219 -- segment, then point all the virtual segments to it.
220 {-# NOINLINE replicatePR #-}
221 replicatePR c (PArray n darr)
222 = checkNotEmpty "replicatePR[PArray]" c
223 $ let -- Physical segment descriptor contains a single segment.
224 ussegd = U.singletonSSegd n
225
226 -- All virtual segments point to the same physical segment.
227 uvsegd = U.mkVSegd (U.replicate c 0) ussegd
228
229 in PNested uvsegd (V.singleton darr)
230
231
232 -- For segmented replicates, we just replicate the vsegids field.
233 -- TODO: Does replicate_s really need the whole segd,
234 -- or could we get away without creating the indices field?
235 {-# INLINE_PDATA replicatesPR #-}
236 replicatesPR lens (PNested uvsegd pdata)
237 = let segd = U.lengthsToSegd lens
238 in PNested (U.updateVSegsOfVSegd (\vsegids -> U.replicate_s segd vsegids) uvsegd)
239 pdata
240
241
242 -- To index into a nested array, first determine what segment the index
243 -- corresponds to, and extract that as a slice from that physical array.
244 {-# INLINE_PDATA indexPR #-}
245 indexPR (PNested uvsegd pdata) ix
246 | (pseglen, psegstart, psegsrcid) <- U.getSegOfVSegd uvsegd ix
247 = let !psrc = pdata `V.unsafeIndex` psegsrcid
248 !pdata' = extractPR psrc psegstart pseglen
249 in PArray pseglen pdata'
250
251
252 -- Lifted indexing
253 --
254 -- source
255 -- VIRT [ [[0],[1,2,3]], [[0],[1,2,3]]
256 -- , [[5,6,7,8,9]], [[5,6,7,8,9]], [[5,6,7,8,9]]
257 -- , [[7,8,9,10,11,12,13],[0],[1,2,3],[0],[5,6,7,8,9],[0],[1,2,3]] ]
258 --
259 -- PHYS PNested
260 -- UVSegd vsegids: [0,0,1,1,1,2]
261 -- USSegd lengths: [2,1,7]
262 -- indices: [0,2,3]
263 -- srcids: [0,0,0]
264 -- 0: PNested
265 -- UVSegd vsegids: [0,1,2,3,4,5,6,7,8,9]
266 -- USSegd lengths: [1,3,5,7,1,3,1,5,1,3]
267 -- indices: [0,1,0,0,7,8,11,12,17,18]
268 -- srcids: [0,0,1,2,2,2,2,2,2,2]
269 -- 0: PInt [0,1,2,3]
270 -- 1: PInt [5,6,7,8,9]
271 -- 2: PInt [7,8,9,10,11,12,13,0,1,2,3,0,5,6,7,8,9,0,1,2,3]
272 --
273 -- indexl with [1, 0, 0, 0, 0, 4]
274 -- VIRT [[1,2,3],[0],[5,6,7,8,9],[5,6,7,8,9],[5,6,7,8,9],[1,2,3]]
275 -- PHYS PNested
276 -- UVSegd vsegids: [0,1,2,3,4,5]
277 -- USSegd lengths: [3,1,5,5,5,3]
278 -- indices: [1,0,0,0,0,8]
279 -- srcids: [0,0,1,1,1,2]
280 -- 0: PInt [0,1,2,3]
281 -- 1: PInt [5,6,7,8,9]
282 -- 2: PInt [7,8,9,10,11,12,13,0,1,2,3,0,5,6,7,8,9,0,1,2,3]
283 --
284 {-# INLINE_PDATA indexlPR #-}
285 indexlPR c (PNested uvsegd pdata) (PInt ixs)
286 = let
287 -- See Note: psrcoffset
288 psrcoffset = V.prescanl (+) 0 $ V.map (V.length . pnested_psegdata) pdata
289
290 -- length, start and srcid of the segments we're returning.
291 -- Note that we need to offset the srcid
292 seginfo :: U.Array (Int, Int, Int)
293 seginfo
294 = U.zipWith (\segid ix ->
295 let (_, segstart, segsrcid) = U.getSegOfVSegd uvsegd segid
296 (PNested uvsegd2 _) = pdata V.! segsrcid
297 (len, start, srcid) = U.getSegOfVSegd uvsegd2 (segstart + ix)
298 in (len, start, srcid + (psrcoffset V.! segsrcid)))
299 (U.enumFromTo 0 (c - 1))
300 ixs
301
302 (pseglens', psegstarts', psegsrcs')
303 = U.unzip3 seginfo
304
305 -- TODO: check that doing lengthsToSegd won't cause overflow
306 uvsegd' = U.promoteSSegdToVSegd
307 $ U.mkSSegd psegstarts' psegsrcs'
308 $ U.lengthsToSegd pseglens'
309
310 -- All flat data arrays in the sources go into the result.
311 psegdata' = V.concat $ V.toList $ V.map pnested_psegdata pdata
312
313 in PNested uvsegd' psegdata'
314
315
316 -- To extract a range of elements from a nested array, perform the extract
317 -- on the vsegids field. The `updateVSegsOfUVSegd` function will then filter
318 -- out all of the psegs that are no longer reachable from the new vsegids.
319 {-# NOINLINE extractPR #-}
320 extractPR (PNested uvsegd pdata) start len
321 = PNested (U.updateVSegsOfVSegd (\vsegids -> U.extract vsegids start len) uvsegd)
322 pdata
323
324
325 -- TODO: cleanup pnested projections
326 -- use getSegOfUVSegd like in indexlPR
327
328 -- [Note: psrcoffset]
329 -- ~~~~~~~~~~~~~~~~~~
330 -- As all the flat data arrays in the sources are present in the result array,
331 -- we need to offset the psegsrcs field when combining multiple sources.
332 --
333 -- Exaple
334 -- Source Arrays:
335 -- arr0 ...
336 -- psrcids : [0, 0, 0, 1, 1]
337 -- psegdata : [PInt xs1, PInt xs2]
338 --
339 -- arr1 ...
340 -- psrcids : [0, 0, 1, 1, 2, 2, 2]
341 -- psegdata : [PInt ys1, PInt ys2, PInt ys3]
342 --
343 -- Result Array:
344 -- psrcids : [...]
345 -- psegdata : [PInt xs1, PInt xs2, PInt ys1, PInt ys2, PInt ys3]
346 --
347 -- Note that references to flatdata arrays [0, 1, 2] in arr1 need to be offset
348 -- by 2 (which is length arr0.psegdata) to refer to the same flat data arrays
349 -- in the result.
350 --
351 -- We encode these offsets in the psrcoffset vector:
352 -- psrcoffset : [0, 2]
353 --
354 {-# NOINLINE extractsPR #-}
355 extractsPR arrs ussegd
356 = let segsrcs = U.sourcesSSegd ussegd
357 segstarts = U.startsSSegd ussegd
358 seglens = U.lengthsSSegd ussegd
359
360 vsegids_src = uextracts (V.map pnested_vsegids arrs) segsrcs segstarts seglens
361
362 srcids' = U.replicate_s (U.lengthsToSegd seglens) segsrcs
363
364 -- See Note: psrcoffset
365 psrcoffset = V.prescanl (+) 0 $ V.map (V.length . pnested_psegdata) arrs
366
367 -- Unpack the lens and srcids arrays so we don't need to
368 -- go though all the segment descriptors each time.
369 !arrs_pseglens = V.map pnested_pseglens arrs
370 !arrs_psegstarts = V.map pnested_psegstarts arrs
371 !arrs_psegsrcids = V.map pnested_psegsrcids arrs
372
373 -- Function to get one element of the result.
374 {-# INLINE get #-}
375 get srcid vsegid
376 = let !pseglen = (arrs_pseglens `V.unsafeIndex` srcid) `VU.unsafeIndex` vsegid
377 !psegstart = (arrs_psegstarts `V.unsafeIndex` srcid) `VU.unsafeIndex` vsegid
378 !psegsrcid = (arrs_psegsrcids `V.unsafeIndex` srcid) `VU.unsafeIndex` vsegid
379 + psrcoffset `V.unsafeIndex` srcid
380 in (pseglen, psegstart, psegsrcid)
381
382 (pseglens', psegstarts', psegsrcs')
383 = U.unzip3 $ U.zipWith get srcids' vsegids_src
384
385 -- All flat data arrays in the sources go into the result.
386 psegdata' = V.concat $ V.toList $ V.map pnested_psegdata arrs
387
388 -- Build the result segment descriptor.
389 vsegd' = U.promoteSSegdToVSegd
390 $ U.mkSSegd psegstarts' psegsrcs'
391 $ U.lengthsToSegd pseglens'
392
393 in PNested vsegd' psegdata'
394
395
396 -- Append nested arrays by appending the segment descriptors,
397 -- and putting all physical arrays in the result.
398 {-# INLINE_PDATA appendPR #-}
399 appendPR (PNested uvsegd1 pdata1) (PNested uvsegd2 pdata2)
400 = PNested (U.appendVSegd
401 uvsegd1 (V.length pdata1)
402 uvsegd2 (V.length pdata2))
403 (pdata1 V.++ pdata2)
404
405
406 -- Performing segmented append requires segments from the physical arrays to
407 -- be interspersed, so we need to copy data from the second level of nesting.
408 --
409 -- In the implementation we can safely flatten out replication in the vsegs
410 -- because the source program result would have this same physical size
411 -- anyway. Once this is done we use copying segmented append on the flat
412 -- arrays, and then reconstruct the segment descriptor.
413 --
414 {- INLINE_PDATA appendsPR #-}
415 appendsPR rsegd segd1 xarr segd2 yarr
416 = let (xsegd, xs) = unsafeFlattenPR xarr
417 (ysegd, ys) = unsafeFlattenPR yarr
418
419 xsegd' = U.lengthsToSegd
420 $ U.sum_s segd1 (U.lengthsSegd xsegd)
421
422 ysegd' = U.lengthsToSegd
423 $ U.sum_s segd2 (U.lengthsSegd ysegd)
424
425 segd' = U.lengthsToSegd
426 $ U.append_s rsegd segd1 (U.lengthsSegd xsegd)
427 segd2 (U.lengthsSegd ysegd)
428
429 in PNested (U.promoteSegdToVSegd segd')
430 (V.singleton
431 $ appendsPR (U.plusSegd xsegd' ysegd')
432 xsegd' xs
433 ysegd' ys)
434
435
436 -- Pack the vsegids to determine which of the vsegs are present in the result.
437 -- eg tags: [0 1 1 1 0 0 0 0 1 0 0 0 0 1 0 1 0 1 1] tag = 1
438 -- vsegids: [0 0 1 1 2 2 2 2 3 3 4 4 4 5 5 5 5 6 6]
439 -- => vsegids_packed: [ 0 1 1 3 5 5 6 6]
440 --
441 {-# INLINE_PDATA packByTagPR #-}
442 packByTagPR (PNested uvsegd pdata) tags tag
443 = PNested (U.updateVSegsOfVSegd (\vsegids -> U.packByTag vsegids tags tag) uvsegd)
444 pdata
445
446
447 -- Combine nested arrays by combining the segment descriptors,
448 -- and putting all physical arrays in the result.
449 {-# INLINE_PDATA combine2PR #-}
450 combine2PR sel2 (PNested uvsegd1 pdata1) (PNested uvsegd2 pdata2)
451 = PNested (U.combine2VSegd sel2
452 uvsegd1 (V.length pdata1)
453 uvsegd2 (V.length pdata2))
454 (pdata1 V.++ pdata2)
455
456
457 -- Conversions ----------------------
458 {-# INLINE_PDATA fromVectorPR #-}
459 fromVectorPR xx
460 | V.length xx == 0 = emptyPR
461 | otherwise
462 = let segd = U.lengthsToSegd $ U.fromList $ V.toList $ V.map lengthPA xx
463 in mkPNested
464 (U.enumFromTo 0 (V.length xx - 1))
465 (U.lengthsSegd segd)
466 (U.indicesSegd segd)
467 (U.replicate (V.length xx) 0)
468 (V.singleton (V.foldl1 appendPR $ V.map unpackPA xx))
469
470
471 {-# INLINE_PDATA toVectorPR #-}
472 toVectorPR arr
473 = V.generate (U.length (pnested_vsegids arr))
474 $ indexPR arr
475
476
477 fromUArrayPR = error "fromUArrayPR[PArray]: not defined yet"
478 toUArrayPR = error "toUArrayPR[PArray]: not defined et"
479
480
481 -------------------------------------------------------------------------------
482
483 -- | O(len result). Concatenate a nested array.
484 --
485 -- This physically performs a 'gather' operation, whereby array data is copied
486 -- through the index-space transformation defined by the segment descriptor.
487 -- We need to do this because discarding the segment descriptor means that we
488 -- can no-longer represent the data layout of the logical array other than by
489 -- physically creating it.
490 --
491 -- The segment descriptor keeps track of the layout of the data, and if it
492 -- knows that the segments are already in a single, contiguous array with
493 -- no sharing then we can just return that array directly in O(1) time.
494 --
495 -- IMPORTANT:
496 -- In the case where there is sharing between segments, or they are scattered
497 -- through multiple arrays, only outer-most two levels of nesting are physically
498 -- merged. The data for lower levels is not touched. This ensures that concat
499 -- has complexity proportional to the length of the result array, instead
500 -- of the total number of elements within it.
501 --
502 concatPR :: PR a => PData (PArray a) -> PData a
503 {-# NOINLINE concatPR #-}
504 concatPR (PNested vsegd pdatas)
505 -- If we know that the segments are in a single contiguous array,
506 -- and there is no sharing between them, then we can just return
507 -- that array directly.
508 | U.isManifestVSegd vsegd
509 , U.isContiguousVSegd vsegd
510 , V.length pdatas == 1
511 = pdatas `V.unsafeIndex` 0
512
513 -- Otherwise we have to pull all the segments through the index
514 -- space transform defined by the vsegd, which copies them
515 -- into a single contiguous array.
516 | otherwise
517 = let -- Flatten out the virtualization of the vsegd so that we have
518 -- a description of each segment individually.
519 ussegd = U.demoteToSSegdOfVSegd vsegd
520
521 -- Copy these segments into a new array.
522 in extractsPR pdatas ussegd
523
524
525 -- | Build a nested array given a single flat data vector,
526 -- and a template nested array that defines the segmentation.
527 --
528 -- Although the template nested array may be using vsegids to describe
529 -- internal sharing, the provided data array has manifest elements
530 -- for every segment. Because of this we need flatten out the virtual
531 -- segmentation of the template array.
532 --
533
534 unconcatPR :: PR a => PData (PArray a) -> PData b -> PData (PArray b)
535 {-# NOINLINE unconcatPR #-}
536 unconcatPR (PNested vsegd pdatas) arr
537 = let
538 -- Get the lengths of all the vsegs individually.
539 !vseglens = U.takeLengthsOfVSegd vsegd
540
541 -- Rebuild the segd based on these lengths,
542 -- the resulting segd contains no sharing.
543 !vsegd' = U.promoteSegdToVSegd
544 $ U.lengthsToSegd vseglens
545
546 in PNested vsegd' (V.singleton arr)
547
548
549 -- | Lifted concat.
550 -- Both arrays must contain the same number of elements.
551 concatlPR :: PR a => PData (PArray (PArray a)) -> PData (PArray a)
552 {-# INLINE concatlPR #-}
553 concatlPR arr
554 = let (segd1, darr1) = unsafeFlattenPR arr
555 (segd2, darr2) = unsafeFlattenPR darr1
556
557 segd' = U.mkSegd (U.sum_s segd1 (U.lengthsSegd segd2))
558 (U.bpermute (U.indicesSegd segd2) (U.indicesSegd segd1))
559 (U.elementsSegd segd2)
560
561 in PNested (U.promoteSegdToVSegd segd')
562 (V.singleton darr2)
563
564
565 -- | Lifted append.
566 -- Both arrays must contain the same number of elements.
567 appendlPR :: PR a => PData (PArray a) -> PData (PArray a) -> PData (PArray a)
568 {-# NOINLINE appendlPR #-}
569 appendlPR arr1 arr2
570 = let (segd1, darr1) = unsafeFlattenPR arr1
571 (segd2, darr2) = unsafeFlattenPR arr2
572 segd' = U.plusSegd segd1 segd2
573 in PNested (U.promoteSegdToVSegd segd' )
574 (V.singleton
575 $ appendsPR segd' segd1 darr1 segd2 darr2)
576
577
578 -- | Extract some slices from some arrays.
579 -- The arrays of starting indices and lengths must themselves
580 -- have the same length.
581 -- TODO: cleanup pnested projections
582 slicelPR
583 :: PR a
584 => PData Int -- ^ starting indices of slices
585 -> PData Int -- ^ lengths of slices
586 -> PData (PArray a) -- ^ arrays to slice
587 -> PData (PArray a)
588 {-# NOINLINE slicelPR #-}
589 slicelPR (PInt sliceStarts) (PInt sliceLens) arr
590
591 = let segs = U.length vsegids
592 vsegids = pnested_vsegids arr
593 psegstarts = pnested_psegstarts arr
594 psegsrcs = pnested_psegsrcids arr
595 psegdata = pnested_psegdata arr
596 in
597 mkPNested
598 (U.enumFromTo 0 (segs - 1))
599 sliceLens
600 (U.zipWith (+) (U.bpermute psegstarts vsegids) sliceStarts)
601 (U.bpermute psegsrcs vsegids)
602 psegdata
603