Source code for sympy.stats.drv_types

from __future__ import print_function, division

from sympy import (factorial, exp, S, sympify, And, I, zeta, polylog, log, beta, hyper, binomial,
                   Piecewise, floor)
from sympy.stats import density
from sympy.stats.drv import SingleDiscreteDistribution, SingleDiscretePSpace
from sympy.stats.joint_rv import JointPSpace, CompoundDistribution
from sympy.stats.rv import _value_check, RandomSymbol
import random

__all__ = ['Geometric', 'Logarithmic', 'NegativeBinomial', 'Poisson', 'YuleSimon', 'Zeta']


def rv(symbol, cls, *args):
    args = list(map(sympify, args))
    dist = cls(*args)
    dist.check(*args)
    pspace = SingleDiscretePSpace(symbol, dist)
    if any(isinstance(arg, RandomSymbol) for arg in args):
        pspace = JointPSpace(symbol, CompoundDistribution(dist))
    return pspace.value


#-------------------------------------------------------------------------------
# Geometric distribution ------------------------------------------------------------

class GeometricDistribution(SingleDiscreteDistribution):
    _argnames = ('p',)
    set = S.Naturals

    @staticmethod
    def check(p):
        _value_check(And(0 < p, p <= 1), "p must be between 0 and 1")

    def pdf(self, k):
        return (1 - self.p)**(k - 1) * self.p

    def _characteristic_function(self, t):
        p = self.p
        return p * exp(I*t) / (1 - (1 - p)*exp(I*t))

    def _moment_generating_function(self, t):
        p = self.p
        return p * exp(t) / (1 - (1 - p) * exp(t))

[docs]def Geometric(name, p): r""" Create a discrete random variable with a Geometric distribution. The density of the Geometric distribution is given by .. math:: f(k) := p (1 - p)^{k - 1} Parameters ========== p: A probability between 0 and 1 Returns ======= A RandomSymbol. Examples ======== >>> from sympy.stats import Geometric, density, E, variance >>> from sympy import Symbol, S >>> p = S.One / 5 >>> z = Symbol("z") >>> X = Geometric("x", p) >>> density(X)(z) (4/5)**(z - 1)/5 >>> E(X) 5 >>> variance(X) 20 References ========== .. [1] https://en.wikipedia.org/wiki/Geometric_distribution .. [2] http://mathworld.wolfram.com/GeometricDistribution.html """ return rv(name, GeometricDistribution, p)
#------------------------------------------------------------------------------- # Logarithmic distribution ------------------------------------------------------------ class LogarithmicDistribution(SingleDiscreteDistribution): _argnames = ('p',) set = S.Naturals @staticmethod def check(p): _value_check(And(p > 0, p < 1), "p should be between 0 and 1") def pdf(self, k): p = self.p return (-1) * p**k / (k * log(1 - p)) def _characteristic_function(self, t): p = self.p return log(1 - p * exp(I*t)) / log(1 - p) def _moment_generating_function(self, t): p = self.p return log(1 - p * exp(t)) / log(1 - p) def sample(self): ### TODO raise NotImplementedError("Sampling of %s is not implemented" % density(self))
[docs]def Logarithmic(name, p): r""" Create a discrete random variable with a Logarithmic distribution. The density of the Logarithmic distribution is given by .. math:: f(k) := \frac{-p^k}{k \ln{(1 - p)}} Parameters ========== p: A value between 0 and 1 Returns ======= A RandomSymbol. Examples ======== >>> from sympy.stats import Logarithmic, density, E, variance >>> from sympy import Symbol, S >>> p = S.One / 5 >>> z = Symbol("z") >>> X = Logarithmic("x", p) >>> density(X)(z) -5**(-z)/(z*log(4/5)) >>> E(X) -1/(-4*log(5) + 8*log(2)) >>> variance(X) -1/((-4*log(5) + 8*log(2))*(-2*log(5) + 4*log(2))) + 1/(-64*log(2)*log(5) + 64*log(2)**2 + 16*log(5)**2) - 10/(-32*log(5) + 64*log(2)) References ========== .. [1] https://en.wikipedia.org/wiki/Logarithmic_distribution .. [2] http://mathworld.wolfram.com/LogarithmicDistribution.html """ return rv(name, LogarithmicDistribution, p)
#------------------------------------------------------------------------------- # Negative binomial distribution ------------------------------------------------------------ class NegativeBinomialDistribution(SingleDiscreteDistribution): _argnames = ('r', 'p') set = S.Naturals0 @staticmethod def check(r, p): _value_check(r > 0, 'r should be positive') _value_check(And(p > 0, p < 1), 'p should be between 0 and 1') def pdf(self, k): r = self.r p = self.p return binomial(k + r - 1, k) * (1 - p)**r * p**k def _characteristic_function(self, t): r = self.r p = self.p return ((1 - p) / (1 - p * exp(I*t)))**r def _moment_generating_function(self, t): r = self.r p = self.p return ((1 - p) / (1 - p * exp(t)))**r def sample(self): ### TODO raise NotImplementedError("Sampling of %s is not implemented" % density(self))
[docs]def NegativeBinomial(name, r, p): r""" Create a discrete random variable with a Negative Binomial distribution. The density of the Negative Binomial distribution is given by .. math:: f(k) := \binom{k + r - 1}{k} (1 - p)^r p^k Parameters ========== r: A positive value p: A value between 0 and 1 Returns ======= A RandomSymbol. Examples ======== >>> from sympy.stats import NegativeBinomial, density, E, variance >>> from sympy import Symbol, S >>> r = 5 >>> p = S.One / 5 >>> z = Symbol("z") >>> X = NegativeBinomial("x", r, p) >>> density(X)(z) 1024*5**(-z)*binomial(z + 4, z)/3125 >>> E(X) 5/4 >>> variance(X) 25/16 References ========== .. [1] https://en.wikipedia.org/wiki/Negative_binomial_distribution .. [2] http://mathworld.wolfram.com/NegativeBinomialDistribution.html """ return rv(name, NegativeBinomialDistribution, r, p)
#------------------------------------------------------------------------------- # Poisson distribution ------------------------------------------------------------ class PoissonDistribution(SingleDiscreteDistribution): _argnames = ('lamda',) set = S.Naturals0 @staticmethod def check(lamda): _value_check(lamda > 0, "Lambda must be positive") def pdf(self, k): return self.lamda**k / factorial(k) * exp(-self.lamda) def sample(self): def search(x, y, u): while x < y: mid = (x + y)//2 if u <= self.cdf(mid): y = mid else: x = mid + 1 return x u = random.uniform(0, 1) if u <= self.cdf(S.Zero): return S.Zero n = S.One while True: if u > self.cdf(2*n): n *= 2 else: return search(n, 2*n, u) def _characteristic_function(self, t): return exp(self.lamda * (exp(I*t) - 1)) def _moment_generating_function(self, t): return exp(self.lamda * (exp(t) - 1))
[docs]def Poisson(name, lamda): r""" Create a discrete random variable with a Poisson distribution. The density of the Poisson distribution is given by .. math:: f(k) := \frac{\lambda^{k} e^{- \lambda}}{k!} Parameters ========== lamda: Positive number, a rate Returns ======= A RandomSymbol. Examples ======== >>> from sympy.stats import Poisson, density, E, variance >>> from sympy import Symbol, simplify >>> rate = Symbol("lambda", positive=True) >>> z = Symbol("z") >>> X = Poisson("x", rate) >>> density(X)(z) lambda**z*exp(-lambda)/factorial(z) >>> E(X) lambda >>> simplify(variance(X)) lambda References ========== .. [1] https://en.wikipedia.org/wiki/Poisson_distribution .. [2] http://mathworld.wolfram.com/PoissonDistribution.html """ return rv(name, PoissonDistribution, lamda)
#------------------------------------------------------------------------------- # Yule-Simon distribution ------------------------------------------------------------ class YuleSimonDistribution(SingleDiscreteDistribution): _argnames = ('rho',) set = S.Naturals @staticmethod def check(rho): _value_check(rho > 0, 'rho should be positive') def pdf(self, k): rho = self.rho return rho * beta(k, rho + 1) def _cdf(self, x): return Piecewise((1 - floor(x) * beta(floor(x), self.rho + 1), x >= 1), (0, True)) def _characteristic_function(self, t): rho = self.rho return rho * hyper((1, 1), (rho + 2,), exp(I*t)) * exp(I*t) / (rho + 1) def _moment_generating_function(self, t): rho = self.rho return rho * hyper((1, 1), (rho + 2,), exp(t)) * exp(t) / (rho + 1) def sample(self): ### TODO raise NotImplementedError("Sampling of %s is not implemented" % density(self))
[docs]def YuleSimon(name, rho): r""" Create a discrete random variable with a Yule-Simon distribution. The density of the Yule-Simon distribution is given by .. math:: f(k) := \rho B(k, \rho + 1) Parameters ========== rho: A positive value Returns ======= A RandomSymbol. Examples ======== >>> from sympy.stats import YuleSimon, density, E, variance >>> from sympy import Symbol, simplify >>> p = 5 >>> z = Symbol("z") >>> X = YuleSimon("x", p) >>> density(X)(z) 5*beta(z, 6) >>> simplify(E(X)) 5/4 >>> simplify(variance(X)) 25/48 References ========== .. [1] https://en.wikipedia.org/wiki/Yule%E2%80%93Simon_distribution """ return rv(name, YuleSimonDistribution, rho)
#------------------------------------------------------------------------------- # Zeta distribution ------------------------------------------------------------ class ZetaDistribution(SingleDiscreteDistribution): _argnames = ('s',) set = S.Naturals @staticmethod def check(s): _value_check(s > 1, 's should be greater than 1') def pdf(self, k): s = self.s return 1 / (k**s * zeta(s)) def _characteristic_function(self, t): return polylog(self.s, exp(I*t)) / zeta(self.s) def _moment_generating_function(self, t): return polylog(self.s, exp(t)) / zeta(self.s) def sample(self): ### TODO raise NotImplementedError("Sampling of %s is not implemented" % density(self))
[docs]def Zeta(name, s): r""" Create a discrete random variable with a Zeta distribution. The density of the Zeta distribution is given by .. math:: f(k) := \frac{1}{k^s \zeta{(s)}} Parameters ========== s: A value greater than 1 Returns ======= A RandomSymbol. Examples ======== >>> from sympy.stats import Zeta, density, E, variance >>> from sympy import Symbol >>> s = 5 >>> z = Symbol("z") >>> X = Zeta("x", s) >>> density(X)(z) 1/(z**5*zeta(5)) >>> E(X) pi**4/(90*zeta(5)) >>> variance(X) -pi**8/(8100*zeta(5)**2) + zeta(3)/zeta(5) References ========== .. [1] https://en.wikipedia.org/wiki/Zeta_distribution """ return rv(name, ZetaDistribution, s)