{-# LANGUAGE TemplateHaskell, DataKinds, ScopedTypeVariables, DeriveDataTypeable #-} module Main where --import Test.ProbabilityCheck import Test.ProbabilityCheck.Internal import Test.Tasty.TestApproximate import Test.Tasty (defaultMain, testGroup) import Test.Tasty.HUnit (Assertion, assertFailure, testCase) import Data.Conduit (Source, ZipSource(..), ($=), Conduit, ($$)) import qualified Data.Conduit.List as CL import System.Random.MWC (createSystemRandom, GenIO) import System.Random.MWC.Distributions (normal, uniformPermutation) import Control.Applicative ((<*>)) import qualified Data.HyperLogLog as HLL import Data.Reflection (nat) import Data.Approximate (Approximate(..)) import Data.List (nub) import Test.QuickCheck (Gen, Arbitrary(..), choose, elements, frequency) import Data.Monoid (mempty) import Data.Ratio (numerator, denominator) import Data.Int (Int64) import Data.Typeable (Typeable) import Numeric.Log.Signed (SignedLog) import qualified Data.Vector as V main :: IO () main = do mwcGen <- createSystemRandom defaultMain $ testGroup "probability-test's Tests" [ testCase "Simple empiricalBernstienStopping TestZero case" $ assertResHasVal TestZero $ zeroSourceRangeLimit mwcGen $$ empiricalBernstienStopping 2 0.05 0.01 , testCase "Simple empiricalBernstienStopping TestPositive case" $ assertResHasVal TestPositive $ oneHundrethSourceRangeLimit mwcGen $$ empiricalBernstienStopping 2 0.05 0.01 , testCase "Simple empiricalBernstienStopping TestNegative case" $ assertResHasVal TestNegative $ negOneHundrethSourceRangeLimit mwcGen $$ empiricalBernstienStopping 2 0.05 0.01 , testApproximate "HLL test." (HLL.size . foldl (flip HLL.insert) (mempty :: HLL.HyperLogLog $(nat 5))) (fromIntegral . length . nub :: [Int] -> Int64) , testApproximate "Approx simple pass." simpleCorrectApprox simpleActual , testApproximate "Approx simple fail. *THIS SHOULD FAIL*" simpleIncorrectApprox simpleActual {-, testCase "Simulated 'Approx simple fail' with Doubles and MWC random." $ assertResHasVal TestNegative $ simulatedApproxSource mwcGen (0.91::Double) $$ empiricalBernstienStopping 2 0.05 0.01 , testCase "Simulated 'Approx simple fail' with SignedLog Doubles and MWC random." $ assertResHasVal TestNegative $ simulatedApproxSource mwcGen (0.91::SignedLog Double) $$ empiricalBernstienStopping 2 0.05 0.01 -} ] simulatedApproxSource :: (Num a) => GenIO -> a -> Source IO a simulatedApproxSource mwcGen conf = sourceZeroToNine mwcGen $= CL.map (\r -> (if r == 0 then 0 else 1) - conf) sourceZeroToNine :: GenIO -> Source IO Int sourceZeroToNine mwcGen = CL.unfoldM (\_ -> do lst <- uniformPermutation 10 mwcGen return $ Just (V.head lst, ())) () simpleCorrectApprox :: a -> Approximate Int simpleCorrectApprox _ = Approximate 0.9 10 55 99 simpleIncorrectApprox :: a -> Approximate Int simpleIncorrectApprox _ = Approximate 0.91 10 55 99 data ZeroToNintyNine = ZeroToNintyNine {simpleActual :: Int} deriving (Typeable) instance Show ZeroToNintyNine where show = show . simpleActual instance Arbitrary ZeroToNintyNine where arbitrary = choose (0,99) >>= return . ZeroToNintyNine genHLLConfCorrect :: Gen (SignedLog Double, SignedLog Double) genHLLConfCorrect = do ((actual, hll), _) <- genHLLActualApprox let (Approximate conf lo _ hi) = HLL.size hll (n, d) = (numerator $ toRational conf, denominator $ toRational conf) (a, b) = (fromInteger (d-n), fromInteger n) c <- frequency [(a, return 0), (b, return 1)] return (c, if lo <= actual && actual <= hi then 1 else 0) genHLLActualApprox :: (Num a) => Gen ((a, HLL.HyperLogLog $(nat 5)), [Integer]) genHLLActualApprox = do lst <- arbitrary :: Gen [Integer] return ((fromIntegral $ length $ nub lst, foldl (flip HLL.insert) mempty lst), lst) assertResHasVal :: (Show n) => DistributionTestValue -> IO (DistributionTestResult n) -> Assertion assertResHasVal a bIO = do b <- bIO if a == dtrValue b then return () else assertFailure ( "Expected: " ++ (show a) ++ "\nGot: " ++ (show b) ) tupleSource :: GenIO -> Double -> Double -> Source IO (Double, Double) tupleSource mwcGen a b = getZipSource $ ZipSource ((normalDoubleSource mwcGen a) $= CL.map (\x y -> (x,y))) <*> ZipSource (normalDoubleSource mwcGen b) normalDoubleSource :: GenIO -> Double -> Source IO Double normalDoubleSource mwcGen mean = CL.unfoldM (\_ -> do r <- rIO mwcGen mean return $ Just (r, ())) () limitRange :: Double -> Double -> Conduit Double IO Double limitRange lo hi = CL.map (\a -> max lo $ min hi a) rIO :: GenIO -> Double -> IO Double rIO mwcGen mean = normal mean 0.1 mwcGen pIO :: Double -> Double -> Gen (Double, Double) pIO meanA meanB = do a <- elements [meanA-1, meanA+1] -- Binary distribution containing points of meanA +/- 1. b <- choose (meanB-1,meanB+1) -- Uniform distribution over meanB +/- 1. return (a, b) zeroSource :: GenIO -> Source IO Double zeroSource mwcGen = normalDoubleSource mwcGen 0 zeroSourceRangeLimit :: GenIO -> Source IO Double zeroSourceRangeLimit mwcGen = zeroSource mwcGen $= limitRange (-1) 1 oneHundrethSourceRangeLimit :: GenIO -> Source IO Double oneHundrethSourceRangeLimit mwcGen = (normalDoubleSource mwcGen 0.01) $= limitRange (-0.9) 1.1 negOneHundrethSourceRangeLimit :: GenIO -> Source IO Double negOneHundrethSourceRangeLimit mwcGen = (normalDoubleSource mwcGen (-0.01)) $= limitRange (-1.1) 0.9