def test_multiple_pa_ch_table(): """ Tests create table with multiple parent. :return: None. """ d_probs = [ 0.23323615160349853, 0.7667638483965015, 0.7563025210084033, 0.24369747899159663 ] r_probs = [ 0.31000000000000005, 0.69, 0.27, 0.73, 0.13, 0.87, 0.06999999999999995, 0.93 ] g_probs = [0.49, 0.51] g = BbnNode(Variable(0, 'gender', ['female', 'male']), g_probs) d = BbnNode(Variable(1, 'drug', ['false', 'true']), d_probs) r = BbnNode(Variable(2, 'recovery', ['false', 'true']), r_probs) table = Table(r, parents=[d, g]) assert table.has_parents() lhs = np.array(list(table.probs.values())) rhs = np.array([[0.31, 1.0], [0.27, 1.0], [0.13, 1.0], [0.07, 1.0]]) assert_almost_equal(lhs, rhs) lhs = list(table.probs.keys()) rhs = [ '0=female,1=false', '0=female,1=true', '0=male,1=false', '0=male,1=true' ] assert len(lhs) == len(rhs) for l, r in zip(lhs, rhs): assert l == r
def test_clique_is_superset(): """ Tests if clique is a superset of another clique. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) d = BbnNode(Variable(3, 'd', ['on', 'off']), [0.9, 0.1, 0.5, 0.5]) abc = Clique([a, b, c]) abc2 = Clique([a, b, c]) ab = Clique([a, b]) ac = Clique([a, c]) bc = Clique([b, c]) cd = Clique([c, d]) assert abc.is_superset(Clique([a])) == 1 assert abc.is_superset(Clique([b])) == 1 assert abc.is_superset(Clique([c])) == 1 assert abc.is_superset(Clique([d])) == 0 assert abc.is_superset(abc2) == 1 assert abc.is_superset(ab) == 1 assert abc.is_superset(ac) == 1 assert abc.is_superset(bc) == 1 assert abc.is_superset(cd) == 0
def test_inference_4(): """ Tests inference on simple customized graph. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.7, 0.3]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.9, 0.1, 0.3, 0.7, 0.5, 0.5, 0.1, 0.9]) e = BbnNode(Variable(4, 'e', ['on', 'off']), [0.6, 0.4, 0.2, 0.8]) bbn = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_node(e) \ .add_edge(Edge(a, c, EdgeType.DIRECTED)) \ .add_edge(Edge(b, c, EdgeType.DIRECTED)) \ .add_edge(Edge(c, e, EdgeType.DIRECTED)) join_tree = InferenceController.apply(bbn) expected = { 'a': [0.7, 0.3], 'b': [0.4, 0.6], 'c': [0.456, 0.544], 'e': [0.3824, 0.6176] } __validate_posterior__(expected, join_tree)
def test_deepcopy(): """ Tests deep copy of join tree. :return: None """ a = BbnNode(Variable(0, 'a', ['t', 'f']), [0.2, 0.8]) b = BbnNode(Variable(1, 'b', ['t', 'f']), [0.1, 0.9, 0.9, 0.1]) bbn = Bbn().add_node(a).add_node(b) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) lhs = InferenceController.apply(bbn) rhs = copy.deepcopy(lhs) lhs_nodes, rhs_nodes = lhs.get_nodes(), rhs.get_nodes() lhs_edges, rhs_edges = lhs.get_edges(), rhs.get_edges() lhs_neighbors, rhs_neighbors = lhs.neighbors, rhs.neighbors lhs_evidences, rhs_evidences = lhs.evidences, rhs.evidences lhs_potentials, rhs_potentials = lhs.potentials, rhs.potentials assert len(lhs_nodes) == len(rhs_nodes) assert len(lhs_edges) == len(rhs_edges) assert len(lhs_neighbors) == len(rhs_neighbors) assert len(lhs_evidences) == len(rhs_evidences) assert len(lhs_potentials) == len(rhs_potentials) list(lhs.get_nodes())[0].nodes[0].variable.values[0] = 'true' lhs_v = list(lhs.get_nodes())[0].nodes[0].variable.values[0] rhs_v = list(rhs.get_nodes())[0].nodes[0].variable.values[0] assert lhs_v != rhs_v
def test_jointree_creation(): """ Tests join tree creation. :return: None. """ n0 = BbnNode(Variable(0, 'n0', ['t', 'f']), []) n1 = BbnNode(Variable(1, 'n1', ['t', 'f']), []) n2 = BbnNode(Variable(2, 'n2', ['t', 'f']), []) clique0 = Clique([n0, n1]) clique1 = Clique([n1, n2]) sep_set0 = clique0.get_sep_set(clique1) sep_set1 = clique0.get_sep_set(clique1) sep_set2 = clique1.get_sep_set(clique0) sep_set3 = clique0.get_sep_set(clique0) e0 = JtEdge(sep_set0) e1 = JtEdge(sep_set1) e2 = JtEdge(sep_set2) e3 = JtEdge(sep_set3) g = JoinTree().add_edge(e0).add_edge(e1).add_edge(e2).add_edge(e3) nodes = g.get_nodes() edges = g.get_edges() assert len(nodes) == 3 assert len(edges) == 1 assert len(g.get_flattened_edges()) == 2
def test_sampling_with_rejection(): """ Tests sampling a serial graph with rejection and evidence set. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) bbn = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) \ .add_edge(Edge(b, c, EdgeType.DIRECTED)) sampler = LogicSampler(bbn) n_samples = 10000 samples = pd.DataFrame( sampler.get_samples(evidence={0: 'on'}, n_samples=n_samples, seed=37)) samples.columns = ['a', 'b', 'c'] assert n_samples == samples.shape[0] assert 3 == samples.shape[1] s_a = samples.a.value_counts() s_b = samples.b.value_counts() s_c = samples.c.value_counts() s_a = s_a / s_a.sum() s_b = s_b / s_b.sum() s_c = s_c / s_c.sum() s_a = s_a.sort_index().values s_b = s_b.sort_index().values s_c = s_c.sort_index().values assert_almost_equal(s_a, np.array([1.0])) assert_almost_equal(s_b, np.array([0.5006, 0.4994])) assert_almost_equal(s_c, np.array([0.5521, 0.4479])) join_tree = InferenceController.apply(bbn) ev = EvidenceBuilder() \ .with_node(join_tree.get_bbn_node_by_name('a')) \ .with_evidence('on', 1.0) \ .build() join_tree.set_observation(ev) posteriors = join_tree.get_posteriors() assert_almost_equal(s_a, np.array([posteriors['a']['on']]), decimal=1) assert_almost_equal(s_b, np.array( [posteriors['b']['off'], posteriors['b']['on']]), decimal=1) assert_almost_equal(s_c, np.array( [posteriors['c']['off'], posteriors['c']['on']]), decimal=1)
def test_sampling(): """ Tests sampling a serial graph. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) bbn = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) \ .add_edge(Edge(b, c, EdgeType.DIRECTED)) sampler = LogicSampler(bbn) n_samples = 10000 samples = pd.DataFrame(sampler.get_samples(n_samples=n_samples, seed=37)) samples.columns = ['a', 'b', 'c'] assert n_samples == samples.shape[0] assert 3 == samples.shape[1] s_a = samples.a.value_counts() s_b = samples.b.value_counts() s_c = samples.c.value_counts() s_a = s_a / s_a.sum() s_b = s_b / s_b.sum() s_c = s_c / s_c.sum() s_a = s_a.sort_index() s_b = s_b.sort_index() s_c = s_c.sort_index() assert_almost_equal(s_a.values, np.array([0.4985, 0.5015])) assert_almost_equal(s_b.values, np.array([0.5502, 0.4498])) assert_almost_equal(s_c.values, np.array([0.5721, 0.4279])) join_tree = InferenceController.apply(bbn) posteriors = join_tree.get_posteriors() assert_almost_equal(s_a.values, np.array( [posteriors['a']['off'], posteriors['a']['on']]), decimal=1) assert_almost_equal(s_b.values, np.array( [posteriors['b']['off'], posteriors['b']['on']]), decimal=1) assert_almost_equal(s_c.values, np.array( [posteriors['c']['off'], posteriors['c']['on']]), decimal=1)
def test_clique_creation(): a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) clique = Clique([a, b, c]) assert clique.id == 45718137 assert len(clique.nodes) == 3 assert clique.get_weight() == 8 assert clique.contains(0) assert clique.contains(1) assert clique.contains(2) assert clique.contains(3) == 0
def get_huang_graph(): """ Gets the Huang reference BBN graph. :return: BBN. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) d = BbnNode(Variable(3, 'd', ['on', 'off']), [0.9, 0.1, 0.5, 0.5]) e = BbnNode(Variable(4, 'e', ['on', 'off']), [0.3, 0.7, 0.6, 0.4]) f = BbnNode(Variable(5, 'f', ['on', 'off']), [0.01, 0.99, 0.01, 0.99, 0.01, 0.99, 0.99, 0.01]) g = BbnNode(Variable(6, 'g', ['on', 'off']), [0.8, 0.2, 0.1, 0.9]) h = BbnNode(Variable(7, 'h', ['on', 'off']), [0.05, 0.95, 0.95, 0.05, 0.95, 0.05, 0.95, 0.05]) bbn = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_node(d) \ .add_node(e) \ .add_node(f) \ .add_node(g) \ .add_node(h) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) \ .add_edge(Edge(a, c, EdgeType.DIRECTED)) \ .add_edge(Edge(b, d, EdgeType.DIRECTED)) \ .add_edge(Edge(c, e, EdgeType.DIRECTED)) \ .add_edge(Edge(d, f, EdgeType.DIRECTED)) \ .add_edge(Edge(e, f, EdgeType.DIRECTED)) \ .add_edge(Edge(c, g, EdgeType.DIRECTED)) \ .add_edge(Edge(e, h, EdgeType.DIRECTED)) \ .add_edge(Edge(g, h, EdgeType.DIRECTED)) return bbn
def create_bbn_nodes(): # globals()['machine_%s' %machine_name] global num_of_nodes try: num_of_nodes = int(input("How many nodes your network has: ")) if num_of_nodes > 1: for i in range(num_of_nodes): node_id = int(input("Please input the node ID: ")) node_name = str(input("Please input the node name: ")) node_values_input = input( "Please input the node values (seperated by comma, e.g. low,high or on,off): ") node_values = node_values_input.split(",") prob_array_input = input("Please input the probability array (seperated by comma, e.g. 0.5,0.5): ") prob_array_str = prob_array_input.split(",") prob_array = [] for x in prob_array_str: prob_array.append(float(x)) globals()['%s' % node_name] = BbnNode(Variable(node_id, str(node_name), node_values), prob_array) globals()['machine_%s' % machine_name] = globals()['machine_%s' % machine_name].add_node( globals()['%s' % node_name]) else: print("Number of nodes should be atleast 2") create_bbn_nodes() except: print("Name of nodes is out of range") create_bbn_nodes()
def build_bbn(variable_profiles, g, p): """ Builds a BBN from a DAG, g, and paremeters, p. :param variable_profiles: Variable profiles. :param g: DAG. :param p: Parameters. :return: BBN. """ bbn = Bbn() nodes = list(g.nodes) bbn_node_dict = {} for idx in nodes: name = g.nodes[idx]['name'] domain = variable_profiles[name] cpt = p[idx] v = Variable(idx, name, domain) n = BbnNode(v, cpt) bbn.add_node(n) bbn_node_dict[idx] = n edges = list(g.edges) for edge in edges: pa = bbn_node_dict[edge[0]] ch = bbn_node_dict[edge[1]] e = Edge(pa, ch, EdgeType.DIRECTED) bbn.add_edge(e) return bbn
def convert_for_exact_inference(g, p): """ Converts the graph and parameters to a BBN. :param g: Directed acyclic graph (DAG in the form of networkx). :param p: Parameters. :return: BBN. """ bbn = Bbn() bbn_nodes = {} for node in g.nodes: id = node params = p[id]['params'].flatten() states = [ 'state{}'.format(state) for state in range(p[id]['shape'][1]) ] v = Variable(id, str(id), states) n = BbnNode(v, params) bbn.add_node(n) bbn_nodes[id] = n for e in g.edges: pa = bbn_nodes[e[0]] ch = bbn_nodes[e[1]] bbn.add_edge(Edge(pa, ch, EdgeType.DIRECTED)) return bbn
def test_from_data_simple(): """ Tests create BBN from data. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) bbn1 = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) \ .add_edge(Edge(b, c, EdgeType.DIRECTED)) sampler = LogicSampler(bbn1) samples = sampler.get_samples(n_samples=10000, seed=37) i2n = {n.variable.id: n.variable.name for n in bbn1.get_nodes()} samples = pd.DataFrame(samples).rename(columns=i2n) parents = { 'a': [], 'b': ['a'], 'c': ['b'] } bbn2 = Factory.from_data(parents, samples) join_tree1 = InferenceController.apply(bbn1) join_tree2 = InferenceController.apply(bbn2) posteriors1 = join_tree1.get_posteriors() posteriors2 = join_tree2.get_posteriors() for k, v1 in posteriors1.items(): assert k in posteriors2 v2 = posteriors2[k] assert len(v1) == len(v2) for k2 in v1: assert k2 in v2 diff = abs(v1[k2] - v2[k2]) assert diff < 0.01
def test_pa_ch_table(): """ Tests create table with a single parent. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) table = Table(b, parents=[a]) assert table.has_parents() lhs = np.array(list(table.probs.values())) rhs = np.array([[0.5, 1.0], [0.4, 1.0]]) assert_almost_equal(lhs, rhs) assert 'on' == table.get_value(0.4, sample={0: 'on'}) assert 'off' == table.get_value(0.7, sample={0: 'on'}) assert 'on' == table.get_value(0.3, sample={0: 'off'}) assert 'off' == table.get_value(0.6, sample={0: 'off'})
def test_clique_creation(): """ Tests clique creation. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) clique = Clique([a, b, c]) assert clique.id == '0-1-2' assert len(clique.nodes) == 3 assert clique.get_weight() == 8 assert clique.contains(0) assert clique.contains(1) assert clique.contains(2) assert clique.contains(3) == 0
def test_sep_set_creation(): a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) d = BbnNode(Variable(3, 'd', ['on', 'off']), [0.9, 0.1, 0.5, 0.5]) abc = Clique([a, b, c]) bcd = Clique([b, c, d]) sepset = abc.get_sep_set(bcd) assert len(sepset.nodes) == 2 names = [node.variable.name for node in sepset.nodes] assert 'b' in names assert 'c' in names assert sepset.get_cost() == 16 assert sepset.get_mass() == 2
def test_toplogical_sort_reversed(): """ Tests topological sorting of graph with nodes in reverse order. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.5, 0.5]) bbn = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_edge(Edge(c, b, EdgeType.DIRECTED)) \ .add_edge(Edge(b, a, EdgeType.DIRECTED)) sampler = LogicSampler(bbn) assert_almost_equal([2, 1, 0], sampler.nodes)
def test_toplogical_sort_mixed(): """ Tests topological sort of diverging structure. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) bbn = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_edge(Edge(b, a, EdgeType.DIRECTED)) \ .add_edge(Edge(b, c, EdgeType.DIRECTED)) sampler = LogicSampler(bbn) assert_almost_equal([1, 0, 2], sampler.nodes)
def get_nodes(bn, domain_spaces=True): def get_parent_domains(name, bn): parents = bn.Vdata[name]['parents'] domains = [] if parents is None or len(parents) == 0: return domains for parent in parents: domain = bn.Vdata[parent]['vals'][:] domains.append(domain) return domains def cross_product(domains): products = [] if domains is None or len(domains) == 0: return products for e in itertools.product(*domains): products.append(e) return products def stringify_cross_product(pa_domains, domain_spaces=True): joiner_delim = ', ' if domain_spaces is True else ',' s = [] for pa_domain in pa_domains: r = joiner_delim.join( ["'{}'".format(v) for v in pa_domain]) r = '[{}]'.format(r) s.append(r) return s def get_cond_probs(name, bn, domain_spaces=True): probs = [] pa_domains = stringify_cross_product( cross_product(get_parent_domains(name, bn)), domain_spaces) if len(pa_domains) == 0: probs = bn.Vdata[name]['cprob'][:] else: for pa_domain in pa_domains: cprob = bn.Vdata[name]['cprob'][pa_domain] probs.extend(cprob) return probs nodes = {} idx = 0 for name in bn.V: domain = bn.Vdata[name]['vals'][:] probs = get_cond_probs(name, bn, domain_spaces) node = BbnNode(Variable(idx, name, domain), probs) nodes[name] = node idx += 1 return nodes
def test_reapply(): """ Tests reinitializing join tree after updating CPTs. :return: None. """ a = BbnNode(Variable(0, 'a', ['t', 'f']), [0.2, 0.8]) b = BbnNode(Variable(1, 'b', ['t', 'f']), [0.1, 0.9, 0.9, 0.1]) bbn = Bbn().add_node(a).add_node(b) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) lhs = InferenceController.apply(bbn) rhs = InferenceController.reapply(lhs, { 0: [0.3, 0.7], 1: [0.2, 0.8, 0.8, 0.2] }) lhs_pot = [lhs.get_bbn_potential(n) for n in lhs.get_bbn_nodes()] rhs_pot = [rhs.get_bbn_potential(n) for n in rhs.get_bbn_nodes()] lhs_d = Potential.to_dict(lhs_pot) rhs_d = Potential.to_dict(rhs_pot) # lhs should not match rhs after CPT update for k, prob in lhs_d.items(): assert k in rhs_d assert prob != rhs_d[k] # now create lhs with same params as param used to update old # should match with rhs since params are now the same a = BbnNode(Variable(0, 'a', ['t', 'f']), [0.3, 0.7]) b = BbnNode(Variable(1, 'b', ['t', 'f']), [0.2, 0.8, 0.8, 0.2]) bbn = Bbn().add_node(a).add_node(b) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) lhs = InferenceController.apply(bbn) lhs_pot = [lhs.get_bbn_potential(n) for n in lhs.get_bbn_nodes()] lhs_d = Potential.to_dict(lhs_pot) for k, prob in lhs_d.items(): assert k in rhs_d assert_almost_equals(prob, rhs_d[k], 0.001)
def test_table(): """ Tests creating table without parent. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) table = Table(a) assert not table.has_parents() assert_almost_equal(table.probs, np.array([0.5, 1.0])) assert 'on' == table.get_value(0.4) assert 'off' == table.get_value(0.6)
def get_simple(): """ Gets a simple BBN graph. :return: BBN. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) d = BbnNode(Variable(3, 'd', ['on', 'off']), [0.9, 0.1, 0.5, 0.5]) e = BbnNode(Variable(4, 'e', ['on', 'off']), [0.3, 0.7, 0.6, 0.4]) f = BbnNode(Variable(5, 'f', ['on', 'off']), [0.01, 0.99, 0.01, 0.99, 0.01, 0.99, 0.99, 0.01]) bbn = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_node(d) \ .add_node(e) \ .add_node(f) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) \ .add_edge(Edge(a, c, EdgeType.DIRECTED)) \ .add_edge(Edge(b, d, EdgeType.DIRECTED)) \ .add_edge(Edge(c, e, EdgeType.DIRECTED)) \ .add_edge(Edge(d, f, EdgeType.DIRECTED)) \ .add_edge(Edge(e, f, EdgeType.DIRECTED)) return bbn
def test_inference_1(): """ Tests inference on the Huang graph with manual construction. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) d = BbnNode(Variable(3, 'd', ['on', 'off']), [0.9, 0.1, 0.5, 0.5]) e = BbnNode(Variable(4, 'e', ['on', 'off']), [0.3, 0.7, 0.6, 0.4]) f = BbnNode(Variable(5, 'f', ['on', 'off']), [0.01, 0.99, 0.01, 0.99, 0.01, 0.99, 0.99, 0.01]) g = BbnNode(Variable(6, 'g', ['on', 'off']), [0.8, 0.2, 0.1, 0.9]) h = BbnNode(Variable(7, 'h', ['on', 'off']), [0.05, 0.95, 0.95, 0.05, 0.95, 0.05, 0.95, 0.05]) bbn = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_node(d) \ .add_node(e) \ .add_node(f) \ .add_node(g) \ .add_node(h) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) \ .add_edge(Edge(a, c, EdgeType.DIRECTED)) \ .add_edge(Edge(b, d, EdgeType.DIRECTED)) \ .add_edge(Edge(c, e, EdgeType.DIRECTED)) \ .add_edge(Edge(d, f, EdgeType.DIRECTED)) \ .add_edge(Edge(e, f, EdgeType.DIRECTED)) \ .add_edge(Edge(c, g, EdgeType.DIRECTED)) \ .add_edge(Edge(e, h, EdgeType.DIRECTED)) \ .add_edge(Edge(g, h, EdgeType.DIRECTED)) join_tree = InferenceController.apply(bbn) expected = { 'a': [0.5, 0.5], 'b': [0.45, 0.55], 'c': [0.45, 0.55], 'd': [0.680, 0.32], 'e': [0.465, 0.535], 'f': [0.176, 0.824], 'g': [0.415, 0.585], 'h': [0.823, 0.177] } __validate_posterior__(expected, join_tree)
def test_inference_libpgm2(): """ Tests libpgm graph where ordering messes up computation. :return: None. """ letter = BbnNode(Variable(4, 'Letter', ['weak', 'strong']), [0.1, 0.9, 0.4, 0.6, 0.99, 0.01]) grade = BbnNode( Variable(2, 'Grade', ['a', 'b', 'c']), [0.3, 0.4, 0.3, 0.9, 0.08, 0.02, 0.05, 0.25, 0.7, 0.5, 0.3, 0.2]) intelligence = BbnNode(Variable(3, 'Intelligence', ['low', 'high']), [0.7, 0.3]) sat = BbnNode(Variable(1, 'SAT', ['low', 'high']), [0.95, 0.05, 0.2, 0.8]) difficulty = BbnNode(Variable(0, 'Difficulty', ['easy', 'hard']), [0.6, 0.4]) bbn = Bbn() \ .add_node(letter) \ .add_node(grade) \ .add_node(intelligence) \ .add_node(sat) \ .add_node(difficulty) \ .add_edge(Edge(difficulty, grade, EdgeType.DIRECTED)) \ .add_edge(Edge(intelligence, grade, EdgeType.DIRECTED)) \ .add_edge(Edge(intelligence, sat, EdgeType.DIRECTED)) \ .add_edge(Edge(grade, letter, EdgeType.DIRECTED)) join_tree = InferenceController.apply(bbn) __validate_posterior__( { 'Difficulty': [0.6, 0.4], 'Intelligence': [0.7, 0.3], 'Grade': [0.362, 0.288, 0.350], 'SAT': [0.725, 0.275], 'Letter': [0.498, 0.502] }, join_tree, debug=False)
def test_simple_serde(): """ Tests join tree serde with only 1 clique. :return: None. """ a = BbnNode(Variable(0, 'a', ['t', 'f']), [0.2, 0.8]) b = BbnNode(Variable(1, 'b', ['t', 'f']), [0.1, 0.9, 0.9, 0.1]) bbn = Bbn().add_node(a).add_node(b) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) lhs = InferenceController.apply(bbn) d = JoinTree.to_dict(lhs) rhs = JoinTree.from_dict(d) rhs = InferenceController.apply_from_serde(rhs) lhs_pot = [lhs.get_bbn_potential(n) for n in lhs.get_bbn_nodes()] rhs_pot = [rhs.get_bbn_potential(n) for n in rhs.get_bbn_nodes()] lhs_pot = Potential.to_dict(lhs_pot) rhs_pot = Potential.to_dict(rhs_pot) assert len(lhs_pot) == len(rhs_pot)
def test_sampler_tables(): """ Tests sampler creation of tables. :return: None. """ a = BbnNode(Variable(0, 'a', ['on', 'off']), [0.5, 0.5]) b = BbnNode(Variable(1, 'b', ['on', 'off']), [0.5, 0.5, 0.4, 0.6]) c = BbnNode(Variable(2, 'c', ['on', 'off']), [0.7, 0.3, 0.2, 0.8]) bbn = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) \ .add_edge(Edge(b, c, EdgeType.DIRECTED)) sampler = LogicSampler(bbn) assert_almost_equal([0, 1, 2], sampler.nodes) tables = sampler.tables assert 3 == len(tables) assert 0 in tables assert 1 in tables assert 2 in tables lhs = np.array(tables[0].probs) rhs = np.array([0.5, 1.0]) assert_almost_equal(lhs, rhs) lhs = np.array(list(tables[1].probs.values())) rhs = np.array([[0.5, 1.0], [0.4, 1.0]]) assert_almost_equal(lhs, rhs) lhs = np.array(list(tables[2].probs.values())) rhs = np.array([[0.7, 1.0], [0.2, 1.0]]) assert_almost_equal(lhs, rhs)
def get_drug_network(): gender_probs = [0.49, 0.51] drug_probs = [ 0.23323615160349853, 0.7667638483965015, 0.7563025210084033, 0.24369747899159663 ] recovery_probs = [ 0.31000000000000005, 0.69, 0.27, 0.73, 0.13, 0.87, 0.06999999999999995, 0.93 ] X = BbnNode(Variable(1, 'drug', ['false', 'true']), drug_probs) Y = BbnNode(Variable(2, 'recovery', ['false', 'true']), recovery_probs) Z = BbnNode(Variable(0, 'gender', ['female', 'male']), gender_probs) bbn = Bbn() \ .add_node(X) \ .add_node(Y) \ .add_node(Z) \ .add_edge(Edge(Z, X, EdgeType.DIRECTED)) \ .add_edge(Edge(Z, Y, EdgeType.DIRECTED)) \ .add_edge(Edge(X, Y, EdgeType.DIRECTED)) return bbn
def test_github_issue_4(): """ Tests issue #4 https://github.com/vangj/py-bbn/issues/4 :return: None. """ a = BbnNode(Variable(0, 'A', ['T', 'F']), [0.5, 0.5]) b = BbnNode(Variable(1, 'B', ['T', 'F']), [0.2, 0.8, 0.1, 0.9]) c = BbnNode(Variable(2, 'C', ['T', 'F']), [0.5, 0.5, 0.5, 0.5]) d = BbnNode(Variable(3, 'D', ['T', 'F']), [0.5, 0.5, 0.5, 0.5]) e = BbnNode(Variable(4, 'E', ['T', 'F']), [0.5, 0.5, 0.5, 0.5]) f = BbnNode(Variable(5, 'F', ['T', 'F']), [0.5, 0.5, 0.5, 0.5]) g = BbnNode(Variable(6, 'G', ['T', 'F']), [ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ]) bbn = Bbn() \ .add_node(a) \ .add_node(b) \ .add_node(c) \ .add_node(d) \ .add_node(e) \ .add_node(f) \ .add_node(g) \ .add_edge(Edge(a, b, EdgeType.DIRECTED)) \ .add_edge(Edge(a, c, EdgeType.DIRECTED)) \ .add_edge(Edge(b, d, EdgeType.DIRECTED)) \ .add_edge(Edge(b, e, EdgeType.DIRECTED)) \ .add_edge(Edge(c, f, EdgeType.DIRECTED)) \ .add_edge(Edge(e, g, EdgeType.DIRECTED)) \ .add_edge(Edge(d, g, EdgeType.DIRECTED)) \ .add_edge(Edge(f, g, EdgeType.DIRECTED)) join_tree = InferenceController.apply(bbn) expected = { 'A': [0.5, 0.5], 'B': [0.15, 0.85], 'C': [0.5, 0.5], 'D': [0.5, 0.5], 'E': [0.5, 0.5], 'F': [0.5, 0.5], 'G': [0.5, 0.5] } __validate_posterior__(expected, join_tree) __print_potentials__(join_tree)
def from_csv(path): """ Converts the BBN in CSV format to a BBN. :param path: Path to CSV file. :return: BBN. """ with open(path, 'r') as f: nodes = {} edges = [] for line in f: tokens = line.split(',') if 3 == len(tokens): edge = int(tokens[0]), int(tokens[1]) edges.append(edge) else: tokens = line.split('|') v_part = [ item.strip() for item in tokens[0].split(',') if len(item.strip()) > 0 ] p_part = [ item.strip() for item in tokens[1].split(',') if len(item.strip()) > 0 ] i = int(v_part[0]) v = Variable(i, v_part[1], v_part[2:]) p = [float(p) for p in p_part] node = BbnNode(v, p) nodes[i] = node bbn = Bbn() for _, node in nodes.items(): bbn.add_node(node) for edge in edges: pa_id, ch_id = edge pa = nodes[pa_id] ch = nodes[ch_id] bbn.add_edge(Edge(pa, ch, EdgeType.DIRECTED)) return bbn
def test_bbn_node_deepcopy(): """ Tests BBN deep copy. :return: None. """ lhs = BbnNode(Variable(0, 'a', ['t', 'f']), [0.2, 0.8]) rhs = copy.deepcopy(lhs) assert lhs.variable.id == rhs.variable.id assert lhs.variable.name == rhs.variable.name assert len(lhs.variable.values) == len(rhs.variable.values) for lhs_v, rhs_v in zip(lhs.variable.values, rhs.variable.values): assert lhs_v == rhs_v assert len(lhs.probs) == len(rhs.probs) for lhs_v, rhs_v in zip(lhs.probs, rhs.probs): assert_almost_equals(lhs_v, rhs_v, 0.001) lhs.variable.values[0] = 'true' assert lhs.variable.values[0] != rhs.variable.values[0]