def add_separator(self, separator): """ Add a valid separator made up of variables to the list of separators Variables can be both list/dict of references or a list of variable names :type separator: list[str] or dict[Variable,None] or list[Variable] :return: None """ if all(isinstance(x, str) for x in separator): separator = [self.get_variable_by_name(name) for name in separator] separator = dict.fromkeys(separator) if not separator.keys() <= self._variables.keys(): raise AttributeError( "The given separator is not valid for the junction tree") new_node = Node(BeliefTable(separator)) self._separators.append(new_node)
def add_clique(self, clique): """ Add a valid clique made up of variables to the list of cliques Variables can be both list/dict of references or a list of variable names :type clique: list[str] or dict[Variable,None] or list[Variable] :return: None """ if all(isinstance(x, str) for x in clique): clique = [self.get_variable_by_name(name) for name in clique] clique = dict.fromkeys(clique) if not clique.keys() <= self._variables.keys(): raise AttributeError( "The given clique is not valid for the junction tree") new_node = Node(BeliefTable(clique)) self._cliques.append(new_node)
def test_marginalization(self): # Check that it doesn't allow marginalization on sets greater than the variables of the table dict1 = dict.fromkeys([self.A]) dict2 = dict.fromkeys([self.A, self.B]) arr1 = np.arange(2).reshape(2) t1 = BeliefTable(dict1, arr1) self.assertRaises(AttributeError, t1.marginalize, dict2) # Test marginalization on single variable dict1 = dict.fromkeys([self.A, self.B]) dict2 = dict.fromkeys([self.A]) arr1 = np.arange(4).reshape((2, 2)) t1 = BeliefTable(dict1, arr1) t2 = t1.marginalize(dict2) self.assertEqual(t2.get_prob(0), 1) self.assertEqual(t2.get_prob(1), 5) # Test marginalization on one variable from 3 dict1 = dict.fromkeys([self.A, self.B, self.C]) dict2 = dict.fromkeys([self.C]) arr1 = np.arange(8).reshape((2, 2,2)) t1 = BeliefTable(dict1, arr1) t2 = t1.marginalize(dict2) self.assertEqual(t2.get_prob(0), 12) self.assertEqual(t2.get_prob(1), 16) # Test marginalization on two variables dict1 = dict.fromkeys([self.A, self.B, self.C]) dict2 = dict.fromkeys([self.A, self.C]) arr1 = np.arange(8).reshape((2, 2,2)) t1 = BeliefTable(dict1, arr1) t2 = t1.marginalize(dict2) self.assertEqual(t2.get_prob((0, 0)), 2) self.assertEqual(t2.get_prob((0, 1)), 4) self.assertEqual(t2.get_prob((1, 0)), 10) self.assertEqual(t2.get_prob((1, 1)), 12)
def test_collect_and_distribute(self): # Apple tree example, 2 clusters tS = BeliefTable(dict.fromkeys([self.S]), np.zeros(2)) tD = BeliefTable(dict.fromkeys([self.D]), np.zeros(2)) tL = BeliefTable(dict.fromkeys([self.S, self.D, self.L]), np.zeros((2, 2, 2))) tH = BeliefTable(dict.fromkeys([self.H, self.S])) tS.set_probability_dict({'S': 0}, 0.9) tS.set_probability_dict({'S': 1}, 0.1) tD.set_probability_dict({'D': 0}, 0.9) tD.set_probability_dict({'D': 1}, 0.1) tL.set_probability_dict({'S': 0, 'D': 0, 'L': 0}, 0.98) tL.set_probability_dict({'S': 0, 'D': 0, 'L': 1}, 0.02) tL.set_probability_dict({'S': 0, 'D': 1, 'L': 0}, 0.15) tL.set_probability_dict({'D': 1, 'L': 1, 'S': 0}, 0.85) tL.set_probability_dict({'L': 0, 'S': 1, 'D': 0}, 0.1) tL.set_probability_dict({'S': 1, 'D': 0, 'L': 1}, 0.9) tL.set_probability_dict({'S': 1, 'D': 1, 'L': 0}, 0.05) tL.set_probability_dict({'S': 1, 'D': 1, 'L': 1}, 0.95) tH.set_probability_dict({'H': 0, 'S': 0}, 0.8) tH.set_probability_dict({'H': 0, 'S': 1}, 0.3) tH.set_probability_dict({'H': 1, 'S': 0}, 0.2) tH.set_probability_dict({'H': 1, 'S': 1}, 0.7) net = BayesianNet() net.add_variable(self.L) net.add_variable(self.S) net.add_variable(self.D) net.add_variable(self.H) net.add_dependence('L', 'S') net.add_dependence('L', 'D') net.add_dependence('H', 'S') net.add_prob_table('L', tL) net.add_prob_table('S', tS) net.add_prob_table('D', tD) net.add_prob_table('H', tH) jtree = JunctionTree(dict.fromkeys([self.S, self.D, self.L, self.H])) jtree.add_clique(['S', 'D', 'L']) jtree.set_variable_chosen_clique('S', ['S', 'D', 'L']) jtree.set_variable_chosen_clique('D', ['S', 'D', 'L']) jtree.set_variable_chosen_clique('L', ['S', 'D', 'L']) jtree.add_clique(['S', 'H']) jtree.set_variable_chosen_clique('H', ['H', 'S']) jtree.add_separator(['S']) jtree.add_link(['S', 'H'], ['S']) jtree.add_link(['S', 'D', 'L'], ['S']) jtree.initialize_tables(net) jtree.add_evidence('L', 0) jtree.add_evidence('H', 1) jtree.sum_propagate() STable = jtree.calculate_variable_probability('S') DTable = jtree.calculate_variable_probability('D') LTable = jtree.calculate_variable_probability('L') HTable = jtree.calculate_variable_probability('H') self.assertAlmostEqual(round(STable.get_prob(0), 4), 0.9604) self.assertAlmostEqual(round(STable.get_prob(1), 4), 0.0396) self.assertAlmostEqual(round(DTable.get_prob(0), 4), 0.9819) self.assertAlmostEqual(round(DTable.get_prob(1), 4), 0.0181) self.assertAlmostEqual(round(LTable.get_prob(0), 4), 1) self.assertAlmostEqual(round(LTable.get_prob(1), 4), 0) self.assertAlmostEqual(round(HTable.get_prob(0), 4), 0) self.assertAlmostEqual(round(HTable.get_prob(1), 4), 1)
def test_inserting_evidence(self): # Cluster tree with only one node tS = BeliefTable([self.S], np.zeros(2)) tD = BeliefTable([self.D], np.zeros(2)) tL = BeliefTable(dict.fromkeys([self.S, self.D, self.L]), np.zeros((2, 2, 2))) tS.set_probability_dict({'S': 0}, 0.9) tS.set_probability_dict({'S': 1}, 0.1) tD.set_probability_dict({'D': 0}, 0.9) tD.set_probability_dict({'D': 1}, 0.1) tL.set_probability_dict({'S': 0, 'D': 0, 'L': 0}, 0.98) tL.set_probability_dict({'S': 0, 'D': 0, 'L': 1}, 0.02) tL.set_probability_dict({'S': 0, 'D': 1, 'L': 0}, 0.15) tL.set_probability_dict({'D': 1, 'L': 1, 'S': 0}, 0.85) tL.set_probability_dict({'L': 0, 'S': 1, 'D': 0}, 0.1) tL.set_probability_dict({'S': 1, 'D': 0, 'L': 1}, 0.9) tL.set_probability_dict({'S': 1, 'D': 1, 'L': 0}, 0.05) tL.set_probability_dict({'S': 1, 'D': 1, 'L': 1}, 0.95) net = BayesianNet() net.add_variable(self.L) net.add_variable(self.S) net.add_variable(self.D) net.add_dependence('L', 'S') net.add_dependence('L', 'D') net.add_prob_table('L', tL) net.add_prob_table('S', tS) net.add_prob_table('D', tD) jtree = JunctionTree(dict.fromkeys([self.S, self.D, self.L])) jtree.add_clique(['S', 'D', 'L']) jtree.set_variable_chosen_clique('S', ['S', 'D', 'L']) jtree.set_variable_chosen_clique('D', ['S', 'D', 'L']) jtree.set_variable_chosen_clique('L', ['S', 'D', 'L']) jtree.initialize_tables(net) # Add evidence to one node jtree.add_evidence('L', 0) Stable = jtree.calculate_variable_probability('S') Dtable = jtree.calculate_variable_probability('D') self.assertAlmostEqual(Stable.get_prob(0), 0.9884, 4) self.assertAlmostEqual(Stable.get_prob(1), 0.0116, 4) self.assertAlmostEqual(Dtable.get_prob(0), 0.9829, 4) self.assertAlmostEqual(Dtable.get_prob(1), 0.0171, 4) # Add evidence to another one jtree.add_evidence('S', 0) Stable = jtree.calculate_variable_probability('S') Dtable = jtree.calculate_variable_probability('D') self.assertAlmostEqual(Stable.get_prob(0), 1, 4) self.assertAlmostEqual(Stable.get_prob(1), 0, 4) self.assertAlmostEqual(Dtable.get_prob(0), 0.9833, 4) self.assertAlmostEqual(Dtable.get_prob(1), 0.0167, 4)
def test_bnet_linking(self): # Test if it's possible to calculate the probability of a variable given the bayesian net # No message passing, single cluster tS = BeliefTable([self.S], np.zeros(2)) tD = BeliefTable([self.D], np.zeros(2)) tL = BeliefTable(dict.fromkeys([self.S, self.D, self.L]), np.zeros((2, 2, 2))) tS.set_probability_dict({'S': 0}, 0.9) tS.set_probability_dict({'S': 1}, 0.1) tD.set_probability_dict({'D': 0}, 0.9) tD.set_probability_dict({'D': 1}, 0.1) tL.set_probability_dict({'S': 0, 'D': 0, 'L': 0}, 0.98) tL.set_probability_dict({'S': 0, 'D': 0, 'L': 1}, 0.02) tL.set_probability_dict({'S': 0, 'D': 1, 'L': 0}, 0.15) tL.set_probability_dict({'D': 1, 'L': 1, 'S': 0}, 0.85) tL.set_probability_dict({'L': 0, 'S': 1, 'D': 0}, 0.1) tL.set_probability_dict({'S': 1, 'D': 0, 'L': 1}, 0.9) tL.set_probability_dict({'S': 1, 'D': 1, 'L': 0}, 0.05) tL.set_probability_dict({'S': 1, 'D': 1, 'L': 1}, 0.95) net = BayesianNet() net.add_variable(self.L) net.add_variable(self.S) net.add_variable(self.D) net.add_dependence('L', 'S') net.add_dependence('L', 'D') net.add_prob_table('L', tL) net.add_prob_table('S', tS) net.add_prob_table('D', tD) jtree = JunctionTree(dict.fromkeys([self.S, self.D, self.L])) jtree.add_clique(['S', 'D', 'L']) jtree.set_variable_chosen_clique('S', ['S', 'D', 'L']) jtree.set_variable_chosen_clique('D', ['S', 'D', 'L']) jtree.set_variable_chosen_clique('L', ['S', 'D', 'L']) jtree.initialize_tables(net) Ltable = jtree.calculate_variable_probability('L') self.assertAlmostEqual(Ltable.get_prob(0), 0.8168) self.assertAlmostEqual(Ltable.get_prob(1), 0.1832)
def test_table_assignment(self): # Check if assigning tables via identifiers works correctly even when the order of variables is wrong S = Variable('S', 'S', [0, 1]) D = Variable('D', 'D', [0, 1]) L = Variable('L', 'L', [0, 1]) tS = BeliefTable(dict.fromkeys([S]), np.zeros(2)) tD = BeliefTable(dict.fromkeys([D]), np.zeros(2)) tL = BeliefTable(dict.fromkeys([S, D, L]), np.zeros((2, 2, 2))) tS.set_probability_dict({'S': 0}, 0.9) tS.set_probability_dict({'S': 1}, 0.1) tD.set_probability_dict({'D': 0}, 0.9) tD.set_probability_dict({'D': 1}, 0.1) tL.set_probability_dict({'S': 0, 'D': 0, 'L': 0}, 0.98) tL.set_probability_dict({'S': 0, 'D': 0, 'L': 1}, 0.02) tL.set_probability_dict({'S': 0, 'D': 1, 'L': 0}, 0.15) tL.set_probability_dict({'D': 1, 'L': 1, 'S': 0}, 0.85) tL.set_probability_dict({'L': 0, 'S': 1, 'D': 0}, 0.1) tL.set_probability_dict({'S': 1, 'D': 0, 'L': 1}, 0.9) tL.set_probability_dict({'S': 1, 'D': 1, 'L': 0}, 0.05) tL.set_probability_dict({'S': 1, 'D': 1, 'L': 1}, 0.95) net = BayesianNet() net.add_variable(L) net.add_variable(S) net.add_variable(D) net.add_dependence('L', 'S') net.add_dependence('L', 'D') net.add_prob_table('L', tL) net.add_prob_table('S', tS) net.add_prob_table('D', tD) self.assertEqual(str(tS), str(net.get_table(S))) self.assertEqual(str(tD), str(net.get_table(D))) self.assertEqual(str(tL), str(net.get_table(L)))