/** * Poisson distribution - probability mass function * A discrete probability distribution that expresses the probability of a given number of events * occurring in a fixed interval of time and/or space if these events occur with a known average * rate and independently of the time since the last event. * https://en.wikipedia.org/wiki/Poisson_distribution * * λᵏℯ^⁻λ * P(k events in an interval) = ------ * k! * * @param int $k events in the interval * @param float $λ average number of successful events per interval * * @return float The Poisson probability of observing k successful events in an interval */ public static function PMF(int $k, float $λ) : float { Support::checkLimits(self::LIMITS, ['k' => $k, 'λ' => $λ]); $λᵏℯ^−λ = pow($λ, $k) * exp(-$λ); $k! = Combinatorics::factorial($k); return $λᵏℯ^−λ / $k!; }
/** * Binomial distribution - probability mass function * https://en.wikipedia.org/wiki/Binomial_distribution * * P(X = r) = nCr pʳ (1 - p)ⁿ⁻ʳ * * @param int $n number of events * @param int $r number of successful events * @param float $p probability of success * * @return float */ public static function PMF(int $n, int $r, float $p) : float { Support::checkLimits(self::LIMITS, ['n' => $n, 'r' => $r, 'p' => $p]); $nCr = Combinatorics::combinations($n, $r); $pʳ = pow($p, $r); $⟮1 − p⟯ⁿ⁻ʳ = pow(1 - $p, $n - $r); return $nCr * $pʳ * $⟮1 − p⟯ⁿ⁻ʳ; }
/** * Probability mass function * * b(x; r, p) = ₓ₋₁Cᵣ₋₁ pʳ * (1 - p)ˣ⁻ʳ * * @param int $x number of trials required to produce r successes * @param int $r number of successful events * @param float $p probability of success on an individual trial * * @return float */ public static function PMF(int $x, int $r, float $p) : float { Support::checkLimits(self::LIMITS, ['x' => $x, 'r' => $r, 'p' => $p]); $ₓ₋₁Cᵣ₋₁ = Combinatorics::combinations($x - 1, $r - 1); $pʳ = pow($p, $r); $⟮1 − p⟯ˣ⁻ʳ = pow(1 - $p, $x - $r); return $ₓ₋₁Cᵣ₋₁ * $pʳ * $⟮1 − p⟯ˣ⁻ʳ; }
/** * Multinomial distribution (multivariate) - probability mass function * * https://en.wikipedia.org/wiki/Multinomial_distribution * * n! * pmf = ------- p₁ˣ¹⋯pkˣᵏ * x₁!⋯xk! * * n = number of trials (sum of the frequencies) = x₁ + x₂ + ⋯ xk * * @param array $frequencies * @param array $probabilities * * @return float */ public static function PMF(array $frequencies, array $probabilities) : float { // Must have a probability for each frequency if (count($frequencies) !== count($probabilities)) { throw new Exception\BadDataException('Number of frequencies does not match number of probabilities.'); } // Probabilities must add up to 1 if (round(array_sum($probabilities), 1) != 1) { throw new Exception\BadDataException('Probabilities do not add up to 1.'); } $n = array_sum($frequencies); $n! = Combinatorics::factorial($n); $x₁!⋯xk! = array_product(array_map('MathPHP\\Probability\\Combinatorics::factorial', $frequencies)); $p₁ˣ¹⋯pkˣᵏ = array_product(array_map(function ($x, $p) { return $p ** $x; }, $frequencies, $probabilities)); return $n! / $x₁!⋯xk! * $p₁ˣ¹⋯pkˣᵏ; }
/** * Gamma function - Stirling approximation * https://en.wikipedia.org/wiki/Gamma_function * https://en.wikipedia.org/wiki/Stirling%27s_approximation * https://www.wolframalpha.com/input/?i=Gamma(n)&lk=3 * * For postive integers: * Γ(n) = (n - 1)! * * For positive real numbers -- approximation: * ___ * __ / 1 / 1 \ n * Γ(n)≈ √2π ℯ⁻ⁿ / - | n + ----------- | * √ n \ 12n - 1/10n / * * @param number $n * * @return number */ public static function gammaStirling($n) { // Basic integer/factorial cases if ($n == 0) { return \INF; } // Negative integer, or negative int as a float if ((is_int($n) || is_numeric($n) && abs($n - round($n)) < 1.0E-5) && $n < 0) { return -\INF; } // Positive integer, or postive int as a float if ((is_int($n) || is_numeric($n) && abs($n - round($n)) < 1.0E-5) && $n > 0) { return Combinatorics::factorial(round($n) - 1); } // Compute parts of equation $√2π = sqrt(2 * \M_PI); $ℯ⁻ⁿ = exp(-$n); $√1/n = sqrt(1 / $n); $⟮n + 1/⟮12n − 1/10n⟯⟯ⁿ = pow($n + 1 / (12 * $n - 1 / (10 * $n)), $n); /** * Put it all together: * ___ * __ / 1 / 1 \ n * Γ(n)≈ √2π ℯ⁻ⁿ / - | n + ----------- | * √ n \ 12n - 1/10n / */ return $√2π * $ℯ⁻ⁿ * $√1/n * $⟮n + 1/⟮12n − 1/10n⟯⟯ⁿ; }
/** * F used within CDF * _ _ * 1 ∞ | / 1 ν \ / ν \ | * Fᵥ,ᵤ(x) = Φ(-μ) + - ∑ | pⱼIy | j + -, - | + qⱼIy | j + 1, - | | * 2 ʲ⁼⁰ |_ \ 2 2 / \ 2 / _| * * where * Φ = cumulative distribution function of the standard normal distribution * Iy(a,b) = regularized incomplete beta function * * x² * y = ------ * x² + ν * * 1 / μ² \ / μ² \ʲ * pⱼ = -- exp| - - | | - | * j! \ 2 / \ 2 / * * μ / μ² \ / μ² \ʲ * qⱼ = ------------ exp| - - | | - | * √2Γ(j + 3/2) \ 2 / \ 2 / * * @param number $x * @param int $ν Degrees of freedom * @param number $μ Noncentrality parameter * * @return number */ private static function F($x, int $ν, $μ) { Support::checkLimits(self::LIMITS, ['x' => $x, 'ν' => $ν, 'μ' => $μ]); $Φ = StandardNormal::CDF(-$μ); $y = $x ** 2 / ($x ** 2 + $ν); $sum = $Φ; $tol = 1.0E-8; $j = 0; do { $exp = exp(-1 * $μ ** 2 / 2) * ($μ ** 2 / 2) ** $j; $pⱼ = 1 / Combinatorics::factorial($j) * $exp; $qⱼ = $μ / sqrt(2) / Special::gamma($j + 3 / 2) * $exp; $I1 = Special::regularizedIncompleteBeta($y, $j + 1 / 2, $ν / 2); $I2 = Special::regularizedIncompleteBeta($y, $j + 1, $ν / 2); $delta = $pⱼ * $I1 + $qⱼ * $I2; $sum += $delta / 2; $j += 1; } while ($delta / $sum > $tol || $j < 10); return $sum; }