accelerate-examples-0.12.0.0: examples/tests/primitives/Scatter.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
module Scatter where
import Random
import Data.List
import Data.Maybe
import Data.Array.ST
import Control.Monad
import Control.Applicative
import System.Random.MWC
import Data.Array.Unboxed
import Prelude as P
import Data.Array.Accelerate as Acc hiding ((!))
import qualified Data.Array.MArray as M
import qualified Data.HashTable.IO as Hash
-- Tests
-- -----
scatterAcc :: Vector Int -> Vector Float -> Vector Float -> Acc (Vector Float)
scatterAcc mapV defaultV inputV = Acc.scatter (use mapV) (use defaultV) (use inputV)
scatterIfAcc :: Vector Int -> Vector Int -> Vector Float -> Vector Float -> Acc (Vector Float)
scatterIfAcc mapV maskV defaultV inputV
= Acc.scatterIf (use mapV) (use maskV) evenAcc (use defaultV) (use inputV)
evenAcc :: Exp Int -> Exp Bool
evenAcc v = (v `mod` 2) ==* 0
scatterRef :: UArray Int Int -> UArray Int Float -> UArray Int Float -> UArray Int Float
scatterRef mapV defaultV inputV = runSTUArray $ do
mu <- M.thaw defaultV
forM_ (P.zip [0..] $ elems mapV) $ \(inIx, outIx) -> do
writeArray mu outIx (inputV ! inIx)
return mu
scatterIfRef :: UArray Int Int -> UArray Int Int -> UArray Int Float -> UArray Int Float -> UArray Int Float
scatterIfRef mapV maskV defaultV inputV = runSTUArray $ do
mu <- M.thaw defaultV
forM_ (P.zip [0..] $ elems mapV) $ \(inIx, outIx) -> do
when (evenRef (maskV ! inIx)) $ do
writeArray mu outIx (inputV ! inIx)
return mu
evenRef :: Int -> Bool
evenRef = even
-- Random
-- ------
uniqueRandomUArrayR :: GenIO -> (Int,Int) -> Int -> IO (UArray Int Int)
uniqueRandomUArrayR gen lim n = do
set <- Hash.new :: IO (Hash.BasicHashTable Int ())
let go !i !m | i >= n = return m
| otherwise = do
v <- uniformR lim gen
exists <- isJust <$> Hash.lookup set v
if exists
then go (i+1) m
else Hash.insert set v () >> go (i+1) (m+1)
n' <- go 0 0
listArray (0, n'-1) . P.map P.fst <$> Hash.toList set
-- Main
-- ----
run :: String -> Int -> IO (() -> UArray Int Float, () -> Acc (Vector Float))
run alg n = withSystemRandom $ \gen -> do
let m = 2 * n
mapV <- uniqueRandomUArrayR gen (0, m-1) n
mapV' <- convertUArray mapV
let n' = rangeSize (bounds mapV)
vec <- randomUArrayR (-1, 1) gen n'
vec' <- convertUArray vec
maskV <- randomUArrayR (0, n') gen n'
maskV' <- convertUArray maskV
defaultV <- randomUArrayR (-1, 1) gen m
defaultV' <- convertUArray defaultV
--
let go f g = return (run_ref f vec, run_acc g vec')
case alg of
"scatter" -> go (scatterRef mapV defaultV) (scatterAcc mapV' defaultV')
"scatter-if" -> go (scatterIfRef mapV maskV defaultV) (scatterIfAcc mapV' maskV' defaultV')
x -> error $ "unknown variant: " ++ x
where
{-# NOINLINE run_ref #-}
run_ref f xs () = f xs
run_acc f xs () = f xs