packages feed

massiv-0.1.0.0: tests/Data/Massiv/Array/Ops/FoldSpec.hs

{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MonoLocalBinds        #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Data.Massiv.Array.Ops.FoldSpec (spec) where

import           Data.Massiv.CoreArbitrary
import           Prelude                   hiding (map, product, sum)
import qualified Prelude                   as P (length, sum)
import           Test.Hspec
import           Test.QuickCheck
import           Test.QuickCheck.Monadic


prop_SumSEqSumP :: Index ix => proxy ix -> Array D ix Int -> Bool
prop_SumSEqSumP _ arr = sum arr == sum (setComp Par arr)


prop_ProdSEqProdP :: Index ix => proxy ix -> Array D ix Int -> Bool
prop_ProdSEqProdP _ arr = product arr == product (setComp Par arr)

prop_NestedFoldP :: Array D Ix1 (Array D Ix1 Int) -> Bool
prop_NestedFoldP arr = sum (setComp Par (map sum $ setComp Par arr)) == sum (map sum arr)

prop_FoldrOnP :: Int -> [Int] -> ArrP D Ix1 Int -> Property
prop_FoldrOnP wId wIds (ArrP arr) =
  P.length arr > P.length wIds ==> monadicIO $ do
    res <- run $ ifoldrOnP wIdsNE (\_ -> (+)) 0 (:) [] arr
    if P.length arr `mod` P.length wIdsNE == 0
      then assert (P.length res == P.length wIdsNE)
      else assert (P.length res == P.length wIdsNE + 1)
    assert (P.sum res == sum arr)
  where
    wIdsNE = wId : wIds

prop_FoldlOnP :: Int -> [Int] -> ArrP D Ix1 Int -> Property
prop_FoldlOnP wId wIds (ArrP arr) =
  P.length arr > P.length wIds ==> monadicIO $ do
    res <- run $ ifoldlOnP wIdsNE (\a _ x -> a + x) 0 (flip (:)) [] arr
    if P.length arr `mod` P.length wIdsNE == 0
      then assert (P.length res == P.length wIdsNE)
      else assert (P.length res == P.length wIdsNE + 1)
    assert (P.sum res == sum arr)
  where
    wIdsNE = wId : wIds


specFold ::
     (Arbitrary ix, CoArbitrary ix, Index ix, Show (Array D ix Int))
  => proxy ix
  -> String
  -> Spec
specFold proxy dimStr = do
  describe dimStr $ do
    it "sumS Eq sumP" $ property $ prop_SumSEqSumP proxy
    it "prodS Eq prodP" $ property $ prop_ProdSEqProdP proxy

spec :: Spec
spec = do
  specFold (Nothing :: Maybe Ix1) "Ix1"
  specFold (Nothing :: Maybe Ix2) "Ix2"
  it "Nested Parallel Fold" $ property prop_NestedFoldP
  it "FoldrOnP" $ property $ prop_FoldrOnP
  it "FoldlOnP" $ property $ prop_FoldlOnP