packages feed

factory-0.2.1.1: src/Factory/Test/QuickCheck/Statistics.hs

{-
	Copyright (C) 2011-2014 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 for "Math.Statistics".
-}

module Factory.Test.QuickCheck.Statistics(
-- * Functions
	quickChecks
) where

import qualified	Data.Array
import qualified	Data.List
import qualified	Data.Map
import qualified	Data.Numbers.Primes
import qualified	Data.Set
import qualified	Factory.Math.Implementations.Factorial	as Math.Implementations.Factorial
import qualified	Factory.Math.Power			as Math.Power
import qualified	Factory.Math.Statistics			as Math.Statistics
import			Factory.Test.QuickCheck.Factorial()
import qualified	Test.QuickCheck
import			Test.QuickCheck((==>))

-- | Defines invariant properties.
quickChecks :: IO ()
quickChecks	= Test.QuickCheck.quickCheck `mapM_` [prop_nC0, prop_nC1, prop_sum]
	>> Test.QuickCheck.quickCheck `mapM_` [prop_symmetry, prop_prime]
	>> Test.QuickCheck.quickCheck `mapM_` [prop_nP0, prop_nP1]
	>> Test.QuickCheck.quickCheck `mapM_` [prop_zeroVariance, prop_zeroAverageAbsoluteDeviation]
	>> Test.QuickCheck.quickCheck `mapM_` [prop_balance, prop_varianceRelocated, prop_varianceScaled, prop_varianceOrder, prop_equivalence, prop_varianceOfArray, prop_varianceOfMap, prop_meanOfSet]
	>> Test.QuickCheck.quickCheck prop_weightedMeanRational
	>> Test.QuickCheck.quickCheck prop_weightedMeanInteger
	>> Test.QuickCheck.quickCheck prop_weightedMeanUniformDenominator
 where
	prop_nC0, prop_nC1, prop_sum :: Math.Implementations.Factorial.Algorithm -> Integer -> Test.QuickCheck.Property
	prop_nC0 algorithm n	= Test.QuickCheck.label "prop_nC0" $ Math.Statistics.nCr algorithm (abs n) 0 == 1

	prop_nC1 algorithm i	= Test.QuickCheck.label "prop_nC1" $ Math.Statistics.nCr algorithm n 1 == n	where
		n	= succ $ abs i

	prop_sum algorithm i	= Test.QuickCheck.label "prop_sum" $ sum (Math.Statistics.nCr algorithm n `map` [0 .. n]) == 2 ^ n	where
		n	= succ $ abs i

	prop_symmetry, prop_prime :: Math.Implementations.Factorial.Algorithm -> (Integer, Integer) -> Test.QuickCheck.Property
	prop_symmetry algorithm (i, j)	= Test.QuickCheck.label "prop_symmetry" $ Math.Statistics.nCr algorithm n r == Math.Statistics.nCr algorithm n (n - r)	where
		[r, n]		= Data.List.sort $ map abs [i, j]

	prop_prime algorithm (i, j)	= r `notElem` [0, n]	==> Test.QuickCheck.label "prop_prime" $ (Math.Statistics.nCr algorithm n r `mod` n) == 0	where
		n	= Data.Numbers.Primes.primes !! fromIntegral (i `mod` 500000)
		r	= j `mod` n	-- Ensure r is smaller than n.

	prop_nP0, prop_nP1 :: Integer -> Test.QuickCheck.Property
	prop_nP0 n	= Test.QuickCheck.label "prop_nP0" $ Math.Statistics.nPr (abs n) 0 == 1

	prop_nP1 i	= Test.QuickCheck.label "prop_nP1" $ Math.Statistics.nPr n 1 == n	where
		n	= succ $ abs i

	prop_zeroVariance, prop_zeroAverageAbsoluteDeviation :: Rational -> Test.QuickCheck.Property
	prop_zeroVariance x			= Test.QuickCheck.label "prop_zeroVariance" $ Math.Statistics.getVariance (replicate 32 x) == (0 :: Rational)
	prop_zeroAverageAbsoluteDeviation x	= Test.QuickCheck.label "zeroAverageAbsoluteDeviation" $ Math.Statistics.getAverageAbsoluteDeviation (replicate 32 x) == (0 :: Rational)

	prop_balance, prop_varianceRelocated, prop_varianceScaled, prop_varianceOrder, prop_equivalence, prop_varianceOfMap, prop_meanOfSet, prop_varianceOfArray :: [Integer] -> Test.QuickCheck.Property
	prop_balance l			= not (null l)	==> Test.QuickCheck.label "prop_balance" . (== 0) . abs . sum $ map (\i -> toRational i - Math.Statistics.getMean l) l
	prop_varianceRelocated l	= not (null l)	==> Test.QuickCheck.label "prop_varianceRelocated" $ (Math.Statistics.getVariance l :: Rational) == Math.Statistics.getVariance (map succ l)
	prop_varianceScaled l		= not (null l)	==> Test.QuickCheck.label "prop_varianceScaled" $ (4 * Math.Statistics.getVariance l :: Rational) == Math.Statistics.getVariance (map (* 2) l)
	prop_varianceOrder l		= not (null l)	==> Test.QuickCheck.label "prop_varianceOrder" $ Math.Statistics.getVariance l == (Math.Statistics.getVariance (reverse l) :: Rational)
	prop_equivalence l		= not (null l)	==> Test.QuickCheck.label "prop_equivalence" $ Math.Statistics.getVariance l == Math.Statistics.getMean (map Math.Power.square l) - Math.Power.square (Math.Statistics.getMean l :: Rational)
	prop_varianceOfArray l		= not (null l)	==> Test.QuickCheck.label "prop_varianceOfArray" $ Math.Statistics.getVariance (Data.Array.array (1, length l) $ zip [1 ..] l) == (Math.Statistics.getVariance l :: Rational)
	prop_varianceOfMap l		= not (null l)	==> Test.QuickCheck.label "prop_varianceOfMap" $ Math.Statistics.getVariance (Data.Map.fromList $ zip [0 :: Int ..] l) == (Math.Statistics.getVariance l :: Rational)
	prop_meanOfSet l		= not (null l')	==> Test.QuickCheck.label "prop_meanOfSet" $ Math.Statistics.getMean (Data.Set.fromList l') == (Math.Statistics.getMean l' :: Rational)	where
		l'	= Data.List.nub l

	prop_weightedMeanRational :: [(Rational, Rational)] -> Test.QuickCheck.Property
	prop_weightedMeanRational assoc	= (denominator /= 0) ==> Test.QuickCheck.label "prop_weightedMeanRational" $ Math.Statistics.getWeightedMean assoc == (
		sum (map (uncurry (*)) assoc) / denominator
	 ) where
		denominator	= sum $ map snd assoc


	prop_weightedMeanInteger :: [(Integer, Integer)] -> Test.QuickCheck.Property
	prop_weightedMeanInteger assoc	= (denominator /= 0) ==> Test.QuickCheck.label "prop_weightedMeanInteger" $ Math.Statistics.getWeightedMean assoc == (
		toRational (
			sum $ map (
				uncurry (*)
			) assoc
		) / toRational denominator
	 ) where
		denominator	= sum $ map snd assoc

	prop_weightedMeanUniformDenominator :: [Rational] -> Integer -> Test.QuickCheck.Property
	prop_weightedMeanUniformDenominator numerators i	= (not (null numerators) && i /= 0) ==> Test.QuickCheck.label "prop_weightedMeanUniformDenominator" $ Math.Statistics.getWeightedMean (
		zip numerators $ repeat i
	 ) == (
		Math.Statistics.getMean numerators :: Rational
	 )