{-
	Copyright (C) 2011-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 <https://www.gnu.org/licenses/>.
-}
{- |
 [@AUTHOR@]	Dr. Alistair Ward

 [@DESCRIPTION@]	Functions for probability-distributions.

 [@CAVEAT@]	Because data-constructors are exposed, 'ToolShed.SelfValidate.isValid' need not be called.
-}

module Factory.Math.Probability(
-- * Type-classes
	Distribution(..),
-- * Types
-- ** Data-types
	ContinuousDistribution(..),
	DiscreteDistribution(..),
-- * Functions
	maxPreciseInteger,
--	minPositiveFloat,
	boxMullerTransform,
--	reProfile,
	generateStandardizedNormalDistribution,
	generateContinuousPopulation,
--	generatePoissonDistribution,
	generateDiscretePopulation
) where

import qualified	Control.Arrow
import			Control.Arrow((***), (&&&))
import qualified	Factory.Data.Interval	as Data.Interval
import qualified	Factory.Math.Power	as Math.Power
import qualified	System.Random
import qualified	ToolShed.Data.List
import qualified	ToolShed.Data.Pair
import qualified	ToolShed.SelfValidate

-- | The maximum integer which can be accurately represented as a Double.
maxPreciseInteger :: RealFloat a => a -> Integer
maxPreciseInteger :: a -> Integer
maxPreciseInteger	= (Integer
2 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^) (Int -> Integer) -> (a -> Int) -> a -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Int
forall a. RealFloat a => a -> Int
floatDigits

{- |
	* Determines the minimum positive floating-point number, which can be represented by using the parameter's type.

	* Only the type of the parameter is relevant, not its value.
-}
minPositiveFloat :: RealFloat a => a -> a
minPositiveFloat :: a -> a
minPositiveFloat	= Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat Integer
1 (Int -> a) -> (a -> Int) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int -> Int) -> (Int, Int) -> Int
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (-) ((Int, Int) -> Int) -> (a -> (Int, Int)) -> a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Int, Int) -> Int
forall a b. (a, b) -> a
fst ((Int, Int) -> Int) -> (a -> (Int, Int)) -> a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> (Int, Int)
forall a. RealFloat a => a -> (Int, Int)
floatRange (a -> Int) -> (a -> Int) -> a -> (Int, Int)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& a -> Int
forall a. RealFloat a => a -> Int
floatDigits)

-- | Describes /continuous probability-distributions/; <https://en.wikipedia.org/wiki/List_of_probability_distributions#Continuous_distributions>.
data ContinuousDistribution parameter
	= ExponentialDistribution parameter {-lambda-}				-- ^ Defines an /Exponential/-distribution with a particular /lambda/; <https://en.wikipedia.org/wiki/Exponential_distribution>.
	| LogNormalDistribution parameter {-location-} parameter {-scale2-}	-- ^ Defines a distribution whose logarithm is normally distributed with a particular /mean/ & /variance/; <https://en.wikipedia.org/wiki/Lognormal>.
	| NormalDistribution parameter {-mean-} parameter {-variance-}		-- ^ Defines a /Normal/-distribution with a particular /mean/ & /variance/; <https://en.wikipedia.org/wiki/Normal_distribution>.
	| UniformDistribution (Data.Interval.Interval parameter)		-- ^ Defines a /Uniform/-distribution within a /closed interval/; <https://en.wikipedia.org/wiki/Uniform_distribution>.
	deriving (ContinuousDistribution parameter
-> ContinuousDistribution parameter -> Bool
(ContinuousDistribution parameter
 -> ContinuousDistribution parameter -> Bool)
-> (ContinuousDistribution parameter
    -> ContinuousDistribution parameter -> Bool)
-> Eq (ContinuousDistribution parameter)
forall parameter.
Eq parameter =>
ContinuousDistribution parameter
-> ContinuousDistribution parameter -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ContinuousDistribution parameter
-> ContinuousDistribution parameter -> Bool
$c/= :: forall parameter.
Eq parameter =>
ContinuousDistribution parameter
-> ContinuousDistribution parameter -> Bool
== :: ContinuousDistribution parameter
-> ContinuousDistribution parameter -> Bool
$c== :: forall parameter.
Eq parameter =>
ContinuousDistribution parameter
-> ContinuousDistribution parameter -> Bool
Eq, ReadPrec [ContinuousDistribution parameter]
ReadPrec (ContinuousDistribution parameter)
Int -> ReadS (ContinuousDistribution parameter)
ReadS [ContinuousDistribution parameter]
(Int -> ReadS (ContinuousDistribution parameter))
-> ReadS [ContinuousDistribution parameter]
-> ReadPrec (ContinuousDistribution parameter)
-> ReadPrec [ContinuousDistribution parameter]
-> Read (ContinuousDistribution parameter)
forall parameter.
Read parameter =>
ReadPrec [ContinuousDistribution parameter]
forall parameter.
Read parameter =>
ReadPrec (ContinuousDistribution parameter)
forall parameter.
Read parameter =>
Int -> ReadS (ContinuousDistribution parameter)
forall parameter.
Read parameter =>
ReadS [ContinuousDistribution parameter]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [ContinuousDistribution parameter]
$creadListPrec :: forall parameter.
Read parameter =>
ReadPrec [ContinuousDistribution parameter]
readPrec :: ReadPrec (ContinuousDistribution parameter)
$creadPrec :: forall parameter.
Read parameter =>
ReadPrec (ContinuousDistribution parameter)
readList :: ReadS [ContinuousDistribution parameter]
$creadList :: forall parameter.
Read parameter =>
ReadS [ContinuousDistribution parameter]
readsPrec :: Int -> ReadS (ContinuousDistribution parameter)
$creadsPrec :: forall parameter.
Read parameter =>
Int -> ReadS (ContinuousDistribution parameter)
Read, Int -> ContinuousDistribution parameter -> ShowS
[ContinuousDistribution parameter] -> ShowS
ContinuousDistribution parameter -> String
(Int -> ContinuousDistribution parameter -> ShowS)
-> (ContinuousDistribution parameter -> String)
-> ([ContinuousDistribution parameter] -> ShowS)
-> Show (ContinuousDistribution parameter)
forall parameter.
Show parameter =>
Int -> ContinuousDistribution parameter -> ShowS
forall parameter.
Show parameter =>
[ContinuousDistribution parameter] -> ShowS
forall parameter.
Show parameter =>
ContinuousDistribution parameter -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ContinuousDistribution parameter] -> ShowS
$cshowList :: forall parameter.
Show parameter =>
[ContinuousDistribution parameter] -> ShowS
show :: ContinuousDistribution parameter -> String
$cshow :: forall parameter.
Show parameter =>
ContinuousDistribution parameter -> String
showsPrec :: Int -> ContinuousDistribution parameter -> ShowS
$cshowsPrec :: forall parameter.
Show parameter =>
Int -> ContinuousDistribution parameter -> ShowS
Show)

instance (Floating parameter, Ord parameter, Show parameter) => ToolShed.SelfValidate.SelfValidator (ContinuousDistribution parameter)	where
	getErrors :: ContinuousDistribution parameter -> [String]
getErrors ContinuousDistribution parameter
probabilityDistribution	= [(Bool, String)] -> [String]
ToolShed.SelfValidate.extractErrors ([(Bool, String)] -> [String]) -> [(Bool, String)] -> [String]
forall a b. (a -> b) -> a -> b
$ case ContinuousDistribution parameter
probabilityDistribution of
		ExponentialDistribution parameter
lambda		-> [(parameter
lambda parameter -> parameter -> Bool
forall a. Ord a => a -> a -> Bool
<= parameter
0, String
"'lambda' must exceed zero; " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ContinuousDistribution parameter -> String
forall a. Show a => a -> String
show ContinuousDistribution parameter
probabilityDistribution String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".")]
		LogNormalDistribution parameter
location parameter
scale2	-> let
			maxParameter :: parameter
maxParameter	= parameter -> parameter
forall a. Floating a => a -> a
log (parameter -> parameter)
-> (Integer -> parameter) -> Integer -> parameter
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> parameter
forall a. Num a => Integer -> a
fromInteger (Integer -> parameter) -> Integer -> parameter
forall a b. (a -> b) -> a -> b
$ Double -> Integer
forall a. RealFloat a => a -> Integer
maxPreciseInteger (Double
forall a. HasCallStack => a
undefined :: Double)
		 in [
			(parameter
scale2 parameter -> parameter -> Bool
forall a. Ord a => a -> a -> Bool
<= parameter
0,						String
"'scale' must exceed zero; " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ContinuousDistribution parameter -> String
forall a. Show a => a -> String
show ContinuousDistribution parameter
probabilityDistribution String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"."),
			(parameter
location parameter -> parameter -> Bool
forall a. Ord a => a -> a -> Bool
> parameter
maxParameter Bool -> Bool -> Bool
|| parameter
scale2 parameter -> parameter -> Bool
forall a. Ord a => a -> a -> Bool
> parameter
maxParameter,	String
"loss of precision will result from either 'location' or 'scale^2' exceeding '" String -> ShowS
forall a. [a] -> [a] -> [a]
++ parameter -> String
forall a. Show a => a -> String
show parameter
maxParameter String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"'; " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ContinuousDistribution parameter -> String
forall a. Show a => a -> String
show ContinuousDistribution parameter
probabilityDistribution String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".")
		 ]
		NormalDistribution parameter
_ parameter
variance		-> [(parameter
variance parameter -> parameter -> Bool
forall a. Ord a => a -> a -> Bool
<= parameter
0, String
"variance must exceed zero; " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ContinuousDistribution parameter -> String
forall a. Show a => a -> String
show ContinuousDistribution parameter
probabilityDistribution String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".")]
		UniformDistribution Interval parameter
interval		-> [(Interval parameter -> Bool
forall endPoint. Ord endPoint => Interval endPoint -> Bool
Data.Interval.isReversed Interval parameter
interval, String
"reversed interval='" String -> ShowS
forall a. [a] -> [a] -> [a]
++ ContinuousDistribution parameter -> String
forall a. Show a => a -> String
show ContinuousDistribution parameter
probabilityDistribution String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"'.")]

-- | Describes /discrete probability-distributions/; <https://en.wikipedia.org/wiki/List_of_probability_distributions#Discrete_distributions>.
data DiscreteDistribution parameter
	= PoissonDistribution parameter {-lambda-}			-- ^ Defines an /Poisson/-distribution with a particular /lambda/; <https://en.wikipedia.org/wiki/Poisson_distribution>.
	| ShiftedGeometricDistribution parameter {-probability-}	-- ^ Defines an /Geometric/-distribution with a particular probability of success; <https://en.wikipedia.org/wiki/Geometric_distribution>.
	deriving (DiscreteDistribution parameter
-> DiscreteDistribution parameter -> Bool
(DiscreteDistribution parameter
 -> DiscreteDistribution parameter -> Bool)
-> (DiscreteDistribution parameter
    -> DiscreteDistribution parameter -> Bool)
-> Eq (DiscreteDistribution parameter)
forall parameter.
Eq parameter =>
DiscreteDistribution parameter
-> DiscreteDistribution parameter -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DiscreteDistribution parameter
-> DiscreteDistribution parameter -> Bool
$c/= :: forall parameter.
Eq parameter =>
DiscreteDistribution parameter
-> DiscreteDistribution parameter -> Bool
== :: DiscreteDistribution parameter
-> DiscreteDistribution parameter -> Bool
$c== :: forall parameter.
Eq parameter =>
DiscreteDistribution parameter
-> DiscreteDistribution parameter -> Bool
Eq, ReadPrec [DiscreteDistribution parameter]
ReadPrec (DiscreteDistribution parameter)
Int -> ReadS (DiscreteDistribution parameter)
ReadS [DiscreteDistribution parameter]
(Int -> ReadS (DiscreteDistribution parameter))
-> ReadS [DiscreteDistribution parameter]
-> ReadPrec (DiscreteDistribution parameter)
-> ReadPrec [DiscreteDistribution parameter]
-> Read (DiscreteDistribution parameter)
forall parameter.
Read parameter =>
ReadPrec [DiscreteDistribution parameter]
forall parameter.
Read parameter =>
ReadPrec (DiscreteDistribution parameter)
forall parameter.
Read parameter =>
Int -> ReadS (DiscreteDistribution parameter)
forall parameter.
Read parameter =>
ReadS [DiscreteDistribution parameter]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [DiscreteDistribution parameter]
$creadListPrec :: forall parameter.
Read parameter =>
ReadPrec [DiscreteDistribution parameter]
readPrec :: ReadPrec (DiscreteDistribution parameter)
$creadPrec :: forall parameter.
Read parameter =>
ReadPrec (DiscreteDistribution parameter)
readList :: ReadS [DiscreteDistribution parameter]
$creadList :: forall parameter.
Read parameter =>
ReadS [DiscreteDistribution parameter]
readsPrec :: Int -> ReadS (DiscreteDistribution parameter)
$creadsPrec :: forall parameter.
Read parameter =>
Int -> ReadS (DiscreteDistribution parameter)
Read, Int -> DiscreteDistribution parameter -> ShowS
[DiscreteDistribution parameter] -> ShowS
DiscreteDistribution parameter -> String
(Int -> DiscreteDistribution parameter -> ShowS)
-> (DiscreteDistribution parameter -> String)
-> ([DiscreteDistribution parameter] -> ShowS)
-> Show (DiscreteDistribution parameter)
forall parameter.
Show parameter =>
Int -> DiscreteDistribution parameter -> ShowS
forall parameter.
Show parameter =>
[DiscreteDistribution parameter] -> ShowS
forall parameter.
Show parameter =>
DiscreteDistribution parameter -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DiscreteDistribution parameter] -> ShowS
$cshowList :: forall parameter.
Show parameter =>
[DiscreteDistribution parameter] -> ShowS
show :: DiscreteDistribution parameter -> String
$cshow :: forall parameter.
Show parameter =>
DiscreteDistribution parameter -> String
showsPrec :: Int -> DiscreteDistribution parameter -> ShowS
$cshowsPrec :: forall parameter.
Show parameter =>
Int -> DiscreteDistribution parameter -> ShowS
Show)

instance (Num parameter, Ord parameter, Show parameter) => ToolShed.SelfValidate.SelfValidator (DiscreteDistribution parameter)	where
	getErrors :: DiscreteDistribution parameter -> [String]
getErrors DiscreteDistribution parameter
probabilityDistribution	= [(Bool, String)] -> [String]
ToolShed.SelfValidate.extractErrors ([(Bool, String)] -> [String]) -> [(Bool, String)] -> [String]
forall a b. (a -> b) -> a -> b
$ case DiscreteDistribution parameter
probabilityDistribution of
		PoissonDistribution parameter
lambda			-> [(parameter
lambda parameter -> parameter -> Bool
forall a. Ord a => a -> a -> Bool
<= parameter
0, String
"'lambda' must exceed zero; " String -> ShowS
forall a. [a] -> [a] -> [a]
++ DiscreteDistribution parameter -> String
forall a. Show a => a -> String
show DiscreteDistribution parameter
probabilityDistribution String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".")]
		ShiftedGeometricDistribution parameter
probability	-> [(((parameter -> Bool) -> Bool) -> [parameter -> Bool] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ((parameter -> Bool) -> parameter -> Bool
forall a b. (a -> b) -> a -> b
$ parameter
probability) [(parameter -> parameter -> Bool
forall a. Ord a => a -> a -> Bool
<= parameter
0), (parameter -> parameter -> Bool
forall a. Ord a => a -> a -> Bool
> parameter
1)], String
"probability must be in the semi-closed unit-interval (0, 1]; " String -> ShowS
forall a. [a] -> [a] -> [a]
++ DiscreteDistribution parameter -> String
forall a. Show a => a -> String
show DiscreteDistribution parameter
probabilityDistribution String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".")]

-- | Defines a common interface for probability-distributions.
class Distribution probabilityDistribution	where
	generatePopulation
		:: (Fractional sample, System.Random.RandomGen randomGen)
		=> probabilityDistribution
		-> randomGen	-- ^ A generator of /uniformly distributed/ random numbers.
		-> [sample]	-- ^ CAVEAT: the integers generated for discrete distributions are represented by a fractional type; use 'generateDiscretePopulation' if this is a problem.

	getMean :: Fractional mean => probabilityDistribution -> mean	-- ^ The theoretical mean.

	getStandardDeviation :: Floating standardDeviation => probabilityDistribution -> standardDeviation-- ^ The theoretical standard-deviation.
	getStandardDeviation	= standardDeviation -> standardDeviation
forall a. Floating a => a -> a
sqrt (standardDeviation -> standardDeviation)
-> (probabilityDistribution -> standardDeviation)
-> probabilityDistribution
-> standardDeviation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. probabilityDistribution -> standardDeviation
forall probabilityDistribution variance.
(Distribution probabilityDistribution, Floating variance) =>
probabilityDistribution -> variance
getVariance	-- Default implementation.

	getVariance :: Floating variance => probabilityDistribution -> variance	-- ^ The theoretical variance.
	getVariance	= variance -> variance
forall n. Num n => n -> n
Math.Power.square (variance -> variance)
-> (probabilityDistribution -> variance)
-> probabilityDistribution
-> variance
forall b c a. (b -> c) -> (a -> b) -> a -> c
. probabilityDistribution -> variance
forall probabilityDistribution variance.
(Distribution probabilityDistribution, Floating variance) =>
probabilityDistribution -> variance
getStandardDeviation	-- Default implementation.

instance (RealFloat parameter, Show parameter, System.Random.Random parameter) => Distribution (ContinuousDistribution parameter)	where
	generatePopulation :: ContinuousDistribution parameter -> randomGen -> [sample]
generatePopulation ContinuousDistribution parameter
probabilityDistribution	= (parameter -> sample) -> [parameter] -> [sample]
forall a b. (a -> b) -> [a] -> [b]
map parameter -> sample
forall a b. (Real a, Fractional b) => a -> b
realToFrac {-parameter -> sample-} ([parameter] -> [sample])
-> (randomGen -> [parameter]) -> randomGen -> [sample]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ContinuousDistribution parameter -> randomGen -> [parameter]
forall f randomGen.
(RealFloat f, Show f, Random f, RandomGen randomGen) =>
ContinuousDistribution f -> randomGen -> [f]
generateContinuousPopulation ContinuousDistribution parameter
probabilityDistribution

	getMean :: ContinuousDistribution parameter -> mean
getMean (ExponentialDistribution parameter
lambda)			= parameter -> mean
forall a b. (Real a, Fractional b) => a -> b
realToFrac (parameter -> mean) -> parameter -> mean
forall a b. (a -> b) -> a -> b
$ parameter -> parameter
forall a. Fractional a => a -> a
recip parameter
lambda
	getMean (LogNormalDistribution parameter
location parameter
scale2)			= parameter -> mean
forall a b. (Real a, Fractional b) => a -> b
realToFrac (parameter -> mean)
-> (parameter -> parameter) -> parameter -> mean
forall b c a. (b -> c) -> (a -> b) -> a -> c
. parameter -> parameter
forall a. Floating a => a -> a
exp (parameter -> parameter)
-> (parameter -> parameter) -> parameter -> parameter
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (parameter -> parameter -> parameter
forall a. Num a => a -> a -> a
+ parameter
location) (parameter -> mean) -> parameter -> mean
forall a b. (a -> b) -> a -> b
$ parameter
scale2 parameter -> parameter -> parameter
forall a. Fractional a => a -> a -> a
/ parameter
2
	getMean (NormalDistribution parameter
mean parameter
_)				= parameter -> mean
forall a b. (Real a, Fractional b) => a -> b
realToFrac parameter
mean
	getMean (UniformDistribution (parameter
minParameter, parameter
maxParameter))	= parameter -> mean
forall a b. (Real a, Fractional b) => a -> b
realToFrac (parameter -> mean) -> parameter -> mean
forall a b. (a -> b) -> a -> b
$ (parameter
minParameter parameter -> parameter -> parameter
forall a. Num a => a -> a -> a
+ parameter
maxParameter) parameter -> parameter -> parameter
forall a. Fractional a => a -> a -> a
/ parameter
2

	getVariance :: ContinuousDistribution parameter -> variance
getVariance (ExponentialDistribution parameter
lambda)			= parameter -> variance
forall a b. (Real a, Fractional b) => a -> b
realToFrac (parameter -> variance)
-> (parameter -> parameter) -> parameter -> variance
forall b c a. (b -> c) -> (a -> b) -> a -> c
. parameter -> parameter
forall a. Fractional a => a -> a
recip (parameter -> variance) -> parameter -> variance
forall a b. (a -> b) -> a -> b
$ parameter -> parameter
forall n. Num n => n -> n
Math.Power.square parameter
lambda
	getVariance (LogNormalDistribution parameter
location parameter
scale2)		= parameter -> variance
forall a b. (Real a, Fractional b) => a -> b
realToFrac (parameter -> variance) -> parameter -> variance
forall a b. (a -> b) -> a -> b
$ (parameter -> parameter
forall a. Floating a => a -> a
exp parameter
scale2 parameter -> parameter -> parameter
forall a. Num a => a -> a -> a
- parameter
1) parameter -> parameter -> parameter
forall a. Num a => a -> a -> a
* parameter -> parameter
forall a. Floating a => a -> a
exp (parameter
2 parameter -> parameter -> parameter
forall a. Num a => a -> a -> a
* parameter
location parameter -> parameter -> parameter
forall a. Num a => a -> a -> a
+ parameter
scale2)	-- N.B.: for standard-deviation == mean, use scale^2 == ln 2.
	getVariance (NormalDistribution parameter
_ parameter
variance)			= parameter -> variance
forall a b. (Real a, Fractional b) => a -> b
realToFrac parameter
variance
	getVariance (UniformDistribution (parameter
minParameter, parameter
maxParameter))	= parameter -> variance
forall a b. (Real a, Fractional b) => a -> b
realToFrac (parameter -> variance) -> parameter -> variance
forall a b. (a -> b) -> a -> b
$ parameter -> parameter
forall n. Num n => n -> n
Math.Power.square (parameter
maxParameter parameter -> parameter -> parameter
forall a. Num a => a -> a -> a
- parameter
minParameter) parameter -> parameter -> parameter
forall a. Fractional a => a -> a -> a
/ parameter
12

instance (RealFloat parameter, Show parameter, System.Random.Random parameter) => Distribution (DiscreteDistribution parameter)	where
	generatePopulation :: DiscreteDistribution parameter -> randomGen -> [sample]
generatePopulation DiscreteDistribution parameter
probabilityDistribution		= (Integer -> sample) -> [Integer] -> [sample]
forall a b. (a -> b) -> [a] -> [b]
map Integer -> sample
forall a. Num a => Integer -> a
fromInteger ([Integer] -> [sample])
-> (randomGen -> [Integer]) -> randomGen -> [sample]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DiscreteDistribution parameter -> randomGen -> [Integer]
forall sample parameter randomGen.
(Integral sample, Ord parameter, RealFloat parameter,
 Show parameter, Random parameter, RandomGen randomGen) =>
DiscreteDistribution parameter -> randomGen -> [sample]
generateDiscretePopulation DiscreteDistribution parameter
probabilityDistribution

	getMean :: DiscreteDistribution parameter -> mean
getMean (PoissonDistribution parameter
lambda)			= parameter -> mean
forall a b. (Real a, Fractional b) => a -> b
realToFrac parameter
lambda
	getMean (ShiftedGeometricDistribution parameter
probability)	= parameter -> mean
forall a b. (Real a, Fractional b) => a -> b
realToFrac (parameter -> mean) -> parameter -> mean
forall a b. (a -> b) -> a -> b
$ parameter -> parameter
forall a. Fractional a => a -> a
recip parameter
probability

	getVariance :: DiscreteDistribution parameter -> variance
getVariance (PoissonDistribution parameter
lambda)		= parameter -> variance
forall a b. (Real a, Fractional b) => a -> b
realToFrac parameter
lambda
	getVariance (ShiftedGeometricDistribution parameter
probability)	= parameter -> variance
forall a b. (Real a, Fractional b) => a -> b
realToFrac (parameter -> variance) -> parameter -> variance
forall a b. (a -> b) -> a -> b
$ (parameter
1 parameter -> parameter -> parameter
forall a. Num a => a -> a -> a
- parameter
probability) parameter -> parameter -> parameter
forall a. Fractional a => a -> a -> a
/ parameter -> parameter
forall n. Num n => n -> n
Math.Power.square parameter
probability

{- |
	* Converts a pair of independent /uniformly distributed/ random numbers, within the /semi-closed unit interval/ /(0,1]/,
	to a pair of independent /normally distributed/ random numbers, of standardized /mean/=0, and /variance/=1.

	* <https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform>.
-}
boxMullerTransform :: (
	Floating	f,
	Ord		f,
	Show		f
 )
	=> (f, f)	-- ^ Independent, /uniformly distributed/ random numbers, which must be within the /semi-closed unit interval/, /(0,1]/.
	-> (f, f)	-- ^ Independent, /normally distributed/ random numbers, with standardized /mean/=0 and /variance/=1.
boxMullerTransform :: (f, f) -> (f, f)
boxMullerTransform (f, f)
cartesian
	| Bool -> Bool
not (Bool -> Bool) -> ((Bool, Bool) -> Bool) -> (Bool, Bool) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Bool -> Bool) -> (Bool, Bool) -> Bool
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Bool -> Bool -> Bool
(&&) ((Bool, Bool) -> Bool) -> (Bool, Bool) -> Bool
forall a b. (a -> b) -> a -> b
$ (f -> Bool) -> (f, f) -> (Bool, Bool)
forall a b. (a -> b) -> (a, a) -> (b, b)
ToolShed.Data.Pair.mirror f -> Bool
forall n. (Num n, Ord n) => n -> Bool
inSemiClosedUnitInterval (f, f)
cartesian	= String -> (f, f)
forall a. HasCallStack => String -> a
error (String -> (f, f)) -> String -> (f, f)
forall a b. (a -> b) -> a -> b
$ String
"Factory.Math.Probability.boxMullerTransform:\tspecified Cartesian coordinates, must be within semi-closed unit-interval (0, 1]; " String -> ShowS
forall a. [a] -> [a] -> [a]
++ (f, f) -> String
forall a. Show a => a -> String
show (f, f)
cartesian
	| Bool
otherwise										= (f, f) -> (f, f)
forall f. Floating f => (f, f) -> (f, f)
polarToCartesianTransform ((f, f) -> (f, f)) -> (f, f) -> (f, f)
forall a b. (a -> b) -> a -> b
$ (f -> f
forall a. Floating a => a -> a
sqrt (f -> f) -> (f -> f) -> f -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f -> f
forall n. Num n => n -> n
negate (f -> f) -> (f -> f) -> f -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (f -> f -> f
forall a. Num a => a -> a -> a
* f
2) (f -> f) -> (f -> f) -> f -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f -> f
forall a. Floating a => a -> a
log (f -> f) -> (f -> f) -> (f, f) -> (f, f)
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** (f -> f -> f
forall a. Num a => a -> a -> a
* f
2) (f -> f) -> (f -> f) -> f -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (f -> f -> f
forall a. Num a => a -> a -> a
* f
forall a. Floating a => a
pi)) (f, f)
cartesian
	where
		inSemiClosedUnitInterval :: (Num n, Ord n) => n -> Bool
		inSemiClosedUnitInterval :: n -> Bool
inSemiClosedUnitInterval	= (Bool -> Bool -> Bool) -> (Bool, Bool) -> Bool
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Bool -> Bool -> Bool
(&&) ((Bool, Bool) -> Bool) -> (n -> (Bool, Bool)) -> n -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((n -> n -> Bool
forall a. Ord a => a -> a -> Bool
> n
0) (n -> Bool) -> (n -> Bool) -> n -> (Bool, Bool)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& (n -> n -> Bool
forall a. Ord a => a -> a -> Bool
<= n
1))

		polarToCartesianTransform :: Floating f => (f, f) -> (f, f)
		polarToCartesianTransform :: (f, f) -> (f, f)
polarToCartesianTransform	= (f -> f -> f) -> (f, f) -> f
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry f -> f -> f
forall a. Num a => a -> a -> a
(*) ((f, f) -> f) -> ((f, f) -> (f, f)) -> (f, f) -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (f -> f) -> (f, f) -> (f, f)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
Control.Arrow.second f -> f
forall a. Floating a => a -> a
cos ((f, f) -> f) -> ((f, f) -> f) -> (f, f) -> (f, f)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& (f -> f -> f) -> (f, f) -> f
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry f -> f -> f
forall a. Num a => a -> a -> a
(*) ((f, f) -> f) -> ((f, f) -> (f, f)) -> (f, f) -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (f -> f) -> (f, f) -> (f, f)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
Control.Arrow.second f -> f
forall a. Floating a => a -> a
sin

{- |
	* Uses the supplied random-number generator,
	to generate a conceptually infinite list, of /normally distributed/ random numbers, with standardized /mean/=0, and /variance/=1.

	* <https://en.wikipedia.org/wiki/Normal_distribution>, <https://mathworld.wolfram.com/NormalDistribution.html>.
-}
generateStandardizedNormalDistribution :: (
	RealFloat		f,
	Show			f,
	System.Random.Random	f,
	System.Random.RandomGen	randomGen
 ) => randomGen -> [f]
generateStandardizedNormalDistribution :: randomGen -> [f]
generateStandardizedNormalDistribution	= [(f, f)] -> [f]
forall a. [(a, a)] -> [a]
ToolShed.Data.List.linearise ([(f, f)] -> [f]) -> (randomGen -> [(f, f)]) -> randomGen -> [f]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([f] -> [f] -> [(f, f)]) -> ([f], [f]) -> [(f, f)]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((f -> f -> (f, f)) -> [f] -> [f] -> [(f, f)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith ((f -> f -> (f, f)) -> [f] -> [f] -> [(f, f)])
-> (f -> f -> (f, f)) -> [f] -> [f] -> [(f, f)]
forall a b. (a -> b) -> a -> b
$ ((f, f) -> (f, f)) -> f -> f -> (f, f)
forall a b c. ((a, b) -> c) -> a -> b -> c
curry (f, f) -> (f, f)
forall f. (Floating f, Ord f, Show f) => (f, f) -> (f, f)
boxMullerTransform) (([f], [f]) -> [(f, f)])
-> (randomGen -> ([f], [f])) -> randomGen -> [(f, f)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (randomGen -> [f]) -> (randomGen, randomGen) -> ([f], [f])
forall a b. (a -> b) -> (a, a) -> (b, b)
ToolShed.Data.Pair.mirror (
	(f, f) -> randomGen -> [f]
forall a g. (Random a, RandomGen g) => (a, a) -> g -> [a]
System.Random.randomRs (f -> f
forall a. RealFloat a => a -> a
minPositiveFloat f
forall a. HasCallStack => a
undefined, f
1)
 ) ((randomGen, randomGen) -> ([f], [f]))
-> (randomGen -> (randomGen, randomGen)) -> randomGen -> ([f], [f])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. randomGen -> (randomGen, randomGen)
forall g. RandomGen g => g -> (g, g)
System.Random.split

-- | Stretches and shifts a /distribution/ to achieve the required /mean/ and /standard-deviation/.
reProfile :: (Distribution distribution, Floating n) => distribution -> [n] -> [n]
reProfile :: distribution -> [n] -> [n]
reProfile distribution
distribution	= (n -> n) -> [n] -> [n]
forall a b. (a -> b) -> [a] -> [b]
map ((n -> n -> n
forall a. Num a => a -> a -> a
+ distribution -> n
forall probabilityDistribution mean.
(Distribution probabilityDistribution, Fractional mean) =>
probabilityDistribution -> mean
getMean distribution
distribution) (n -> n) -> (n -> n) -> n -> n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n -> n -> n
forall a. Num a => a -> a -> a
* distribution -> n
forall probabilityDistribution variance.
(Distribution probabilityDistribution, Floating variance) =>
probabilityDistribution -> variance
getStandardDeviation distribution
distribution))

-- | Uses the supplied random-number generator, to generate a conceptually infinite population, with the specified continuous probability-distribution.
generateContinuousPopulation :: (
	RealFloat		f,
	Show			f,
	System.Random.Random	f,
	System.Random.RandomGen	randomGen
 )
	=> ContinuousDistribution f
	-> randomGen	-- ^ A generator of /uniformly distributed/ random numbers.
	-> [f]
generateContinuousPopulation :: ContinuousDistribution f -> randomGen -> [f]
generateContinuousPopulation ContinuousDistribution f
probabilityDistribution randomGen
randomGen
	| Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ContinuousDistribution f -> Bool
forall v. SelfValidator v => v -> Bool
ToolShed.SelfValidate.isValid ContinuousDistribution f
probabilityDistribution	= String -> [f]
forall a. HasCallStack => String -> a
error (String -> [f]) -> String -> [f]
forall a b. (a -> b) -> a -> b
$ String
"Factory.Math.Probability.generateContinuousPopulation:\t" String -> ShowS
forall a. [a] -> [a] -> [a]
++ ContinuousDistribution f -> String
forall v. SelfValidator v => v -> String
ToolShed.SelfValidate.getFirstError ContinuousDistribution f
probabilityDistribution
	| Bool
otherwise							= (
		case ContinuousDistribution f
probabilityDistribution of
			ExponentialDistribution f
lambda		-> let
				quantile :: f -> f
quantile	= (f -> f -> f
forall a. Fractional a => a -> a -> a
/ f
lambda) (f -> f) -> (f -> f) -> f -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f -> f
forall n. Num n => n -> n
negate (f -> f) -> (f -> f) -> f -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f -> f
forall a. Floating a => a -> a
log (f -> f) -> (f -> f) -> f -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (f
1 f -> f -> f
forall a. Num a => a -> a -> a
-)	-- <https://en.wikipedia.org/wiki/Quantile_function>.
			 in (f -> f) -> [f] -> [f]
forall a b. (a -> b) -> [a] -> [b]
map f -> f
quantile ([f] -> [f]) -> (randomGen -> [f]) -> randomGen -> [f]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (f, f) -> randomGen -> [f]
forall a g. (Random a, RandomGen g) => (a, a) -> g -> [a]
System.Random.randomRs (f
0, f
1)
			LogNormalDistribution f
location f
scale2	-> (f -> f) -> [f] -> [f]
forall a b. (a -> b) -> [a] -> [b]
map (
				f -> f
forall a. Floating a => a -> a
exp (f -> f) -> (f -> f) -> f -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (f -> f -> f
forall a. Num a => a -> a -> a
+ f
location) (f -> f) -> (f -> f) -> f -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (f -> f -> f
forall a. Num a => a -> a -> a
* f -> f
forall a. Floating a => a -> a
sqrt f
scale2)	-- Stretch the standard-deviation & re-locate the mean to that specified for the log-space, then return to the original coordinates.
			 ) ([f] -> [f]) -> (randomGen -> [f]) -> randomGen -> [f]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. randomGen -> [f]
forall f randomGen.
(RealFloat f, Show f, Random f, RandomGen randomGen) =>
randomGen -> [f]
generateStandardizedNormalDistribution
			NormalDistribution f
_ f
_			-> ContinuousDistribution f -> [f] -> [f]
forall distribution n.
(Distribution distribution, Floating n) =>
distribution -> [n] -> [n]
reProfile ContinuousDistribution f
probabilityDistribution ([f] -> [f]) -> (randomGen -> [f]) -> randomGen -> [f]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. randomGen -> [f]
forall f randomGen.
(RealFloat f, Show f, Random f, RandomGen randomGen) =>
randomGen -> [f]
generateStandardizedNormalDistribution
			UniformDistribution (f, f)
interval		-> (f, f) -> randomGen -> [f]
forall a g. (Random a, RandomGen g) => (a, a) -> g -> [a]
System.Random.randomRs (f, f)
interval
	) randomGen
randomGen

{- |
	* Uses the supplied random-number generator,
	to generate a conceptually infinite population, of random integers conforming to the /Poisson distribution/; <https://en.wikipedia.org/wiki/Poisson_distribution>.

	* CAVEAT:
		uses an algorithm by Knuth, which having a /linear time-complexity/ in /lambda/, can be intolerably slow;
		also, the term @exp $ negate lambda@, underflows for large /lambda/;
		so for large /lambda/, this implementation returns the appropriate 'NormalDistribution'.
-}
generatePoissonDistribution :: (
	Integral		sample,
	RealFloat		lambda,
	Show			lambda,
	System.Random.Random	lambda,
	System.Random.RandomGen	randomGen
 )
	=> lambda	-- ^ Defines the required approximate value of both /mean/ and /variance/.
	-> randomGen
	-> [sample]
generatePoissonDistribution :: lambda -> randomGen -> [sample]
generatePoissonDistribution lambda
lambda
	| lambda
lambda lambda -> lambda -> Bool
forall a. Ord a => a -> a -> Bool
<= lambda
0	= String -> randomGen -> [sample]
forall a. HasCallStack => String -> a
error (String -> randomGen -> [sample])
-> String -> randomGen -> [sample]
forall a b. (a -> b) -> a -> b
$ String
"Factory.Math.Probability.generatePoissonDistribution:\tlambda must exceed zero " String -> ShowS
forall a. [a] -> [a] -> [a]
++ lambda -> String
forall a. Show a => a -> String
show lambda
lambda
	| lambda
lambda lambda -> lambda -> Bool
forall a. Ord a => a -> a -> Bool
> (
		lambda -> lambda
forall n. Num n => n -> n
negate (lambda -> lambda) -> (lambda -> lambda) -> lambda -> lambda
forall b c a. (b -> c) -> (a -> b) -> a -> c
. lambda -> lambda
forall a. Floating a => a -> a
log (lambda -> lambda) -> lambda -> lambda
forall a b. (a -> b) -> a -> b
$ lambda -> lambda
forall a. RealFloat a => a -> a
minPositiveFloat lambda
lambda	-- Guard against underflow, in the user-defined type for lambda.
	)		= (sample -> Bool) -> [sample] -> [sample]
forall a. (a -> Bool) -> [a] -> [a]
filter (sample -> sample -> Bool
forall a. Ord a => a -> a -> Bool
>= sample
0) ([sample] -> [sample])
-> (randomGen -> [sample]) -> randomGen -> [sample]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Double -> sample) -> [Double] -> [sample]
forall a b. (a -> b) -> [a] -> [b]
map Double -> sample
forall a b. (RealFrac a, Integral b) => a -> b
round ([Double] -> [sample])
-> (randomGen -> [Double]) -> randomGen -> [sample]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (DiscreteDistribution lambda -> [Double] -> [Double]
forall distribution n.
(Distribution distribution, Floating n) =>
distribution -> [n] -> [n]
reProfile (lambda -> DiscreteDistribution lambda
forall parameter. parameter -> DiscreteDistribution parameter
PoissonDistribution lambda
lambda) :: [Double] -> [Double]) ([Double] -> [Double])
-> (randomGen -> [Double]) -> randomGen -> [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. randomGen -> [Double]
forall f randomGen.
(RealFloat f, Show f, Random f, RandomGen randomGen) =>
randomGen -> [f]
generateStandardizedNormalDistribution
	| Bool
otherwise	= randomGen -> [sample]
generator
	where
		generator :: randomGen -> [sample]
generator	= (sample -> [sample] -> [sample]) -> (sample, [sample]) -> [sample]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (:) ((sample, [sample]) -> [sample])
-> (randomGen -> (sample, [sample])) -> randomGen -> [sample]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (
			(sample, lambda) -> sample
forall a b. (a, b) -> a
fst ((sample, lambda) -> sample)
-> (randomGen -> (sample, lambda)) -> randomGen -> sample
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(sample, lambda)] -> (sample, lambda)
forall a. [a] -> a
head ([(sample, lambda)] -> (sample, lambda))
-> (randomGen -> [(sample, lambda)])
-> randomGen
-> (sample, lambda)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((sample, lambda) -> Bool)
-> [(sample, lambda)] -> [(sample, lambda)]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (
				(lambda -> lambda -> Bool
forall a. Ord a => a -> a -> Bool
> lambda -> lambda
forall a. Floating a => a -> a
exp (lambda -> lambda
forall n. Num n => n -> n
negate lambda
lambda)) (lambda -> Bool)
-> ((sample, lambda) -> lambda) -> (sample, lambda) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (sample, lambda) -> lambda
forall a b. (a, b) -> b
snd	-- CAVEAT: underflows if lambda > (103 :: Float, 745 :: Double).
			) ([(sample, lambda)] -> [(sample, lambda)])
-> (randomGen -> [(sample, lambda)])
-> randomGen
-> [(sample, lambda)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((sample, lambda) -> lambda -> (sample, lambda))
-> (sample, lambda) -> [lambda] -> [(sample, lambda)]
forall b a. (b -> a -> b) -> b -> [a] -> [b]
scanl (
				\(sample, lambda)
accumulator lambda
random	-> sample -> sample
forall a. Enum a => a -> a
succ (sample -> sample)
-> (lambda -> lambda) -> (sample, lambda) -> (sample, lambda)
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** (lambda -> lambda -> lambda
forall a. Num a => a -> a -> a
* lambda
random) ((sample, lambda) -> (sample, lambda))
-> (sample, lambda) -> (sample, lambda)
forall a b. (a -> b) -> a -> b
$ (sample, lambda)
accumulator
			) (sample -> sample
forall n. Num n => n -> n
negate sample
1, lambda
1) ([lambda] -> [(sample, lambda)])
-> (randomGen -> [lambda]) -> randomGen -> [(sample, lambda)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (lambda, lambda) -> randomGen -> [lambda]
forall a g. (Random a, RandomGen g) => (a, a) -> g -> [a]
System.Random.randomRs (lambda
0, lambda
1) (randomGen -> sample)
-> (randomGen -> [sample])
-> (randomGen, randomGen)
-> (sample, [sample])
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** randomGen -> [sample]
generator {-recurse-}
		 ) ((randomGen, randomGen) -> (sample, [sample]))
-> (randomGen -> (randomGen, randomGen))
-> randomGen
-> (sample, [sample])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. randomGen -> (randomGen, randomGen)
forall g. RandomGen g => g -> (g, g)
System.Random.split

-- | Uses the supplied random-number generator, to generate a conceptually infinite population, with the specified discrete probability-distribution.
generateDiscretePopulation :: (
	Integral		sample,
	Ord			parameter,
	RealFloat		parameter,
	Show			parameter,
	System.Random.Random	parameter,
	System.Random.RandomGen	randomGen
 )
	=> DiscreteDistribution parameter
	-> randomGen	-- ^ A generator of /uniformly distributed/ random numbers.
	-> [sample]
generateDiscretePopulation :: DiscreteDistribution parameter -> randomGen -> [sample]
generateDiscretePopulation DiscreteDistribution parameter
probabilityDistribution randomGen
randomGen
	| Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ DiscreteDistribution parameter -> Bool
forall v. SelfValidator v => v -> Bool
ToolShed.SelfValidate.isValid DiscreteDistribution parameter
probabilityDistribution	= String -> [sample]
forall a. HasCallStack => String -> a
error (String -> [sample]) -> String -> [sample]
forall a b. (a -> b) -> a -> b
$ String
"Factory.Math.Probability.generateDiscretePopulation:\t" String -> ShowS
forall a. [a] -> [a] -> [a]
++ DiscreteDistribution parameter -> String
forall v. SelfValidator v => v -> String
ToolShed.SelfValidate.getFirstError DiscreteDistribution parameter
probabilityDistribution
	| Bool
otherwise							= (
		case DiscreteDistribution parameter
probabilityDistribution of
			PoissonDistribution parameter
lambda	-> parameter -> randomGen -> [sample]
forall sample lambda randomGen.
(Integral sample, RealFloat lambda, Show lambda, Random lambda,
 RandomGen randomGen) =>
lambda -> randomGen -> [sample]
generatePoissonDistribution parameter
lambda
			ShiftedGeometricDistribution parameter
probability
				| parameter
probability parameter -> parameter -> Bool
forall a. Eq a => a -> a -> Bool
== parameter
1	-> [sample] -> randomGen -> [sample]
forall a b. a -> b -> a
const ([sample] -> randomGen -> [sample])
-> [sample] -> randomGen -> [sample]
forall a b. (a -> b) -> a -> b
$ sample -> [sample]
forall a. a -> [a]
repeat sample
1	-- The first Bernoulli Trial is guaranteed to succeed.
				| Bool
otherwise		-> (Rational -> sample) -> [Rational] -> [sample]
forall a b. (a -> b) -> [a] -> [b]
map Rational -> sample
forall a b. (RealFrac a, Integral b) => a -> b
ceiling {-minimum 1-} ([Rational] -> [sample])
-> (randomGen -> [Rational]) -> randomGen -> [sample]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (\[Rational]
x -> [Rational]
x :: [Rational]) ([Rational] -> [Rational])
-> (randomGen -> [Rational]) -> randomGen -> [Rational]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ContinuousDistribution parameter -> randomGen -> [Rational]
forall probabilityDistribution sample randomGen.
(Distribution probabilityDistribution, Fractional sample,
 RandomGen randomGen) =>
probabilityDistribution -> randomGen -> [sample]
generatePopulation (parameter -> ContinuousDistribution parameter
forall parameter. parameter -> ContinuousDistribution parameter
ExponentialDistribution (parameter -> ContinuousDistribution parameter)
-> (parameter -> parameter)
-> parameter
-> ContinuousDistribution parameter
forall b c a. (b -> c) -> (a -> b) -> a -> c
. parameter -> parameter
forall n. Num n => n -> n
negate (parameter -> ContinuousDistribution parameter)
-> parameter -> ContinuousDistribution parameter
forall a b. (a -> b) -> a -> b
$ parameter -> parameter
forall a. Floating a => a -> a
log (parameter
1 parameter -> parameter -> parameter
forall a. Num a => a -> a -> a
- parameter
probability))	-- The geometric distribution is a discrete version of the exponential distribution.
	) randomGen
randomGen