packages feed

massiv-test-1.1.0.0: src/Test/Massiv/Array/Delayed.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

module Test.Massiv.Array.Delayed (
  -- * Spec for safe Mutable instance
  delayedStreamSpec,

  -- * Useful properties for testing toList conversion
  prop_toStream,
  prop_toStreamIsList,
  prop_toStreamFoldable,
  prop_sfilter,
  prop_smapMaybe,
  prop_takeDrop,
  prop_sunfoldr,

  -- * Random reimplementations
  stackSlices',
) where

import Data.Foldable as F
import Data.List as L
import Data.Massiv.Array as A
import qualified Data.Massiv.Vector.Stream as S
import Data.Maybe as M
import qualified GHC.Exts as Exts
import Test.Massiv.Core.Common ()
import Test.Massiv.Utils as T

-- | Alternative implementation of `stackSlicesM` with 'concat''. Useful for testing and benchmarks
stackSlices'
  :: (Functor f, Foldable f, Source r e, Index ix, Load r (Lower ix) e)
  => Dim
  -> f (Array r (Lower ix) e)
  -> Array DL ix e
stackSlices' dim arrsF =
  let fixupSize arr = resize' (Sz (insertDim' (unSz (size arr)) dim 1)) arr
   in concat' dim $ fmap fixupSize arrsF

compareAsListAndLoaded
  :: (Eq e, Show e, Foldable (Array r' Ix1), Load r' Ix1 e) => Array r' Ix1 e -> [e] -> Property
compareAsListAndLoaded str ls =
  F.toList str === ls .&&. computeAs B str === A.fromList Seq ls

-- | Compare `toStream` and `A.toList`
prop_toStream
  :: forall r ix e
   . (Source r e, Stream r ix e, Show e, Eq e)
  => Array r ix e
  -> Property
prop_toStream arr =
  A.toList arr === S.toList (toStream arr)

-- | Compare `toStream` and `Exts.toList`
prop_toStreamIsList
  :: forall r e
   . (Exts.Item (Array r Ix1 e) ~ e, Exts.IsList (Array r Ix1 e), Stream r Ix1 e, Show e, Eq e)
  => Array r Ix1 e
  -> Property
prop_toStreamIsList arr =
  Exts.toList arr === S.toList (toStream arr)

-- | Compare `toStream` and `F.toList`
prop_toStreamFoldable
  :: forall r ix e
   . (Foldable (Array r ix), Stream r ix e, Show e, Eq e)
  => Array r ix e
  -> Property
prop_toStreamFoldable arr =
  F.toList arr === S.toList (toStream arr)

prop_sfilter
  :: forall r ix e
   . (Eq e, Show e, Stream r ix e, Foldable (Array r ix))
  => Array r ix e
  -> Fun e Bool
  -> Property
prop_sfilter arr f =
  compareAsListAndLoaded (A.sfilter (apply f) arr) (L.filter (apply f) (F.toList arr))

prop_smapMaybe
  :: forall r ix e a
   . (Eq a, Show a, Stream r ix e, Foldable (Array r ix))
  => Array r ix e
  -> Fun e (Maybe a)
  -> Property
prop_smapMaybe arr f =
  compareAsListAndLoaded (A.smapMaybe (apply f) arr) (M.mapMaybe (apply f) (F.toList arr))

prop_sunfoldr
  :: forall e s
   . (Eq e, Show e)
  => Fun s (Maybe (e, s))
  -> s
  -> NonNegative Int
  -> Property
prop_sunfoldr f s0 (NonNegative n) =
  compareAsListAndLoaded
    (A.stake (Sz n) (A.sunfoldr (apply f) s0))
    (L.take n (L.unfoldr (apply f) s0))

prop_sunfoldrN
  :: forall e s
   . (Eq e, Show e)
  => Fun s (Maybe (e, s))
  -> s
  -> Int
  -> Property
prop_sunfoldrN f s0 n =
  compareAsListAndLoaded (A.sunfoldrN (Sz n) (apply f) s0) (L.take n (L.unfoldr (apply f) s0))

prop_stakesDrop
  :: forall r e
   . ( Eq e
     , Show e
     , Stream r Ix1 e
     , Foldable (Array r Ix1)
     )
  => Vector r e
  -> Int
  -> Int
  -> Property
prop_stakesDrop arr t d =
  conjoin
    [ stoList (A.stake (Sz t) (A.sdrop (Sz d) arr)) === L.take t (L.drop d (F.toList arr))
    , stoList (A.sdrop (Sz d) (A.stake (Sz t) arr)) === L.drop d (L.take t (F.toList arr))
    ]

prop_takeDrop
  :: forall r e
   . ( Eq e
     , Show e
     , Source r e
     , Foldable (Array r Ix1)
     )
  => Vector r e
  -> Int
  -> Int
  -> Property
prop_takeDrop arr t d =
  conjoin
    [ A.toList (A.take (Sz t) (A.drop (Sz d) arr)) === L.take t (L.drop d (F.toList arr))
    , A.toList (A.drop (Sz d) (A.take (Sz t) arr)) === L.drop d (L.take t (F.toList arr))
    ]

delayedStreamSpec :: Spec
delayedStreamSpec = do
  describe "D Spec" $
    it "takeDrop" $
      property (prop_takeDrop @D @Int)
  describe "DS Spec" $ do
    it "sfilter" $ property (prop_sfilter @DS @Ix1 @Int)
    it "smapMaybe" $ property (prop_smapMaybe @DS @Ix1 @Int @Word)
    it "sunfoldr" $ property (prop_sunfoldr @Int @Word)
    it "sunfoldrN" $ property (prop_sunfoldrN @Int @Word)
    it "stakesDrop" $ property (prop_stakesDrop @DS @Int)