{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
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.Maybe as M
import Data.Foldable as F
import Data.Massiv.Array as A
import qualified Data.Massiv.Vector.Stream as S
import Test.Massiv.Core.Common ()
import Test.Massiv.Utils as T
import qualified GHC.Exts as Exts
import Data.List as L

-- | 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 -> f (Array r (Lower ix) e) -> Array DL ix e
stackSlices' Dim
dim f (Array r (Lower ix) e)
arrsF =
  let fixupSize :: Array r (Lower ix) e -> Array r ix e
fixupSize Array r (Lower ix) e
arr = Sz ix -> Array r (Lower ix) e -> Array r ix e
forall r ix ix' e.
(HasCallStack, Index ix', Index ix, Size r) =>
Sz ix' -> Array r ix e -> Array r ix' e
resize' (ix -> Sz ix
forall ix. Index ix => ix -> Sz ix
Sz (Lower ix -> Dim -> Int -> ix
forall ix. (HasCallStack, Index ix) => Lower ix -> Dim -> Int -> ix
insertDim' (Sz (Lower ix) -> Lower ix
forall ix. Sz ix -> ix
unSz (Array r (Lower ix) e -> Sz (Lower ix)
forall r ix e. Size r => Array r ix e -> Sz ix
size Array r (Lower ix) e
arr)) Dim
dim Int
1)) Array r (Lower ix) e
arr
   in Dim -> f (Array r ix e) -> Array DL ix e
forall (f :: * -> *) r ix e.
(HasCallStack, Foldable f, Index ix, Source r e) =>
Dim -> f (Array r ix e) -> Array DL ix e
concat' Dim
dim (f (Array r ix e) -> Array DL ix e)
-> f (Array r ix e) -> Array DL ix e
forall a b. (a -> b) -> a -> b
$ (Array r (Lower ix) e -> Array r ix e)
-> f (Array r (Lower ix) e) -> f (Array r ix e)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Array r (Lower ix) e -> Array r ix e
fixupSize f (Array r (Lower ix) e)
arrsF

compareAsListAndLoaded ::
     (Eq e, Show e, Foldable (Array r' Ix1), Load r' Ix1 e) => Array r' Ix1 e -> [e] -> Property
compareAsListAndLoaded :: Array r' Int e -> [e] -> Property
compareAsListAndLoaded Array r' Int e
str [e]
ls =
  Array r' Int e -> [e]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList Array r' Int e
str [e] -> [e] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== [e]
ls Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. B -> Array r' Int e -> Array B Int e
forall r e r' ix.
(Manifest r e, Load r' ix e) =>
r -> Array r' ix e -> Array r ix e
computeAs B
B Array r' Int e
str Array B Int e -> Array B Int e -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Comp -> [e] -> Array B Int e
forall r e. Manifest r e => Comp -> [e] -> Vector r e
A.fromList Comp
Seq [e]
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 :: Array r ix e -> Property
prop_toStream Array r ix e
arr =
  Array r ix e -> [e]
forall ix r e. (Index ix, Source r e) => Array r ix e -> [e]
A.toList Array r ix e
arr [e] -> [e] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Steps Id e -> [e]
forall e. Steps Id e -> [e]
S.toList (Array r ix e -> Steps Id e
forall r ix e. Stream r ix e => Array r ix e -> Steps Id e
toStream Array r ix e
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 :: Array r Int e -> Property
prop_toStreamIsList Array r Int e
arr =
  Array r Int e -> [Item (Array r Int e)]
forall l. IsList l => l -> [Item l]
Exts.toList Array r Int e
arr [e] -> [e] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Steps Id e -> [e]
forall e. Steps Id e -> [e]
S.toList (Array r Int e -> Steps Id e
forall r ix e. Stream r ix e => Array r ix e -> Steps Id e
toStream Array r Int e
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 :: Array r ix e -> Property
prop_toStreamFoldable Array r ix e
arr =
  Array r ix e -> [e]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList Array r ix e
arr [e] -> [e] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Steps Id e -> [e]
forall e. Steps Id e -> [e]
S.toList (Array r ix e -> Steps Id e
forall r ix e. Stream r ix e => Array r ix e -> Steps Id e
toStream Array r ix e
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 :: Array r ix e -> Fun e Bool -> Property
prop_sfilter Array r ix e
arr Fun e Bool
f =
  Array DS Int e -> [e] -> Property
forall e r'.
(Eq e, Show e, Foldable (Array r' Int), Load r' Int e) =>
Array r' Int e -> [e] -> Property
compareAsListAndLoaded ((e -> Bool) -> Array r ix e -> Array DS Int e
forall r ix e.
Stream r ix e =>
(e -> Bool) -> Array r ix e -> Vector DS e
A.sfilter (Fun e Bool -> e -> Bool
forall a b. Fun a b -> a -> b
apply Fun e Bool
f) Array r ix e
arr) ((e -> Bool) -> [e] -> [e]
forall a. (a -> Bool) -> [a] -> [a]
L.filter (Fun e Bool -> e -> Bool
forall a b. Fun a b -> a -> b
apply Fun e Bool
f) (Array r ix e -> [e]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList Array r ix e
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 :: Array r ix e -> Fun e (Maybe a) -> Property
prop_smapMaybe Array r ix e
arr Fun e (Maybe a)
f =
  Array DS Int a -> [a] -> Property
forall e r'.
(Eq e, Show e, Foldable (Array r' Int), Load r' Int e) =>
Array r' Int e -> [e] -> Property
compareAsListAndLoaded ((e -> Maybe a) -> Array r ix e -> Array DS Int a
forall r ix a b.
Stream r ix a =>
(a -> Maybe b) -> Array r ix a -> Vector DS b
A.smapMaybe (Fun e (Maybe a) -> e -> Maybe a
forall a b. Fun a b -> a -> b
apply Fun e (Maybe a)
f) Array r ix e
arr) ((e -> Maybe a) -> [e] -> [a]
forall a b. (a -> Maybe b) -> [a] -> [b]
M.mapMaybe (Fun e (Maybe a) -> e -> Maybe a
forall a b. Fun a b -> a -> b
apply Fun e (Maybe a)
f) (Array r ix e -> [e]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList Array r ix e
arr))


prop_sunfoldr ::
     forall e s. (Eq e, Show e)
  => Fun s (Maybe (e, s))
  -> s
  -> NonNegative Int
  -> Property
prop_sunfoldr :: Fun s (Maybe (e, s)) -> s -> NonNegative Int -> Property
prop_sunfoldr Fun s (Maybe (e, s))
f s
s0 (NonNegative Int
n) =
  Array DS Int e -> [e] -> Property
forall e r'.
(Eq e, Show e, Foldable (Array r' Int), Load r' Int e) =>
Array r' Int e -> [e] -> Property
compareAsListAndLoaded
    (Sz1 -> Array DS Int e -> Array DS Int e
forall r e. Stream r Int e => Sz1 -> Vector r e -> Vector DS e
A.stake (Int -> Sz1
forall ix. Index ix => ix -> Sz ix
Sz Int
n) ((s -> Maybe (e, s)) -> s -> Array DS Int e
forall e s. (s -> Maybe (e, s)) -> s -> Vector DS e
A.sunfoldr (Fun s (Maybe (e, s)) -> s -> Maybe (e, s)
forall a b. Fun a b -> a -> b
apply Fun s (Maybe (e, s))
f) s
s0))
    (Int -> [e] -> [e]
forall a. Int -> [a] -> [a]
L.take Int
n ((s -> Maybe (e, s)) -> s -> [e]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
L.unfoldr (Fun s (Maybe (e, s)) -> s -> Maybe (e, s)
forall a b. Fun a b -> a -> b
apply Fun s (Maybe (e, s))
f) s
s0))

prop_sunfoldrN ::
     forall e s. (Eq e, Show e)
  => Fun s (Maybe (e, s))
  -> s
  -> Int
  -> Property
prop_sunfoldrN :: Fun s (Maybe (e, s)) -> s -> Int -> Property
prop_sunfoldrN Fun s (Maybe (e, s))
f s
s0 Int
n =
  Array DS Int e -> [e] -> Property
forall e r'.
(Eq e, Show e, Foldable (Array r' Int), Load r' Int e) =>
Array r' Int e -> [e] -> Property
compareAsListAndLoaded (Sz1 -> (s -> Maybe (e, s)) -> s -> Array DS Int e
forall e s. Sz1 -> (s -> Maybe (e, s)) -> s -> Vector DS e
A.sunfoldrN (Int -> Sz1
forall ix. Index ix => ix -> Sz ix
Sz Int
n) (Fun s (Maybe (e, s)) -> s -> Maybe (e, s)
forall a b. Fun a b -> a -> b
apply Fun s (Maybe (e, s))
f) s
s0) (Int -> [e] -> [e]
forall a. Int -> [a] -> [a]
L.take Int
n ((s -> Maybe (e, s)) -> s -> [e]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
L.unfoldr (Fun s (Maybe (e, s)) -> s -> Maybe (e, s)
forall a b. Fun a b -> a -> b
apply Fun s (Maybe (e, s))
f) s
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 :: Vector r e -> Int -> Int -> Property
prop_stakesDrop Vector r e
arr Int
t Int
d =
  [Property] -> Property
forall prop. Testable prop => [prop] -> Property
conjoin
    [ Array DS Int e -> [e]
forall r ix e. Stream r ix e => Array r ix e -> [e]
stoList (Sz1 -> Array DS Int e -> Array DS Int e
forall r e. Stream r Int e => Sz1 -> Vector r e -> Vector DS e
A.stake (Int -> Sz1
forall ix. Index ix => ix -> Sz ix
Sz Int
t) (Sz1 -> Vector r e -> Array DS Int e
forall r e. Stream r Int e => Sz1 -> Vector r e -> Vector DS e
A.sdrop (Int -> Sz1
forall ix. Index ix => ix -> Sz ix
Sz Int
d) Vector r e
arr)) [e] -> [e] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Int -> [e] -> [e]
forall a. Int -> [a] -> [a]
L.take Int
t (Int -> [e] -> [e]
forall a. Int -> [a] -> [a]
L.drop Int
d (Vector r e -> [e]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList Vector r e
arr))
    , Array DS Int e -> [e]
forall r ix e. Stream r ix e => Array r ix e -> [e]
stoList (Sz1 -> Array DS Int e -> Array DS Int e
forall r e. Stream r Int e => Sz1 -> Vector r e -> Vector DS e
A.sdrop (Int -> Sz1
forall ix. Index ix => ix -> Sz ix
Sz Int
d) (Sz1 -> Vector r e -> Array DS Int e
forall r e. Stream r Int e => Sz1 -> Vector r e -> Vector DS e
A.stake (Int -> Sz1
forall ix. Index ix => ix -> Sz ix
Sz Int
t) Vector r e
arr)) [e] -> [e] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Int -> [e] -> [e]
forall a. Int -> [a] -> [a]
L.drop Int
d (Int -> [e] -> [e]
forall a. Int -> [a] -> [a]
L.take Int
t (Vector r e -> [e]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList Vector r e
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 :: Vector r e -> Int -> Int -> Property
prop_takeDrop Vector r e
arr Int
t Int
d =
  [Property] -> Property
forall prop. Testable prop => [prop] -> Property
conjoin
    [ Vector r e -> [e]
forall ix r e. (Index ix, Source r e) => Array r ix e -> [e]
A.toList (Sz1 -> Vector r e -> Vector r e
forall r e. Source r e => Sz1 -> Vector r e -> Vector r e
A.take (Int -> Sz1
forall ix. Index ix => ix -> Sz ix
Sz Int
t) (Sz1 -> Vector r e -> Vector r e
forall r e. Source r e => Sz1 -> Vector r e -> Vector r e
A.drop (Int -> Sz1
forall ix. Index ix => ix -> Sz ix
Sz Int
d) Vector r e
arr)) [e] -> [e] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Int -> [e] -> [e]
forall a. Int -> [a] -> [a]
L.take Int
t (Int -> [e] -> [e]
forall a. Int -> [a] -> [a]
L.drop Int
d (Vector r e -> [e]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList Vector r e
arr))
    , Vector r e -> [e]
forall ix r e. (Index ix, Source r e) => Array r ix e -> [e]
A.toList (Sz1 -> Vector r e -> Vector r e
forall r e. Source r e => Sz1 -> Vector r e -> Vector r e
A.drop (Int -> Sz1
forall ix. Index ix => ix -> Sz ix
Sz Int
d) (Sz1 -> Vector r e -> Vector r e
forall r e. Source r e => Sz1 -> Vector r e -> Vector r e
A.take (Int -> Sz1
forall ix. Index ix => ix -> Sz ix
Sz Int
t) Vector r e
arr)) [e] -> [e] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Int -> [e] -> [e]
forall a. Int -> [a] -> [a]
L.drop Int
d (Int -> [e] -> [e]
forall a. Int -> [a] -> [a]
L.take Int
t (Vector r e -> [e]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList Vector r e
arr))
    ]

delayedStreamSpec :: Spec
delayedStreamSpec :: Spec
delayedStreamSpec = do
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"D Spec" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"takeDrop" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ (Vector D Int -> Int -> Int -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((Eq Int, Show Int, Source D Int, Foldable (Array D Int)) =>
Vector D Int -> Int -> Int -> Property
forall r e.
(Eq e, Show e, Source r e, Foldable (Array r Int)) =>
Vector r e -> Int -> Int -> Property
prop_takeDrop @D @Int)
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"DS Spec" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"sfilter" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ (Array DS Int Int -> Fun Int Bool -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((Eq Int, Show Int, Stream DS Int Int, Foldable (Array DS Int)) =>
Array DS Int Int -> Fun Int Bool -> Property
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 @DS @Ix1 @Int)
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"smapMaybe" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ (Array DS Int Int -> Fun Int (Maybe Word) -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((Eq Word, Show Word, Stream DS Int Int, Foldable (Array DS Int)) =>
Array DS Int Int -> Fun Int (Maybe Word) -> Property
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 @DS @Ix1 @Int @Word)
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"sunfoldr" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ (Fun Word (Maybe (Int, Word))
 -> Word -> NonNegative Int -> Property)
-> Property
forall prop. Testable prop => prop -> Property
property ((Eq Int, Show Int) =>
Fun Word (Maybe (Int, Word)) -> Word -> NonNegative Int -> Property
forall e s.
(Eq e, Show e) =>
Fun s (Maybe (e, s)) -> s -> NonNegative Int -> Property
prop_sunfoldr @Int @Word)
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"sunfoldrN" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ (Fun Word (Maybe (Int, Word)) -> Word -> Int -> Property)
-> Property
forall prop. Testable prop => prop -> Property
property ((Eq Int, Show Int) =>
Fun Word (Maybe (Int, Word)) -> Word -> Int -> Property
forall e s.
(Eq e, Show e) =>
Fun s (Maybe (e, s)) -> s -> Int -> Property
prop_sunfoldrN @Int @Word)
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"stakesDrop" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ (Array DS Int Int -> Int -> Int -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((Eq Int, Show Int, Stream DS Int Int, Foldable (Array DS Int)) =>
Array DS Int Int -> Int -> Int -> Property
forall r e.
(Eq e, Show e, Stream r Int e, Foldable (Array r Int)) =>
Vector r e -> Int -> Int -> Property
prop_stakesDrop @DS @Int)