packages feed

accelerate-examples-1.1.0.0: examples/nofib/Test/Issues/Issue264.hs

{-# LANGUAGE ConstraintKinds     #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators       #-}
-- https://github.com/AccelerateHS/accelerate/issues/264
--

module Test.Issues.Issue264 (test_issue264)
  where

import Config
import Test.Framework
import Test.Framework.Providers.QuickCheck2
import Test.QuickCheck                                          hiding ( (.&.) )
import QuickCheck.Arbitrary.Array                               ()

import Prelude                                                  as P
import Data.Bits                                                as P
import Data.Label
import Data.Maybe
import Data.Typeable
import Data.Array.Accelerate                                    as A
import Data.Array.Accelerate.Data.Bits                          as A
import Data.Array.Accelerate.Examples.Internal                  as A

import qualified Data.Array.Accelerate.Array.Sugar              as S
import qualified Data.Array.Accelerate.Array.Representation     as R


test_issue264 :: Backend -> Config -> Test
test_issue264 backend opt
  = testGroup "264"
  $ catMaybes
  [ testBool
  , testIntegralElt configInt8   (undefined :: Int8)
  , testIntegralElt configInt16  (undefined :: Int16)
  , testIntegralElt configInt32  (undefined :: Int32)
  , testIntegralElt configInt64  (undefined :: Int64)
  , testIntegralElt configWord8  (undefined :: Word8)
  , testIntegralElt configWord16 (undefined :: Word16)
  , testIntegralElt configWord32 (undefined :: Word32)
  , testIntegralElt configWord64 (undefined :: Word64)
  , testFloatingElt configFloat  (undefined :: Float)
  , testFloatingElt configDouble (undefined :: Double)
  ]
  where
    testBool :: Maybe Test
    testBool = Just $ testGroup "Bool"
      [ testProperty "not.not"        (test_notnot    :: Vector Bool -> Property)
      , testProperty "not(x&&y)"      (test_andnot    :: Vector Bool -> Vector Bool -> Property)
      , testProperty "not(x||y)"      (test_ornot     :: Vector Bool -> Vector Bool -> Property)
      , testProperty "not(not(x&&y))" (test_andnotnot :: Vector Bool -> Vector Bool -> Property)
      , testProperty "not(not(x||y))" (test_ornotnot  :: Vector Bool -> Vector Bool -> Property)
      ]

    testIntegralElt :: forall a. (P.Integral a, P.Bits a, A.Integral a, A.Bits a, Arbitrary a, Similar a, A.FromIntegral a Float) => (Config :-> Bool) -> a -> Maybe Test
    testIntegralElt ok _
      | P.not (get ok opt)      = Nothing
      | otherwise               = Just $ testGroup (show (typeOf (undefined :: a)))
          [ testProperty "neg.neg"    (test_negneg  :: Vector a -> Property)
          ]

    testFloatingElt :: forall a. (P.Floating a, P.RealFloat a, A.Floating a, A.RealFloat a, Arbitrary a, Similar a) => (Config :-> Bool) -> a -> Maybe Test
    testFloatingElt ok _
      | P.not (get ok opt)      = Nothing
      | otherwise               = Just $ testGroup (show (typeOf (undefined :: a)))
          [ testProperty "neg.neg"    (test_negneg  :: Vector a -> Property)
          ]

    test_negneg xs        = run1 backend (A.map negate . A.map negate) xs ~?= mapRef (negate . negate) xs
    test_notnot xs        = run1 backend (A.map A.not . A.map A.not) xs ~?= mapRef (P.not . P.not) xs

    test_andnot xs ys     = runN backend (A.zipWith (\x y -> A.not (x A.&& y))) xs ys
                            ~?=
                            zipWithRef (\x y -> P.not (x P.&& y)) xs ys

    test_ornot xs ys      = runN backend (A.zipWith (\x y -> A.not (x A.|| y))) xs ys
                            ~?=
                            zipWithRef (\x y -> P.not (x P.|| y)) xs ys

    test_andnotnot xs ys  = runN backend (A.zipWith (\x y -> A.not (A.not (x A.&& y)))) xs ys
                            ~?=
                            zipWithRef (\x y -> P.not (P.not (x P.&& y))) xs ys

    test_ornotnot xs ys   = runN backend (A.zipWith (\x y -> A.not (A.not (x A.|| y)))) xs ys
                            ~?=
                            zipWithRef (\x y -> P.not (P.not (x P.|| y))) xs ys

mapRef :: (Shape sh, Elt b) => (a -> b) -> Array sh a -> Array sh b
mapRef f xs
  = fromList (arrayShape xs)
  $ P.map f
  $ toList xs

zipWithRef :: (Shape sh, Elt c) => (a -> b -> c) -> Array sh a -> Array sh b -> Array sh c
zipWithRef f xs ys =
  let shx       = S.fromElt (S.shape xs)
      shy       = S.fromElt (S.shape ys)
      sh        = S.toElt (R.intersect shx shy)
  in
  fromFunction sh (\ix -> f (xs S.! ix) (ys S.! ix))