def expectation(self, expr, condition=None, evaluate=True, **kwargs): """ Computes expectation. Parameters ========== expr: RandomIndexedSymbol, Relational, Logic Condition for which expectation has to be computed. Must contain a RandomIndexedSymbol of the process. condition: Relational, Logic The given conditions under which computations should be done. Returns ======= Expectation of the RandomIndexedSymbol. """ new_expr, new_condition = self._rvindexed_subs(expr, condition) new_pspace = pspace(new_expr) if new_condition is not None: new_expr = given(new_expr, new_condition) if new_expr.is_Add: # As E is Linear return Add(*[ new_pspace.compute_expectation( expr=arg, evaluate=evaluate, **kwargs) for arg in new_expr.args ]) return new_pspace.compute_expectation(new_expr, evaluate=evaluate, **kwargs)
def doit(self, **hints): condition = self.args[0] given_condition = self._condition numsamples = hints.get('numsamples', False) for_rewrite = not hints.get('for_rewrite', False) if isinstance(condition, Not): return S.One - self.func(condition.args[0], given_condition, evaluate=for_rewrite).doit(**hints) if condition.has(RandomIndexedSymbol): return pspace(condition).probability(condition, given_condition, evaluate=for_rewrite) if isinstance(given_condition, RandomSymbol): condrv = random_symbols(condition) if len(condrv) == 1 and condrv[0] == given_condition: from sympy.stats.frv_types import BernoulliDistribution return BernoulliDistribution( self.func(condition).doit(**hints), 0, 1) if any([dependent(rv, given_condition) for rv in condrv]): return Probability(condition, given_condition) else: return Probability(condition).doit() if given_condition is not None and \ not isinstance(given_condition, (Relational, Boolean)): raise ValueError( "%s is not a relational or combination of relationals" % (given_condition)) if given_condition == False or condition is S.false: return S.Zero if not isinstance(condition, (Relational, Boolean)): raise ValueError( "%s is not a relational or combination of relationals" % (condition)) if condition is S.true: return S.One if numsamples: return sampling_P(condition, given_condition, numsamples=numsamples) if given_condition is not None: # If there is a condition # Recompute on new conditional expr return Probability(given(condition, given_condition)).doit() # Otherwise pass work off to the ProbabilitySpace if pspace(condition) == PSpace(): return Probability(condition, given_condition) result = pspace(condition).probability(condition) if hasattr(result, 'doit') and for_rewrite: return result.doit() else: return result
def probability(self, condition, given_condition=None, evaluate=True, **kwargs): """ Computes probability. Parameters ========== condition: Relational Condition for which probability has to be computed. Must contain a RandomIndexedSymbol of the process. given_condition: Relational/And The given conditions under which computations should be done. Returns ======= Probability of the condition. """ new_condition, new_givencondition = self._rvindexed_subs( condition, given_condition) if isinstance(new_givencondition, RandomSymbol): condrv = random_symbols(new_condition) if len(condrv) == 1 and condrv[0] == new_givencondition: return BernoulliDistribution(self.probability(new_condition), 0, 1) if any([dependent(rv, new_givencondition) for rv in condrv]): return Probability(new_condition, new_givencondition) else: return self.probability(new_condition) if new_givencondition is not None and \ not isinstance(new_givencondition, (Relational, Boolean)): raise ValueError( "%s is not a relational or combination of relationals" % (new_givencondition)) if new_givencondition == False: return S.Zero if new_condition == True: return S.One if new_condition == False: return S.Zero if not isinstance(new_condition, (Relational, Boolean)): raise ValueError( "%s is not a relational or combination of relationals" % (new_condition)) if new_givencondition is not None: # If there is a condition # Recompute on new conditional expr return self.probability( given(new_condition, new_givencondition, **kwargs), **kwargs) return pspace(new_condition).probability(new_condition, **kwargs)
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 __new__(cls, *prob, given=None): booleans = [] for arg in prob: assert arg.is_random if arg.is_symbol: booleans.append(Equality(arg, pspace(arg).symbol)) elif arg.is_Conditioned: lhs, rhs = arg.args if lhs.is_symbol: booleans.append( arg.func(Equality(lhs, pspace(lhs).symbol), rhs)) else: booleans.append(arg) else: assert arg.is_Boolean, type(arg) booleans.append(arg) expr = And(*booleans) if given is not None: expr = rv.given(expr, given) obj = Expr.__new__(cls, expr) return obj
def doit(self, **hints): return given(self.lhs, self.rhs)