def setUp(self): self.sn2 = {'grade': ['A', 'B', 'F'], 'diff': ['high', 'low'], 'intel': ['poor', 'good', 'very good']} self.sn1 = {'speed': ['low', 'medium', 'high'], 'switch': ['on', 'off'], 'time': ['day', 'night']} self.phi1 = Factor(['speed', 'switch', 'time'], [3, 2, 2], np.ones(12)) self.phi2 = Factor(['speed', 'switch', 'time'], [3, 2, 2], np.ones(12), state_names=self.sn1) self.cpd1 = TabularCPD('grade', 3, [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.8, 0.8, 0.8, 0.8, 0.8, 0.8]], evidence=['diff', 'intel'], evidence_card=[2, 3]) self.cpd2 = TabularCPD('grade', 3, [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.8, 0.8, 0.8, 0.8, 0.8, 0.8]], evidence=['diff', 'intel'], evidence_card=[2, 3], state_names=self.sn2) student = BayesianModel([('diff', 'grade'), ('intel', 'grade')]) diff_cpd = TabularCPD('diff', 2, [[0.2, 0.8]]) intel_cpd = TabularCPD('intel', 2, [[0.3, 0.7]]) grade_cpd = TabularCPD('grade', 3, [[0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1], [0.8, 0.8, 0.8, 0.8]], evidence=['diff', 'intel'], evidence_card=[2, 2]) student.add_cpds(diff_cpd, intel_cpd, grade_cpd) self.model1 = Inference(student) self.model2 = Inference(student, state_names=self.sn2)
def test_markov_inference_init(self): infer_markov = Inference(self.markov) self.assertEqual(set(infer_markov.variables), {'a', 'b', 'c', 'd'}) self.assertEqual(infer_markov.cardinality, { 'a': 2, 'b': 2, 'c': 2, 'd': 2 }) self.assertEqual( infer_markov.factors, { 'a': [ Factor(['a', 'b'], [2, 2], np.array([100, 1, 1, 100])), Factor(['a', 'c'], [2, 2], np.array([40, 30, 100, 20])) ], 'b': [ Factor(['a', 'b'], [2, 2], np.array([100, 1, 1, 100])), Factor(['b', 'd'], [2, 2], np.array([1, 100, 100, 1])) ], 'c': [ Factor(['a', 'c'], [2, 2], np.array([40, 30, 100, 20])), Factor(['c', 'd'], [2, 2], np.array([60, 60, 40, 40])) ], 'd': [ Factor(['b', 'd'], [2, 2], np.array([1, 100, 100, 1])), Factor(['c', 'd'], [2, 2], np.array([60, 60, 40, 40])) ] })
def test_bayesian_inference_init(self): infer_bayesian = Inference(self.bayesian) self.assertEqual(set(infer_bayesian.variables), {"a", "b", "c", "d", "e"}) self.assertEqual(infer_bayesian.cardinality, { "a": 2, "b": 2, "c": 2, "d": 2, "e": 2 }) self.assertIsInstance(infer_bayesian.factors, defaultdict) self.assertEqual( set(infer_bayesian.factors["a"]), set([ self.bayesian.get_cpds("a").to_factor(), self.bayesian.get_cpds("b").to_factor(), ]), ) self.assertEqual( set(infer_bayesian.factors["b"]), set([ self.bayesian.get_cpds("b").to_factor(), self.bayesian.get_cpds("c").to_factor(), ]), ) self.assertEqual( set(infer_bayesian.factors["c"]), set([ self.bayesian.get_cpds("c").to_factor(), self.bayesian.get_cpds("d").to_factor(), ]), ) self.assertEqual( set(infer_bayesian.factors["d"]), set([ self.bayesian.get_cpds("d").to_factor(), self.bayesian.get_cpds("e").to_factor(), ]), ) self.assertEqual( set(infer_bayesian.factors["e"]), set([self.bayesian.get_cpds("e").to_factor()]), )
def _absorption(self, marginal_tree, c_i, c_j): """ Send a message from c_j to c_i during propagation. """ # Union of all factors in c_j and its separators' factors neighbors = marginal_tree.neighbors(c_j) if c_i in neighbors: neighbors.remove(c_i) R_s = [] for neighbor in neighbors: if (neighbor, c_j) in marginal_tree.separators: R_s.extend(marginal_tree.separators[(neighbor, c_j)]) R_s.extend(marginal_tree.factor_node_assignment[c_j]) separator = frozenset(c_i).intersection(frozenset(c_j)) # Variables to marginalize from R_s marginalize = list(set(c_j) - set(separator)) R_s = self._find_relevant_potentials(R_s, separator, marginal_tree) R_s = Inference.sum_out(marginalize, R_s) # Associate the messages with the separator of c_i and c_j, # in the right direction (from c_j to c_i) marginal_tree.separators[(c_j, c_i)] = R_s
def test_bayesian_inference_init(self): infer_bayesian = Inference(self.bayesian) self.assertEqual(set(infer_bayesian.variables), {'a', 'b', 'c', 'd', 'e'}) self.assertEqual(infer_bayesian.cardinality, { 'a': 2, 'b': 2, 'c': 2, 'd': 2, 'e': 2 }) self.assertIsInstance(infer_bayesian.factors, defaultdict) self.assertEqual( set(infer_bayesian.factors['a']), set([ self.bayesian.get_cpds('a').to_factor(), self.bayesian.get_cpds('b').to_factor() ])) self.assertEqual( set(infer_bayesian.factors['b']), set([ self.bayesian.get_cpds('b').to_factor(), self.bayesian.get_cpds('c').to_factor() ])) self.assertEqual( set(infer_bayesian.factors['c']), set([ self.bayesian.get_cpds('c').to_factor(), self.bayesian.get_cpds('d').to_factor() ])) self.assertEqual( set(infer_bayesian.factors['d']), set([ self.bayesian.get_cpds('d').to_factor(), self.bayesian.get_cpds('e').to_factor() ])) self.assertEqual(set(infer_bayesian.factors['e']), set([self.bayesian.get_cpds('e').to_factor()]))
def test_markov_inference_init(self): infer_markov = Inference(self.markov) self.assertEqual(set(infer_markov.variables), {"a", "b", "c", "d"}) self.assertEqual(infer_markov.cardinality, { "a": 2, "b": 2, "c": 2, "d": 2 }) self.assertEqual( infer_markov.factors, { "a": [ DiscreteFactor(["a", "b"], [2, 2], np.array([100, 1, 1, 100])), DiscreteFactor(["a", "c"], [2, 2], np.array([40, 30, 100, 20])), ], "b": [ DiscreteFactor(["a", "b"], [2, 2], np.array([100, 1, 1, 100])), DiscreteFactor(["b", "d"], [2, 2], np.array([1, 100, 100, 1])), ], "c": [ DiscreteFactor(["a", "c"], [2, 2], np.array([40, 30, 100, 20])), DiscreteFactor(["c", "d"], [2, 2], np.array([60, 60, 40, 40])), ], "d": [ DiscreteFactor(["b", "d"], [2, 2], np.array([1, 100, 100, 1])), DiscreteFactor(["c", "d"], [2, 2], np.array([60, 60, 40, 40])), ], }, )
def query(self, query, evidence=None, elimination_order=None): if not isinstance(query, list): query = [query] ### DEBUG # print(">>>>>--------------------------------------<<<<<<") # print(">>> Query: %s" % query) # print(">>> Evidence: %s" % evidence) # print(">>> Saved MTs:") # for mt in self.marginal_trees: # print("--> Nodes: %s" % mt.nodes()) # print(mt.evidence) ### --- DEBUG # See if it is possible to reuse saved MTs marginal_tree = None reuse_mts = self.find_reusable(query, evidence) ### DEBUG # print(">>> Reusable MTs:") # for mt in reuse_mts: # print("--> Nodes: %s" % mt.nodes()) # print(mt.evidence) ### --- DEBUG factors = [] if len(reuse_mts) > 0: # TODO: choose MT by the size of it # Choose one MT and rebuild it for the new query and evidence marginal_tree = reuse_mts[0] ### DEBUG # print(">>> Nodes before evidence") # print(marginal_tree.nodes()) # print(">>> Messages before evidence") # for s in marginal_tree.separators: # print("--> Separator %s" % s.__str__()) # for f in marginal_tree.separators[s]: # print(f) ### --- DEBUG # Reduce new evidences new_evidence = {k: evidence[k] for k in evidence if k not in marginal_tree.evidence} marginal_tree.set_evidence(new_evidence) ### DEBUG # print(">>> Nodes after evidence") # print(marginal_tree.nodes()) # print(">>> Messages before evidence") # for s in marginal_tree.separators: # print("--> Separator %s" % s.__str__()) # for f in marginal_tree.separators[s]: # print(f) ### --- DEBUG # Rebuild MT to answer new query marginal_tree = marginal_tree.rebuild(query, evidence) # Perform one way propagation self.partial_one_way_propagation(marginal_tree) else: marginal_tree = self._build(query, evidence, elimination_order) ### DEBUG # print(">>> Saving marginal tree") # print(marginal_tree.nodes()) # print(marginal_tree.evidence) ### --- DEBUG # Save the new MT self.marginal_trees.append(marginal_tree) # Answer the query node = marginal_tree.root # Define the variables to marginalize marginalize = set(node) - set(query) # Collect factors for the node neighbors = marginal_tree.neighbors(node) # Collect incoming messages for neighbor in neighbors: if (neighbor, node) in marginal_tree.separators: factors.extend([f for f in marginal_tree.separators[(neighbor, node)] if len(f.variables) > 0]) ### DEBUG # print(">>> Root: %s" % marginal_tree.root.__str__()) # print("incoming...") # for f in factors: # print(f) ### --- DEBUG # Collect assigned Factors factors.extend([f for f in marginal_tree.factor_node_assignment[node] if len(f.variables) > 0]) ### DEBUG # print("assigned...") # for f in marginal_tree.factor_node_assignment[node]: # print(f) # print("going to SUM OUT %s" % marginalize.__str__()) # for f in factors: # print(f) ### --- DEBUG result = None # Sum out variables from factors if len(factors) > 0: result = Inference.sum_out(marginalize, factors) ### DEBUG # print(">>> After SUM OUT") # for f in result: # print(f) ### --- DEBUG # Multiply all remaining CPDs if len(result) > 0: result = factor_product(*result) ### DEBUG # print(">>> After PRODUCT") # print(result) ### --- DEBUG # Normalize result.normalize() ### DEBUG # print(">>> After Normalize") # print(result) # marginal_tree.draw() ### --- DEBUG return result
def query(self, query, evidence=None, elimination_order=None): if not isinstance(query, list): query = [query] ### DEBUG # print(">>>>>--------------------------------------<<<<<<") # print(">>> Query: %s" % query) # print(">>> Evidence: %s" % evidence) # print(">>> Saved MTs:") # for mt in self.marginal_trees: # print("--> Nodes: %s" % mt.nodes()) # print(mt.evidence) ### --- DEBUG # See if it is possible to reuse saved MTs marginal_tree = None reuse_mts = self.find_reusable(query, evidence) ### DEBUG # print(">>> Reusable MTs:") # for mt in reuse_mts: # print("--> Nodes: %s" % mt.nodes()) # print(mt.evidence) ### --- DEBUG factors = [] if len(reuse_mts) > 0: # TODO: choose MT by the size of it # Choose one MT and rebuild it for the new query and evidence marginal_tree = reuse_mts[0] ### DEBUG # print(">>> Nodes before evidence") # print(marginal_tree.nodes()) # print(">>> Messages before evidence") # for s in marginal_tree.separators: # print("--> Separator %s" % s.__str__()) # for f in marginal_tree.separators[s]: # print(f) ### --- DEBUG # Reduce new evidences new_evidence = { k: evidence[k] for k in evidence if k not in marginal_tree.evidence } marginal_tree.set_evidence(new_evidence) ### DEBUG # print(">>> Nodes after evidence") # print(marginal_tree.nodes()) # print(">>> Messages before evidence") # for s in marginal_tree.separators: # print("--> Separator %s" % s.__str__()) # for f in marginal_tree.separators[s]: # print(f) ### --- DEBUG # Rebuild MT to answer new query marginal_tree = marginal_tree.rebuild(query, evidence) # Perform one way propagation self.partial_one_way_propagation(marginal_tree) else: marginal_tree = self._build(query, evidence, elimination_order) ### DEBUG # print(">>> Saving marginal tree") # print(marginal_tree.nodes()) # print(marginal_tree.evidence) ### --- DEBUG # Save the new MT self.marginal_trees.append(marginal_tree) # Answer the query node = marginal_tree.root # Define the variables to marginalize marginalize = set(node) - set(query) # Collect factors for the node neighbors = marginal_tree.neighbors(node) # Collect incoming messages for neighbor in neighbors: if (neighbor, node) in marginal_tree.separators: factors.extend([ f for f in marginal_tree.separators[(neighbor, node)] if len(f.variables) > 0 ]) ### DEBUG # print(">>> Root: %s" % marginal_tree.root.__str__()) # print("incoming...") # for f in factors: # print(f) ### --- DEBUG # Collect assigned Factors factors.extend([ f for f in marginal_tree.factor_node_assignment[node] if len(f.variables) > 0 ]) ### DEBUG # print("assigned...") # for f in marginal_tree.factor_node_assignment[node]: # print(f) # print("going to SUM OUT %s" % marginalize.__str__()) # for f in factors: # print(f) ### --- DEBUG result = None # Sum out variables from factors if len(factors) > 0: result = Inference.sum_out(marginalize, factors) ### DEBUG # print(">>> After SUM OUT") # for f in result: # print(f) ### --- DEBUG # Multiply all remaining CPDs if len(result) > 0: result = factor_product(*result) ### DEBUG # print(">>> After PRODUCT") # print(result) ### --- DEBUG # Normalize result.normalize() ### DEBUG # print(">>> After Normalize") # print(result) # marginal_tree.draw() ### --- DEBUG return result
def setUp(self): self.sn2 = { "grade": ["A", "B", "F"], "diff": ["high", "low"], "intel": ["poor", "good", "very good"], } self.sn1 = { "speed": ["low", "medium", "high"], "switch": ["on", "off"], "time": ["day", "night"], } self.sn2_no_names = { "grade": [0, 1, 2], "diff": [0, 1], "intel": [0, 1, 2] } self.sn1_no_names = { "speed": [0, 1, 2], "switch": [0, 1], "time": [0, 1] } self.phi1 = DiscreteFactor(["speed", "switch", "time"], [3, 2, 2], np.ones(12)) self.phi2 = DiscreteFactor(["speed", "switch", "time"], [3, 2, 2], np.ones(12), state_names=self.sn1) self.cpd1 = TabularCPD( "grade", 3, [ [0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.8, 0.8, 0.8, 0.8, 0.8, 0.8], ], evidence=["diff", "intel"], evidence_card=[2, 3], ) self.cpd2 = TabularCPD( "grade", 3, [ [0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.8, 0.8, 0.8, 0.8, 0.8, 0.8], ], evidence=["diff", "intel"], evidence_card=[2, 3], state_names=self.sn2, ) student = BayesianModel([("diff", "grade"), ("intel", "grade")]) diff_cpd = TabularCPD("diff", 2, [[0.2, 0.8]]) intel_cpd = TabularCPD("intel", 2, [[0.3, 0.7]]) grade_cpd = TabularCPD( "grade", 3, [[0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1], [0.8, 0.8, 0.8, 0.8]], evidence=["diff", "intel"], evidence_card=[2, 2], ) student.add_cpds(diff_cpd, intel_cpd, grade_cpd) self.model1 = Inference(student) self.model2 = Inference(student)