Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Random variables and probability spaces
This introduces a class of random variables, with the focus on discrete random variables (i.e. on a discrete probability space). This avoids the problem of defining a measure space and measurable functions. """
#***************************************************************************** # Copyright (C) 2007 David Kohel <kohel@maths.usyd.edu.au> # # Distributed under the terms of the GNU General Public License (GPL) # # http://www.gnu.org/licenses/ #*****************************************************************************
from sage.structure.parent_base import ParentWithBase from sage.functions.log import log from sage.functions.all import sqrt from sage.rings.real_mpfr import (RealField, is_RealField) from sage.rings.rational_field import is_RationalField from sage.sets.set import Set
################################################################################ ################################################################################
def is_ProbabilitySpace(S):
def is_DiscreteProbabilitySpace(S):
def is_RandomVariable(X): return isinstance(X, RandomVariable_generic)
def is_DiscreteRandomVariable(X): return isinstance(X, DiscreteRandomVariable)
################################################################################ ################################################################################
# We could inherit from a functions class here but use ParentWithBase
class RandomVariable_generic(ParentWithBase): """ A random variable. """ def __init__(self, X, RR): raise TypeError("Argument X (= %s) must be a probability space" % X)
def probability_space(self): return self.base()
def domain(self): return self.base()
def codomain(self): return self._codomain
def field(self):
class DiscreteRandomVariable(RandomVariable_generic): """ A random variable on a discrete probability space. """ def __init__(self, X, f, codomain = None, check = False): r""" Create free binary string monoid on `n` generators.
INPUT: x: A probability space f: A dictionary such that X[x] = value for x in X is the discrete function on X """ raise TypeError("Argument X (= %s) must be a discrete probability space" % X) raise NotImplementedError("Not implemented") RR = RealField() else:
def __call__(self,x): """ Return the value of the random variable at x. """ # Need some condition for x being a valid domain element: # raise IndexError, "Argument x (= %s) is not a valid domain element." % x
def __repr__(self): return "Discrete random variable defined by %s" % self._function
def function(self): """ The function defining the random variable. """
def expectation(self): r""" The expectation of the discrete random variable, namely `\sum_{x \in S} p(x) X[x]`, where `X` = self and `S` is the probability space of `X`. """ E = 0 Omega = self.probability_space() for x in self._function.keys(): E += Omega(x) * self(x) return E
def translation_expectation(self, map): r""" The expectation of the discrete random variable, namely `\sum_{x \in S} p(x) X[e(x)]`, where `X` = self, `S` is the probability space of `X`, and `e` = map. """ E = 0 Omega = self.probability_space() for x in Omega._function.keys(): E += Omega(x) * self(map(x)) return E
def variance(self): r""" The variance of the discrete random variable.
Let `S` be the probability space of `X` = self, with probability function `p`, and `E(X)` be the expectation of `X`. Then the variance of `X` is:
.. MATH::
\mathrm{var}(X) = E((X-E(x))^2) = \sum_{x \in S} p(x) (X(x) - E(x))^2 """ Omega = self.probability_space() mu = self.expectation() var = 0 for x in self._function.keys(): var += Omega(x) * (self(x) - mu)**2 return var
def translation_variance(self, map): r""" The variance of the discrete random variable `X \circ e`, where `X` = self, and `e` = map.
Let `S` be the probability space of `X` = self, with probability function `p`, and `E(X)` be the expectation of `X`. Then the variance of `X` is:
.. MATH::
\mathrm{var}(X) = E((X-E(x))^2) = \sum_{x \in S} p(x) (X(x) - E(x))^2 """ Omega = self.probability_space() mu = self.translation_expectation(map) var = 0 for x in Omega._function.keys(): var += Omega(x) * (self(map(x)) - mu)**2 return var
def covariance(self, other): r""" The covariance of the discrete random variable X = self with Y = other.
Let `S` be the probability space of `X` = self, with probability function `p`, and `E(X)` be the expectation of `X`. Then the variance of `X` is:
.. MATH::
\text{cov}(X,Y) = E((X-E(X)\cdot (Y-E(Y)) = \sum_{x \in S} p(x) (X(x) - E(X))(Y(x) - E(Y)) """ Omega = self.probability_space() if Omega != other.probability_space(): raise ValueError("Argument other (= %s) must be defined on the same probability space." % other) muX = self.expectation() muY = other.expectation() cov = 0 for x in self._function.keys(): cov += Omega(x)*(self(x) - muX)*(other(x) - muY) return cov
def translation_covariance(self, other, map): r""" The covariance of the probability space X = self with image of Y = other under the given map of the probability space.
Let `S` be the probability space of `X` = self, with probability function `p`, and `E(X)` be the expectation of `X`. Then the variance of `X` is:
.. MATH::
\text{cov}(X,Y) = E((X-E(X)\cdot (Y-E(Y)) = \sum_{x \in S} p(x) (X(x) - E(X))(Y(x) - E(Y)) """ Omega = self.probability_space() if Omega != other.probability_space(): raise ValueError("Argument other (= %s) must be defined on the same probability space." % other) muX = self.expectation() muY = other.translation_expectation(map) cov = 0 for x in Omega._function.keys(): cov += Omega(x)*(self(x) - muX)*(other(map(x)) - muY) return cov
def standard_deviation(self): r""" The standard deviation of the discrete random variable.
Let `S` be the probability space of `X` = self, with probability function `p`, and `E(X)` be the expectation of `X`. Then the standard deviation of `X` is defined to be
.. MATH::
\sigma(X) = \sqrt{ \sum_{x \in S} p(x) (X(x) - E(x))^2} """ return sqrt(self.variance())
def translation_standard_deviation(self, map): r""" The standard deviation of the translated discrete random variable `X \circ e`, where `X` = self and `e` = map.
Let `S` be the probability space of `X` = self, with probability function `p`, and `E(X)` be the expectation of `X`. Then the standard deviation of `X` is defined to be
.. MATH::
\sigma(X) = \sqrt{ \sum_{x \in S} p(x) (X(x) - E(x))^2} """ return sqrt(self.translation_variance(map))
def correlation(self, other): """ The correlation of the probability space X = self with Y = other. """ cov = self.covariance(other) sigX = self.standard_deviation() sigY = other.standard_deviation() if sigX == 0 or sigY == 0: raise ValueError("Correlation not defined if standard deviations are not both nonzero.") return cov/(sigX*sigY)
def translation_correlation(self, other, map): """ The correlation of the probability space X = self with image of Y = other under map. """ cov = self.translation_covariance(other, map) sigX = self.standard_deviation() sigY = other.translation_standard_deviation(map) if sigX == 0 or sigY == 0: raise ValueError("Correlation not defined if standard deviations are not both nonzero.") return cov/(sigX*sigY)
################################################################################ ################################################################################
class ProbabilitySpace_generic(RandomVariable_generic): r""" A probability space. """ def __init__(self, domain, RR): """ A generic probability space on given domain space and codomain ring. """ raise TypeError("Argument domain (= %s) must be a list, tuple, or set containing." % domain)
def domain(self):
class DiscreteProbabilitySpace(ProbabilitySpace_generic,DiscreteRandomVariable): r""" The discrete probability space """ def __init__(self, X, P, codomain = None, check = False): r""" Create the discrete probability space with probabilities on the space X given by the dictionary P with values in the field real_field.
EXAMPLES::
sage: S = [ i for i in range(16) ] sage: P = {} sage: for i in range(15): P[i] = 2^(-i-1) sage: P[15] = 2^-16 sage: X = DiscreteProbabilitySpace(S,P) sage: X.domain() (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) sage: X.set() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} sage: X.entropy().n() 1.99972534179688
A probability space can be defined on any list of elements::
sage: AZ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' sage: S = [ AZ[i] for i in range(26) ] sage: P = { 'A':1/2, 'B':1/4, 'C':1/4 } sage: X = DiscreteProbabilitySpace(S,P) sage: X Discrete probability space defined by {'A': 1/2, 'C': 1/4, 'B': 1/4} sage: X.entropy().n() 1.50000000000000 """ raise TypeError("Argument codomain (= %s) must be the reals or rationals" % codomain) one = sum([ P[x] for x in P.keys() ]) if is_RationalField(codomain): if not one == 1: raise TypeError("Argument P (= %s) does not define a probability function") else: if not Abs(one-1) < 2^(-codomain.precision()+1): raise TypeError("Argument P (= %s) does not define a probability function")
def __repr__(self):
def set(self): r""" The set of values of the probability space taking possibly nonzero probability (a subset of the domain). """
def entropy(self): """ The entropy of the probability space. """ return 0 else: |