def test_variance_prop_with_covar(): x, y, z = symbols('x y z') phi, t = consts = symbols('phi t') a = RandomSymbol(x) var_x = Variance(a) b = RandomSymbol(y) var_y = Variance(b) c = RandomSymbol(z) var_z = Variance(c) covar_x_y = Covariance(a, b) covar_x_z = Covariance(a, c) covar_y_z = Covariance(b, c) cases = { x + y: var_x + var_y + 2*covar_x_y, a + y: var_x + var_y + 2*covar_x_y, x + y + z: var_x + var_y + var_z + \ 2*covar_x_y + 2*covar_x_z + 2*covar_y_z, 2*x: 4*var_x, x*y: var_x*y**2 + var_y*x**2 + 2*covar_x_y/(x*y), 1/x: var_x/x**4, exp(x): var_x*exp(2*x), exp(2*x): 4*var_x*exp(4*x), exp(-x*t): t**2*var_x*exp(-2*t*x), } for inp, out in cases.items(): obs = variance_prop(inp, consts=consts, include_covar=True) assert out == obs
def covariance(X, Y, condition=None, **kwargs): """ Covariance of two random expressions The expectation that the two variables will rise and fall together Covariance(X,Y) = E( (X-E(X)) * (Y-E(Y)) ) Examples ======== >>> from sympy.stats import Exponential, covariance >>> from sympy import Symbol >>> rate = Symbol('lambda', positive=True, real=True, finite=True) >>> X = Exponential('X', rate) >>> Y = Exponential('Y', rate) >>> covariance(X, X) lambda**(-2) >>> covariance(X, Y) 0 >>> covariance(X, Y + rate*X) 1/lambda """ if (is_random(X) and pspace(X) == PSpace()) or (is_random(Y) and pspace(Y) == PSpace()): from sympy.stats.symbolic_probability import Covariance return Covariance(X, Y, condition) return expectation((X - expectation(X, condition, **kwargs)) * (Y - expectation(Y, condition, **kwargs)), condition, **kwargs)
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 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(0) elif isinstance(expr, RandomSymbol): return Variance(expr).doit() elif isinstance(expr, Symbol): return Variance(RandomSymbol(expr)).doit() else: return S(0) 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)).doit() \ 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)).doit()/(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 test_literal_probability(): X = Normal('X', 2, 3) Y = Normal('Y', 3, 4) Z = Poisson('Z', 4) W = Poisson('W', 3) x, y, w, z = symbols('x, y, w, z') assert Probability(X > 0).doit() == probability(X > 0) assert Probability(X > x).doit() == probability(X > x) assert Expectation(X).doit() == expectation(X) assert Expectation(X**2).doit() == expectation(X**2) assert Expectation(x*X) == x*Expectation(X) assert Expectation(2*X + 3*Y + z*X*Y) == 2*Expectation(X) + 3*Expectation(Y) + z*Expectation(X*Y) assert Expectation(2*X + 3*Y + z*X*Y, evaluate=False).args == (2*X + 3*Y + z*X*Y,) assert Expectation(sin(X)) == Expectation(sin(X), evaluate=False) assert Expectation(2*x*sin(X)*Y + y*X**2 + z*X*Y) == 2*x*Expectation(sin(X)*Y) + y*Expectation(X**2) + z*Expectation(X*Y) assert Variance(w) == 0 assert Variance(X).doit() == variance(X) assert Variance(X + z) == Variance(X) assert Variance(X*Y).args == (Mul(X, Y),) assert type(Variance(X*Y)) == Variance assert Variance(z*X) == z**2*Variance(X) assert Variance(X + Y) == Variance(X) + Variance(Y) + 2*Covariance(X, Y) assert Variance(X + Y + Z + W) == (Variance(X) + Variance(Y) + Variance(Z) + Variance(W) + 2 * Covariance(X, Y) + 2 * Covariance(X, Z) + 2 * Covariance(X, W) + 2 * Covariance(Y, Z) + 2 * Covariance(Y, W) + 2 * Covariance(W, Z)) assert Variance(X**2).doit() == variance(X**2) assert Variance(X**2, evaluate=False) == Variance(X**2) assert Variance(x*X**2) == x**2*Variance(X**2) assert Variance(sin(X)).args == (sin(X),) assert Variance(sin(X), evaluate=False) == Variance(sin(X)) assert Variance(x*sin(X)) == x**2*Variance(sin(X)) assert Covariance(w, z) == 0 assert Covariance(X, w) == 0 assert Covariance(w, X) == 0 assert Covariance(X, Y).args == (X, Y) assert type(Covariance(X, Y)) == Covariance assert Covariance(z*X + 3, Y) == z*Covariance(X, Y) assert Covariance(X, X) == Variance(X) assert Covariance(z*X + 3, w*Y + 4) == w*z*Covariance(X,Y) assert Covariance(X, Y) == Covariance(Y, X) assert Covariance(X + Y, Z + W) == Covariance(W, X) + Covariance(W, Y) + Covariance(X, Z) + Covariance(Y, Z) assert Covariance(x*X + y*Y, z*Z + w*W) == (x*w*Covariance(W, X) + w*y*Covariance(W, Y) + x*z*Covariance(X, Z) + y*z*Covariance(Y, Z)) assert Covariance(x*X**2 + y*sin(Y), z*Y*Z**2 + w*W) == (w*x*Covariance(W, X**2) + w*y*Covariance(sin(Y), W) + x*z*Covariance(Y*Z**2, X**2) + y*z*Covariance(Y*Z**2, sin(Y))) assert Covariance(X, X**2) == Covariance(X, X**2, evaluate=False) assert Covariance(X, sin(X)) == Covariance(sin(X), X, evaluate=False) assert Covariance(X**2, sin(X)*Y) == Covariance(sin(X)*Y, X**2, evaluate=False)