def ppd(self, query, evidence): """ Computes a posterior probability distribution for the current network, given some query variable and some evidence. :param query: :param evidence: a dictionary of evidence variables. {'varname': varvalue} :return: A dictionary whose keys are tuples of query values. The values of the dictionary are the values of the PPD. """ factors = [] # build a list with the initial factors for k in self.net: parents = self.net[k]['parents'] # build a list with the domains of the parents # use values from the evidence if available dom = [self.net[parent]['values'] if parent not in evidence else [evidence[parent]] for parent in parents] # add this variables' domain, or value from evidence if available dom += [self.net[k]['values'] if k not in evidence else [evidence[k]]] # the variables for this factor are the parents of the variable and # the variable vars_ = parents + [k] # build the probability table for this factor table = {} for row in product(*dom): table[row] = self[vars_[-1]]['cpt'][row] factors.append(Factor(OrderedDict(zip(vars_, dom)), table)) hidden_vars = set(self.net.keys()) - set(query) - set(evidence) hidden_vars = list(hidden_vars) # TODO apply an ordering function ordering = hidden_vars step_nr = 0 for var in ordering: self.__add_new_state_verbose(step_nr, factors) step_nr += 1 # join and sum factors that include var subset = [] for factor in factors: if var in factor: subset.append(factor) self.__add_factor_table_verbose(subset) new_factor = Factor.join(subset) new_factor.eliminate(var) self.step_by_step += '\n\n\tEliminate ' + str(var) for i in subset: factors.remove(i) factors.append(new_factor) self.__add_new_factor_verbose(new_factor) #self.__add_factor_table_verbose(factors) final_factor = Factor.join(factors) self.step_by_step += '\n\n' + str(step_nr) + ' Factors: ' + str(factors) # remove evidence columns for var in evidence: if var not in query: final_factor.eliminate(var) self.step_by_step += '\n\n\tEliminate Evidence ' + str(var) step_nr += 1 self.step_by_step += '\n\n' + str(step_nr) + ' Factors: ' + str(list(final_factor.vars_)) self.step_by_step += '\n\n\t\t' + str(list(final_factor.vars_.keys())) for row in new_factor.table: self.step_by_step += '\n\t\t' + str(row) + ' ' + str(new_factor.table[row]) # build the final, normalized table norm_constant = 0 for row in final_factor.table: norm_constant += final_factor[row] ppd_table = final_factor.table # aliasing for row in ppd_table: ppd_table[row] = ppd_table[row] / norm_constant return ppd_table