def enumerate_joint(variables, e, P): """Return the sum of those entries in P consistent with e, provided variables is P's remaining variables (the ones not in e).""" if not variables: return P[e] Y, rest = variables[0], variables[1:] return sum( [enumerate_joint(rest, extend(e, Y, y), P) for y in P.values(Y)])
def all_events(variables, bn, e): """Yield every way of extending e with values for all variables.""" if not variables: yield e else: X, rest = variables[0], variables[1:] for e1 in all_events(rest, bn, e): for x in bn.variable_values(X): yield extend(e1, X, x)
def sum_out(self, var, bn): """Make a factor eliminating var by summing over its values.""" variables = [X for X in self.variables if X != var] cpt = { event_values(e, variables): sum( self.p(extend(e, var, val)) for val in bn.variable_values(var)) for e in all_events(variables, bn, {}) } return Factor(variables, cpt)
def enumeration_ask(X, e, bn): """Return the conditional probability distribution of variable X given evidence e, from BayesNet bn. [Figure 14.9] >>> enumeration_ask('Burglary', dict(JohnCalls=T, MaryCalls=T), burglary ... ).show_approx() 'False: 0.716, True: 0.284'""" assert X not in e, "Query variable must be distinct from evidence" Q = ProbDist(X) for xi in bn.variable_values(X): Q[xi] = enumerate_all(bn.variables, extend(e, X, xi), bn) return Q.normalize()
def markov_blanket_sample(X, e, bn): """Return a sample from P(X | mb) where mb denotes that the variables in the Markov blanket of X take their values from event e (which must assign a value to each). The Markov blanket of X is X's parents, children, and children's parents.""" Xnode = bn.variable_node(X) Q = ProbDist(X) for xi in bn.variable_values(X): ei = extend(e, X, xi) # [Equation 14.12:] Q[xi] = Xnode.p(xi, e) * product( Yj.p(ei[Yj.variable], ei) for Yj in Xnode.children) # (assuming a Boolean variable here) return probability(Q.normalize()[True])
def enumerate_joint_ask(X, e, P): """Return a probability distribution over the values of the variable X, given the {var:val} observations e, in the JointProbDist P. [Section 13.3] >>> P = JointProbDist(['X', 'Y']) >>> P[0,0] = 0.25; P[0,1] = 0.5; P[1,1] = P[2,1] = 0.125 >>> enumerate_joint_ask('X', dict(Y=1), P).show_approx() '0: 0.667, 1: 0.167, 2: 0.167' """ assert X not in e, "Query variable must be distinct from evidence" Q = ProbDist(X) # probability distribution for X, initially empty Y = [v for v in P.variables if v != X and v not in e] # hidden variables. for xi in P.values(X): Q[xi] = enumerate_joint(Y, extend(e, X, xi), P) return Q.normalize()
def enumerate_all(variables, e, bn): """Return the sum of those entries in P(variables | e{others}) consistent with e, where P is the joint distribution represented by bn, and e{others} means e restricted to bn's other variables (the ones other than variables). Parents must precede children in variables.""" if not variables: return 1.0 Y, rest = variables[0], variables[1:] Ynode = bn.variable_node(Y) if Y in e: return Ynode.p(e[Y], e) * enumerate_all(rest, e, bn) else: return sum( Ynode.p(y, e) * enumerate_all(rest, extend(e, Y, y), bn) for y in bn.variable_values(Y))
def all_events_jpd(vars, jpd, e): """ e is evidence, it is a dict containing 'variable:value' pairs vars is a list of variables jpd is an object of JointProbDist The function generates all events of variables in vars with all possible value assignments and variables in e with fixed values >>>P = JointProbDist(['X', 'Y', 'Z'], {'X':[1,2], 'Y': [True, False], 'Z' : ['a', 'b']}) >>>events = all_events_jpd(['X', 'Y'], P, {'Z':'a'}) >>>for each in events: print(each) {'Y': True, 'X': 1, 'Z': 'a'} {'Y': True, 'X': 2, 'Z': 'a'} {'Y': False, 'X': 1, 'Z': 'a'} {'Y': False, 'X': 2, 'Z': 'a'} """ if not vars: ## if vars is empty yield e else: X, rest = vars[0], vars[1:] for e1 in all_events_jpd(rest, jpd, e): for x in jpd.values(X): yield extend(e1, X, x)