arrayfire-0.8.0.0: test/ArrayFire/RandomSpec.hs
{-# LANGUAGE TypeApplications #-}
module ArrayFire.RandomSpec where
import ArrayFire
import Test.Hspec
spec :: Spec
spec = describe "Random spec" $ do
describe "random engine" $ do
it "Should create random engine" $ do
(`shouldBe` Philox)
=<< getRandomEngineType
=<< createRandomEngine 5000 Philox
(`shouldBe` Mersenne)
=<< getRandomEngineType
=<< createRandomEngine 5000 Mersenne
(`shouldBe` ThreeFry)
=<< getRandomEngineType
=<< createRandomEngine 5000 ThreeFry
it "Should set random engine" $ do
r <- createRandomEngine 5000 ThreeFry
setRandomEngine r Philox
(`shouldBe` Philox) =<< getRandomEngineType r
it "Should set and get seed" $ do
setSeed 100
(`shouldBe` 100) =<< getSeed
-- Reproducibility is the contract that makes randomness usable in tests and
-- science: a fixed seed must yield a fixed stream.
describe "seed reproducibility" $ do
it "global setSeed makes randu reproducible" $ do
setSeed 1234
a1 <- toList <$> randu @Float [256]
setSeed 1234
a2 <- toList <$> randu @Float [256]
a2 `shouldBe` a1
it "global setSeed makes randn reproducible" $ do
setSeed 9876
a1 <- toList <$> randn @Double [256]
setSeed 9876
a2 <- toList <$> randn @Double [256]
a2 `shouldBe` a1
it "two engines with the same seed + type draw the same stream" $ do
e1 <- createRandomEngine 42 Philox
e2 <- createRandomEngine 42 Philox
a1 <- toList <$> randomUniform @Float [256] e1
a2 <- toList <$> randomUniform @Float [256] e2
a2 `shouldBe` a1
it "engines with different seeds draw different streams" $ do
e1 <- createRandomEngine 1 Philox
e2 <- createRandomEngine 2 Philox
a1 <- toList <$> randomUniform @Float [256] e1
a2 <- toList <$> randomUniform @Float [256] e2
a2 `shouldNotBe` a1
describe "distribution shape & range" $ do
it "randu produces the requested dimensions" $ do
a <- randu @Float [3,4]
getDims a `shouldBe` (3,4,1,1)
it "randn produces the requested dimensions" $ do
a <- randn @Double [5,2,3]
getDims a `shouldBe` (5,2,3,1)
it "uniform draws lie in [0,1)" $ do
setSeed 7
xs <- toList <$> randu @Float [4096]
xs `shouldSatisfy` all (\x -> x >= 0 && x < 1)
describe "randomNormal" $ do
it "produces the requested dimensions" $ do
e <- getDefaultRandomEngine
a <- randomNormal @Double [3,4] e
getDims a `shouldBe` (3,4,1,1)
it "produces the right number of elements" $ do
e <- getDefaultRandomEngine
a <- randomNormal @Float [5,2] e
getElements a `shouldBe` 10
it "two engines with the same seed produce the same normal stream" $ do
e1 <- createRandomEngine 42 Philox
e2 <- createRandomEngine 42 Philox
a1 <- toList <$> randomNormal @Double [256] e1
a2 <- toList <$> randomNormal @Double [256] e2
a2 `shouldBe` a1
it "engines with different seeds produce different normal streams" $ do
e1 <- createRandomEngine 1 Philox
e2 <- createRandomEngine 2 Philox
a1 <- toList <$> randomNormal @Double [256] e1
a2 <- toList <$> randomNormal @Double [256] e2
a2 `shouldNotBe` a1
describe "randomEngineSetSeed / randomEngineGetSeed" $ do
it "getSeed returns the seed supplied to createRandomEngine" $ do
e <- createRandomEngine 9999 Philox
s <- randomEngineGetSeed e
s `shouldBe` 9999
it "setAndGet round-trip: seed is updated after randomEngineSetSeed" $ do
e <- createRandomEngine 1 Philox
randomEngineSetSeed e 12345
s <- randomEngineGetSeed e
s `shouldBe` 12345
it "different seeds produce different streams after randomEngineSetSeed" $ do
e <- createRandomEngine 1 Philox
randomEngineSetSeed e 100
a1 <- toList <$> randomUniform @Float [64] e
randomEngineSetSeed e 200
a2 <- toList <$> randomUniform @Float [64] e
a2 `shouldNotBe` a1
it "same seed after reset produces the same stream" $ do
e <- createRandomEngine 1 Philox
randomEngineSetSeed e 777
a1 <- toList <$> randomUniform @Float [64] e
randomEngineSetSeed e 777
a2 <- toList <$> randomUniform @Float [64] e
a2 `shouldBe` a1
describe "retainRandomEngine" $ do
it "retained engine has the same type as the original" $ do
e <- createRandomEngine 42 Philox
e' <- retainRandomEngine e
getRandomEngineType e' `shouldReturn` Philox
it "retained handle shares state with original (both advance the same stream)" $ do
e <- createRandomEngine 42 Philox
e' <- retainRandomEngine e
a1 <- toList <$> randomUniform @Double [4] e
a2 <- toList <$> randomUniform @Double [4] e'
a2 `shouldNotBe` a1
describe "setDefaultRandomEngineType" $ do
it "default engine type reflects the type that was set" $ do
setDefaultRandomEngineType ThreeFry
e <- getDefaultRandomEngine
getRandomEngineType e `shouldReturn` ThreeFry
it "switching type changes what getDefaultRandomEngine reports" $ do
setDefaultRandomEngineType Philox
e1 <- getDefaultRandomEngine
t1 <- getRandomEngineType e1
setDefaultRandomEngineType Mersenne
e2 <- getDefaultRandomEngine
t2 <- getRandomEngineType e2
t1 `shouldBe` Philox
t2 `shouldBe` Mersenne