toolshed-0.18.0.0: src-test/ToolShed/Test/QuickCheck/System/Random.hs
{-
Copyright (C) 2013-2015 Dr. Alistair Ward
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-}
{- |
[@AUTHOR@] Dr. Alistair Ward
[@DESCRIPTION@] Defines /QuickCheck/-properties "ToolShed.System.Random".
-}
module ToolShed.Test.QuickCheck.System.Random(
-- * Constants
results,
-- * Functions
-- getMean,
-- getStandardDeviation
) where
import qualified Control.Arrow
import Control.Arrow((&&&),(***))
import qualified Data.Foldable
import qualified Data.List
import qualified Data.Map
import qualified System.Random
import qualified Test.QuickCheck
import qualified ToolShed.System.Random
-- | Determines the /mean/ of the specified numbers
getMean :: (Data.Foldable.Foldable foldable, Real r, Fractional result) => foldable r -> result
getMean = uncurry (/) . (realToFrac *** fromIntegral) . Data.Foldable.foldr (\i -> (+ i) *** succ) (0, 0 :: Int)
-- | Find the standard-deviation of the specified list.
getStandardDeviation :: (Data.Foldable.Foldable foldable, Functor foldable, Real r) => foldable r -> Double
getStandardDeviation x = sqrt . getMean $ fmap ((^ (2 :: Int)) . subtract (getMean x :: Rational) . toRational) x
-- | The constant test-results for this data-type.
results :: IO [Test.QuickCheck.Result]
results = sequence [
Test.QuickCheck.quickCheckResult prop_shuffle,
Test.QuickCheck.quickCheckResult prop_shuffleDistribution
] where
prop_shuffle :: Int -> Int -> Test.QuickCheck.Property
prop_shuffle seed l = Test.QuickCheck.label "prop_shuffle" . (== testList) . Data.List.sort $ ToolShed.System.Random.shuffle (System.Random.mkStdGen seed) testList where
testList = [0 .. l `mod` 10000]
prop_shuffleDistribution :: Int -> Test.QuickCheck.Property
prop_shuffleDistribution = Test.QuickCheck.label "prop_shuffleDistribution" . all (
uncurry (&&) . (
(
< recip 16 {-empirically-} -- The ideal value for a uniform distribution, would be zero.
) . (
/ getStandardDeviation (populationSize : replicate (pred $ length testList) 0) -- Normalise wrt the worst-case; which occurs when this column contains the same letter, for each test-case in the population.
) . getStandardDeviation &&& (
== populationSize -- Confirm the size of the test-data.
) . Data.Foldable.sum
)
) . map (
foldr (
uncurry $ Data.Map.insertWith (+)
) (
Data.Map.fromList . zip testList $ repeat (0 :: Int) -- Initial value.
) . (`zip` repeat 1) -- Count the instances of each letter in this column, which for a uniform distribution, should be approximately the same.
) . Data.List.transpose {-examine the columns-} . take populationSize . map fst {-shuffled digits-} . tail {-drop initial value-} . iterate (
Control.Arrow.first (`ToolShed.System.Random.shuffle` testList) . System.Random.split . snd
) . (,) undefined . System.Random.mkStdGen where
testList :: String
testList = ['a' .. 'z']
populationSize :: Int
populationSize = 1000