module Main where
import Control.Monad.Error (runErrorT)
import Control.Monad.Mersenne.Random (evalRandom)
import Numeric.IEEE (IEEE, epsilon)
import System.Random.Mersenne.Pure64 (pureMT)
import qualified Data.Vector.Unboxed as V
import Statistics.Test.ApproxRand
import Test.HUnit (Assertion, assertBool, assertEqual)
import Test.Framework
import Test.Framework.Providers.HUnit
tests :: Test
tests = testGroup "Paired approximate randomization tests" $
concat [statTests, randomizationTests]
main :: IO ()
main = defaultMain [ tests ]
-- Statistics tests
statTests :: [Test]
statTests = [meanDifferenceTest]
meanDifferenceTest :: Test
meanDifferenceTest =
testIEEEEquality "mean difference robot competition"
1.8 $ meanDifference cohenRobotsAlpha cohenRobotsBeta
-- Approximate andomization tests
randomizationTests :: [Test]
randomizationTests = [pairApproxExactTestScores]
pairApproxExactTestScores :: Test
pairApproxExactTestScores =
testEquality "number of extreme values robot competition"
(Right 21) $ V.length `fmap` V.filter (>= 1.8) `fmap` scores
where
test = runErrorT $
approxRandPairStats differenceMean 1024 cohenRobotsAlpha cohenRobotsBeta
scores = evalRandom test $ pureMT 42
-- Helper functions
testEquality :: (Show a, Eq a) => String -> a -> a -> Test
testEquality msg a b = testCase msg $ assertEqual msg a b
testIEEEEquality :: IEEE a => String -> a -> a -> Test
testIEEEEquality msg a b = testCase msg $ assertEqualIEEE msg a b
assertEqualIEEE :: IEEE a => String -> a -> a -> Assertion
assertEqualIEEE msg a b = assertBool msg $ fracEq epsilon a b
-- Suggested in The Floating Point Guide: http://floating-point-gui.de/
fracEq :: (Fractional a, Ord a) => a -> a -> a -> Bool
fracEq eps a b
| a == b = True
| a * b == 0 = diff < (eps * eps)
| otherwise = diff / (abs a + abs b) < eps
where diff = abs (a - b)
-- Example from Cohen, 1995
cohenRobotsAlpha :: V.Vector Double
cohenRobotsAlpha = V.fromList [8,3,9,6,5,8,7,8,9,9]
cohenRobotsBeta :: V.Vector Double
cohenRobotsBeta = V.fromList [7,0,9,4,5,9,8,3,4,5]