packages feed

accelerate-examples-0.12.0.0: examples/quickcheck/Test/IndexSpace.hs

{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Test.IndexSpace where

import Prelude                                          as P
import Data.Label
import Data.Maybe
import Data.Typeable
import Test.QuickCheck
import Test.Framework
import Test.Framework.Providers.QuickCheck2

import Config
import Test.Base
import Arbitrary.Array                                  ( )
import Data.Array.Unboxed                               as IArray hiding ( Array )
import Data.Array.Accelerate                            as Acc
import Data.Array.Accelerate.Array.Sugar                ( newArray )


--
-- Forward permutation ---------------------------------------------------------
--

test_permute :: Options -> Test
test_permute opt = testGroup "permute" $ catMaybes
  [ testIntegralElt int8   (undefined :: Int8)
  , testIntegralElt int16  (undefined :: Int16)
  , testIntegralElt int32  (undefined :: Int32)
  , testIntegralElt int64  (undefined :: Int64)
  , testIntegralElt int8   (undefined :: Word8)
  , testIntegralElt int16  (undefined :: Word16)
  , testIntegralElt int32  (undefined :: Word32)
  , testIntegralElt int64  (undefined :: Word64)
  , testFloatingElt float  (undefined :: Float)
  , testFloatingElt double (undefined :: Double)
  ]
  where
    testIntegralElt :: forall e. (Elt e, Integral e, IsIntegral e, Arbitrary e) => (Options :-> Bool) -> e -> Maybe Test
    testIntegralElt ok _
      | P.not (get ok opt)      = Nothing
      | otherwise               = Just $ testGroup (show (typeOf (undefined :: e)))
          [ testProperty "histogram" (test_histogram Acc.fromIntegral P.fromIntegral :: Vector e -> Property)
          ]

    testFloatingElt :: forall e. (Elt e, RealFrac e, IsFloating e, Arbitrary e) => (Options :-> Bool) -> e -> Maybe Test
    testFloatingElt ok _
      | P.not (get ok opt)      = Nothing
      | otherwise               = Just $ testGroup (show (typeOf (undefined :: e)))
          [ testProperty "histogram" (test_histogram Acc.floor P.floor :: Vector e -> Property)
          ]

    test_histogram f g xs =
      sized $ \n -> run opt (histogramAcc n f xs) .==. histogramRef n g xs

    histogramAcc n f xs =
      let n'        = unit (constant n)
          xs'       = use xs
          zeros     = generate (constant (Z :. n)) (const 0)
          ones      = generate (shape xs')         (const 1)
      in
      permute (+) zeros (\ix -> index1 $ f (xs' Acc.! ix) `mod` the n') ones

    histogramRef n f xs =
      let arr :: UArray Int Int32
          arr =  accumArray (+) 0 (0, n-1) [ (f e `mod` n, 1) | e <- toList xs ]
      in
      fromIArray arr


--
-- Backward permutation --------------------------------------------------------
--

test_backpermute :: Options -> Test
test_backpermute opt = testGroup "backpermute" $ catMaybes
  [ testElt int8   (undefined :: Int8)
  , testElt int16  (undefined :: Int16)
  , testElt int32  (undefined :: Int32)
  , testElt int64  (undefined :: Int64)
  , testElt int8   (undefined :: Word8)
  , testElt int16  (undefined :: Word16)
  , testElt int32  (undefined :: Word32)
  , testElt int64  (undefined :: Word64)
  , testElt float  (undefined :: Float)
  , testElt double (undefined :: Double)
  ]
  where
    testElt :: forall e. (Elt e, Similar e, Arbitrary e) => (Options :-> Bool) -> e -> Maybe Test
    testElt ok _
      | P.not (get ok opt)  = Nothing
      | otherwise           = Just $ testGroup (show (typeOf (undefined::e)))
          [ testProperty "reverse"   (test_reverse   :: Array DIM1 e -> Property)
          , testProperty "transpose" (test_transpose :: Array DIM2 e -> Property)
          ]

    test_reverse xs   = run opt (reverseAcc xs)   .==. reverseRef xs
    test_transpose xs = run opt (transposeAcc xs) .==. transposeRef xs

    -- Reverse a vector
    --
    reverseRef xs = fromList (arrayShape xs) (reverse $ toList xs)
    reverseAcc xs =
      let xs'       = use xs
          n         = unindex1 $ shape xs'
      in
      backpermute (shape xs') (\ix -> index1 $ n - unindex1 ix - 1) xs'

    -- Transpose a 2D matrix
    --
    transposeAcc xs =
      let xs'       = use xs
          swap      = lift1 $ \(Z:.x:.y) -> Z:.y:.x :: Z :. Exp Int :. Exp Int
      in
      backpermute (swap (shape xs')) swap xs'

    transposeRef xs =
      let swap (Z:.x:.y)    = Z :. y :. x
      in  newArray (swap (arrayShape xs)) (\ix -> indexArray xs (swap ix))