def expand(self, **hints): expr = self.args[0] condition = self._condition if not is_random(expr): return expr if isinstance(expr, Add): return Add.fromiter( Expectation(a, condition=condition).expand() for a in expr.args) expand_expr = _expand(expr) if isinstance(expand_expr, Add): return Add.fromiter( Expectation(a, condition=condition).expand() for a in expand_expr.args) elif isinstance(expr, Mul): rv = [] nonrv = [] for a in expr.args: if is_random(a): rv.append(a) else: nonrv.append(a) return Mul.fromiter(nonrv) * Expectation(Mul.fromiter(rv), condition=condition) return self
def expand(self, **hints): arg1 = self.args[0] arg2 = self.args[1] condition = self._condition if arg1 == arg2: return Variance(arg1, condition).expand() if not is_random(arg1): return S.Zero if not is_random(arg2): return S.Zero arg1, arg2 = sorted([arg1, arg2], key=default_sort_key) if isinstance(arg1, RandomSymbol) and isinstance(arg2, RandomSymbol): return Covariance(arg1, arg2, condition) coeff_rv_list1 = self._expand_single_argument(arg1.expand()) coeff_rv_list2 = self._expand_single_argument(arg2.expand()) addends = [ a * b * Covariance(*sorted([r1, r2], key=default_sort_key), condition=condition) for (a, r1) in coeff_rv_list1 for (b, r2) in coeff_rv_list2 ] return Add.fromiter(addends)
def expand(self, **hints): arg = self.args[0] condition = self._condition if not is_random(arg): return S.Zero if isinstance(arg, RandomSymbol): return self elif isinstance(arg, Add): rv = [] for a in arg.args: if is_random(a): rv.append(a) variances = Add( *map(lambda xv: Variance(xv, condition).expand(), rv)) map_to_covar = lambda x: 2 * Covariance(*x, condition=condition ).expand() covariances = Add( *map(map_to_covar, itertools.combinations(rv, 2))) return variances + covariances elif isinstance(arg, Mul): nonrv = [] rv = [] for a in arg.args: if is_random(a): rv.append(a) else: nonrv.append(a**2) if len(rv) == 0: return S.Zero return Mul.fromiter(nonrv) * Variance(Mul.fromiter(rv), condition) # this expression contains a RandomSymbol somehow: return self
def JointEigenDistribution(mat): """ Creates joint distribution of eigen values of matrices with random expressions. Parameters ========== mat: Matrix The matrix under consideration Returns ======= JointDistributionHandmade Examples ======== >>> from sympy.stats import Normal, JointEigenDistribution >>> from sympy import Matrix >>> A = [[Normal('A00', 0, 1), Normal('A01', 0, 1)], ... [Normal('A10', 0, 1), Normal('A11', 0, 1)]] >>> JointEigenDistribution(Matrix(A)) JointDistributionHandmade(-sqrt(A00**2 - 2*A00*A11 + 4*A01*A10 + A11**2)/2 + A00/2 + A11/2, sqrt(A00**2 - 2*A00*A11 + 4*A01*A10 + A11**2)/2 + A00/2 + A11/2) """ eigenvals = mat.eigenvals(multiple=True) if any(not is_random(eigenval) for eigenval in set(eigenvals)): raise ValueError("Eigen values don't have any random expression, " "joint distribution cannot be generated.") return JointDistributionHandmade(*eigenvals)
def pmf(self, x): x = sympify(x) if not (x.is_number or x.is_Symbol or is_random(x)): raise ValueError("'x' expected as an argument of type 'number', 'Symbol', or " "'RandomSymbol' not %s" % (type(x))) cond = Ge(x, 1) & Le(x, self.sides) & Contains(x, S.Integers) return Piecewise((S.One/self.sides, cond), (S.Zero, True))
def rv(symbol, cls, *args): args = list(map(sympify, args)) dist = cls(*args) dist.check(*args) pspace = SingleDiscretePSpace(symbol, dist) if any(is_random(arg) for arg in args): pspace = JointPSpace(symbol, CompoundDistribution(dist)) return pspace.value
def _expand_single_argument(cls, expr): # return (coefficient, random_symbol) pairs: if isinstance(expr, RandomSymbol): return [(S.One, expr)] elif isinstance(expr, Add): outval = [] for a in expr.args: if isinstance(a, Mul): outval.append(cls._get_mul_nonrv_rv_tuple(a)) elif is_random(a): outval.append((S.One, a)) return outval elif isinstance(expr, Mul): return [cls._get_mul_nonrv_rv_tuple(expr)] elif is_random(expr): return [(S.One, expr)]
def pmf(self, x): x = sympify(x) if not (x.is_number or x.is_Symbol or is_random(x)): raise ValueError("'x' expected as an argument of type 'number', 'Symbol', or " "'RandomSymbol' not %s" % (type(x))) cond1 = Eq(x, 1) & x.is_integer cond2 = Ge(x, 1) & Le(x, self.k) & x.is_integer return Piecewise((1/self.k, cond1), (1/(x*(x - 1)), cond2), (S.Zero, True))
def pmf(self, x): n, p = self.n, self.p x = sympify(x) if not (x.is_number or x.is_Symbol or is_random(x)): raise ValueError("'x' expected as an argument of type 'number', 'Symbol', or " "'RandomSymbol' not %s" % (type(x))) cond = Ge(x, 0) & Le(x, n) & Contains(x, S.Integers) return Piecewise((binomial(n, x) * p**x * (1 - p)**(n - x), cond), (S.Zero, True))
def _get_mul_nonrv_rv_tuple(cls, m): rv = [] nonrv = [] for a in m.args: if is_random(a): rv.append(a) else: nonrv.append(a) return (Mul.fromiter(nonrv), Mul.fromiter(rv))
def rv(symbol, cls, *args): args = list(map(sympify, args)) dist = cls(*args) dist.check(*args) pspace = SingleDiscretePSpace(symbol, dist) if any(is_random(arg) for arg in args): from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution pspace = CompoundPSpace(symbol, CompoundDistribution(dist)) return pspace.value
def expand(self, **hints): arg = self.args[0] condition = self._condition if not is_random(arg): return ZeroMatrix(*self.shape) if isinstance(arg, RandomSymbol): return self elif isinstance(arg, Add): rv = [] for a in arg.args: if is_random(a): rv.append(a) variances = Add( *map(lambda xv: Variance(xv, condition).expand(), rv)) map_to_covar = lambda x: 2 * Covariance(*x, condition=condition ).expand() covariances = Add( *map(map_to_covar, itertools.combinations(rv, 2))) return variances + covariances elif isinstance(arg, (Mul, MatMul)): nonrv = [] rv = [] for a in arg.args: if is_random(a): rv.append(a) else: nonrv.append(a) if len(rv) == 0: return ZeroMatrix(*self.shape) # Avoid possible infinite loops with MatMul: if len(nonrv) == 0: return self # Variance of many multiple matrix products is not implemented: if len(rv) > 1: return self return Mul.fromiter(nonrv) * Variance( Mul.fromiter(rv), condition) * (Mul.fromiter(nonrv)).transpose() # this expression contains a RandomSymbol somehow: return self
def expand(self, **hints): expr = self.args[0] condition = self._condition if not is_random(expr): return expr if isinstance(expr, Add): return Add.fromiter( Expectation(a, condition=condition).expand() for a in expr.args) expand_expr = _expand(expr) if isinstance(expand_expr, Add): return Add.fromiter( Expectation(a, condition=condition).expand() for a in expand_expr.args) elif isinstance(expr, (Mul, MatMul)): rv = [] nonrv = [] postnon = [] for a in expr.args: if is_random(a): if rv: rv.extend(postnon) else: nonrv.extend(postnon) postnon = [] rv.append(a) elif a.is_Matrix: postnon.append(a) else: nonrv.append(a) # In order to avoid infinite-looping (MatMul may call .doit() again), # do not rebuild if len(nonrv) == 0: return self return Mul.fromiter(nonrv) * Expectation( Mul.fromiter(rv), condition=condition) * Mul.fromiter(postnon) return self
def rv(name, cls, *args, **kwargs): args = list(map(sympify, args)) dist = cls(*args) if kwargs.pop('check', True): dist.check(*args) pspace = SingleFinitePSpace(name, dist) if any(is_random(arg) for arg in args): from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution pspace = CompoundPSpace(name, CompoundDistribution(dist)) return pspace.value
def __new__(cls, expr, condition=None, **kwargs): expr = _sympify(expr) if condition is None: if not is_random(expr): return expr obj = Expr.__new__(cls, expr) else: condition = _sympify(condition) obj = Expr.__new__(cls, expr, condition) obj._condition = condition return obj
def expand(self, **hints): arg1 = self.args[0] arg2 = self.args[1] condition = self._condition if arg1 == arg2: return VarianceMatrix(arg1, condition).expand() if not is_random(arg1) or not is_random(arg2): return ZeroMatrix(*self.shape) if isinstance(arg1, RandomSymbol) and isinstance(arg2, RandomSymbol): return CrossCovarianceMatrix(arg1, arg2, condition) coeff_rv_list1 = self._expand_single_argument(arg1.expand()) coeff_rv_list2 = self._expand_single_argument(arg2.expand()) addends = [a*CrossCovarianceMatrix(r1, r2, condition=condition)*b.transpose() for (a, r1) in coeff_rv_list1 for (b, r2) in coeff_rv_list2] return Add.fromiter(addends)
def pdf(self, x, evaluate=False): dist = self.args[0] randoms = [rv for rv in dist.args if is_random(rv)] if isinstance(dist, SingleFiniteDistribution): y = Dummy('y', integer=True, negative=False) expr = dist.pmf(y) else: y = Dummy('y') expr = dist.pdf(y) for rv in randoms: expr = self._marginalise(expr, rv, evaluate) return Lambda(y, expr)(x)
def __new__(cls, expr, condition=None, **kwargs): expr = _sympify(expr) if expr.is_Matrix: from sympy.stats.symbolic_multivariate_probability import ExpectationMatrix return ExpectationMatrix(expr, condition) if condition is None: if not is_random(expr): return expr obj = Expr.__new__(cls, expr) else: condition = _sympify(condition) obj = Expr.__new__(cls, expr, condition) obj._condition = condition return obj
def pmf(self, x): x = sympify(x) if not (x.is_number or x.is_Symbol or is_random(x)): raise ValueError("'x' expected as an argument of type 'number', 'Symbol', or " "'RandomSymbol' not %s" % (type(x))) cond1 = Eq(x, 1) & x.is_integer cond2 = Ge(x, 1) & Le(x, self.k) & x.is_integer rho = Piecewise((Rational(1, self.k), cond1), (Rational(1, x*(x-1)), cond2), (S.Zero, True)) cond1 = Ge(x, 1) & Le(x, round(self.k/self.R)-1) cond2 = Eq(x, round(self.k/self.R)) tau = Piecewise((self.R/(self.k * x), cond1), (self.R * log(self.R/self.delta)/self.k, cond2), (S.Zero, True)) return (rho + tau)/self.Z
def expand(self, **hints): expr = self.args[0] condition = self._condition if not is_random(expr): return expr if isinstance(expr, Add): return Add(*[ Expectation(a, condition=condition).expand() for a in expr.args ]) elif isinstance(expr, Mul): if isinstance(_expand(expr), Add): return Expectation(_expand(expr)).expand() rv = [] nonrv = [] for a in expr.args: if is_random(a): rv.append(a) else: nonrv.append(a) return Mul(*nonrv) * Expectation(Mul(*rv), condition=condition) return self
def doit(self, **hints): deep = hints.get('deep', True) condition = self._condition expr = self.args[0] numsamples = hints.get('numsamples', False) for_rewrite = not hints.get('for_rewrite', False) if deep: expr = expr.doit(**hints) if not is_random(expr) or isinstance( expr, Expectation): # expr isn't random? return expr if numsamples: # Computing by monte carlo sampling? evalf = hints.get('evalf', True) return sampling_E(expr, condition, numsamples=numsamples, evalf=evalf) if expr.has(RandomIndexedSymbol): return pspace(expr).compute_expectation(expr, condition) # Create new expr and recompute E if condition is not None: # If there is a condition return self.func(given(expr, condition)).doit(**hints) # A few known statements for efficiency if expr.is_Add: # We know that E is Linear return Add(*[ self.func(arg, condition).doit( **hints) if not isinstance(arg, Expectation) else self. func(arg, condition) for arg in expr.args ]) if expr.is_Mul: if expr.atoms(Expectation): return expr if pspace(expr) == PSpace(): return self.func(expr) # Otherwise case is simple, pass work off to the ProbabilitySpace result = pspace(expr).compute_expectation(expr, evaluate=for_rewrite) if hasattr(result, 'doit') and for_rewrite: return result.doit(**hints) else: return result
def probability(self, condition, **kwargs): z = Dummy('z', real=True) cond_inv = False if isinstance(condition, Ne): condition = Eq(condition.args[0], condition.args[1]) cond_inv = True # Univariate case can be handled by where try: domain = self.where(condition) rv = [rv for rv in self.values if rv.symbol == domain.symbol][0] # Integrate out all other random variables pdf = self.compute_density(rv, **kwargs) # return S.Zero if `domain` is empty set if domain.set is S.EmptySet or isinstance(domain.set, FiniteSet): return S.Zero if not cond_inv else S.One if isinstance(domain.set, Union): return sum( Integral(pdf(z), (z, subset), **kwargs) for subset in domain.set.args if isinstance(subset, Interval)) # Integrate out the last variable over the special domain return Integral(pdf(z), (z, domain.set), **kwargs) # Other cases can be turned into univariate case # by computing a density handled by density computation except NotImplementedError: from sympy.stats.rv import density expr = condition.lhs - condition.rhs if not is_random(expr): dens = self.density comp = condition.rhs else: dens = density(expr, **kwargs) comp = 0 if not isinstance(dens, ContinuousDistribution): from sympy.stats.crv_types import ContinuousDistributionHandmade dens = ContinuousDistributionHandmade(dens, set=self.domain.set) # Turn problem into univariate case space = SingleContinuousPSpace(z, dens) result = space.probability(condition.__class__(space.value, comp)) return result if not cond_inv else S.One - result
def doit(self, **hints): if not is_random(self.args[0]): return self.args[0] return self.rewrite(Expectation).doit(**hints)
def test_is_random(): X = Normal('X', 0, 1) Y = Normal('Y', 0, 1) a, b = symbols('a, b') G = GaussianUnitaryEnsemble('U', 2) B = BernoulliProcess('B', 0.9) assert not is_random(a) assert not is_random(a + b) assert not is_random(a * b) assert not is_random(Matrix([a**2, b**2])) assert is_random(X) assert is_random(X**2 + Y) assert is_random(Y + b**2) assert is_random(Y > 5) assert is_random(B[3] < 1) assert is_random(G) assert is_random(X * Y * B[1]) assert is_random(Matrix([[X, B[2]], [G, Y]])) assert is_random(Eq(X, 4))
def variance_prop(expr, consts=(), include_covar=False): r"""Symbolically propagates variance (`\sigma^2`) for expressions. This is computed as as seen in [1]_. Parameters ========== expr : Expr A sympy expression to compute the variance for. consts : sequence of Symbols, optional Represents symbols that are known constants in the expr, and thus have zero variance. All symbols not in consts are assumed to be variant. include_covar : bool, optional Flag for whether or not to include covariances, default=False. Returns ======= var_expr : Expr An expression for the total variance of the expr. The variance for the original symbols (e.g. x) are represented via instance of the Variance symbol (e.g. Variance(x)). Examples ======== >>> from sympy import symbols, exp >>> from sympy.stats.error_prop import variance_prop >>> x, y = symbols('x y') >>> variance_prop(x + y) Variance(x) + Variance(y) >>> variance_prop(x * y) x**2*Variance(y) + y**2*Variance(x) >>> variance_prop(exp(2*x)) 4*exp(4*x)*Variance(x) References ========== .. [1] https://en.wikipedia.org/wiki/Propagation_of_uncertainty """ args = expr.args if len(args) == 0: if expr in consts: return S.Zero elif is_random(expr): return Variance(expr).doit() elif isinstance(expr, Symbol): return Variance(RandomSymbol(expr)).doit() else: return S.Zero nargs = len(args) var_args = list(map(variance_prop, args, repeat(consts, nargs), repeat(include_covar, nargs))) if isinstance(expr, Add): var_expr = Add(*var_args) if include_covar: terms = [2 * Covariance(_arg0_or_var(x), _arg0_or_var(y)).expand() \ for x, y in combinations(var_args, 2)] var_expr += Add(*terms) elif isinstance(expr, Mul): terms = [v/a**2 for a, v in zip(args, var_args)] var_expr = simplify(expr**2 * Add(*terms)) if include_covar: terms = [2*Covariance(_arg0_or_var(x), _arg0_or_var(y)).expand()/(a*b) \ for (a, b), (x, y) in zip(combinations(args, 2), combinations(var_args, 2))] var_expr += Add(*terms) elif isinstance(expr, Pow): b = args[1] v = var_args[0] * (expr * b / args[0])**2 var_expr = simplify(v) elif isinstance(expr, exp): var_expr = simplify(var_args[0] * expr**2) else: # unknown how to proceed, return variance of whole expr. var_expr = Variance(expr) return var_expr
def _(x): return is_random(x.base)
def _(x): atoms = x.free_symbols if len(atoms) == 1 and next(iter(atoms)) == x: return False return any([is_random(i) for i in atoms])