def make_final_net():
    A = BayesNode(0, 2, name='A')
    B = BayesNode(1, 2, name='B')
    C = BayesNode(2, 2, name='C')
    D = BayesNode(3, 2, name='D')
    E = BayesNode(4, 2, name='E')

    A.add_child(C)
    C.add_parent(A)
    B.add_child(C)
    C.add_parent(B)
    B.add_child(D)
    D.add_parent(B)
    C.add_child(E)
    E.add_parent(C)
    D.add_child(E)
    E.add_parent(D)

    nodes = [A, B, C, D, E]
    net = BayesNet(nodes)

    A = net.get_node_by_name('A')
    B = net.get_node_by_name('B')
    C = net.get_node_by_name('C')
    D = net.get_node_by_name('D')
    E = net.get_node_by_name('E')

    A_distribution = DiscreteDistribution(A)
    index = A_distribution.generate_index([], [])
    A_distribution[index] = [0.4, 0.6]
    A.set_dist(A_distribution)

    B_distribution = DiscreteDistribution(B)
    index = B_distribution.generate_index([], [])
    B_distribution[index] = [0.8, 0.2]
    B.set_dist(B_distribution)

    print B, D
    dist = zeros([B.size(), D.size()], dtype=float32)
    dist[0, :] = [0.87, 0.13]
    dist[1, :] = [0.24, 0.76]
    D_distribution = ConditionalDiscreteDistribution(nodes=[B, D], table=dist)
    D.set_dist(D_distribution)

    dist = zeros([A.size(), B.size(), C.size()], dtype=float32)
    dist[0, 0, :] = [0.85, 0.15]
    dist[0, 1, :] = [0.68, 0.32]
    dist[1, 0, :] = [0.16, 0.84]
    dist[1, 1, :] = [0.05, 0.95]
    C_distribution = ConditionalDiscreteDistribution(nodes=[A, B, C],
                                                     table=dist)
    C.set_dist(C_distribution)

    dist = zeros([C.size(), D.size(), E.size()], dtype=float32)
    dist[0, 0, :] = [0.8, 0.2]
    dist[0, 1, :] = [0.37, 0.63]
    dist[1, 0, :] = [0.08, 0.92]
    dist[1, 1, :] = [0.07, 0.93]
    E_distribution = ConditionalDiscreteDistribution(nodes=[C, D, E],
                                                     table=dist)
    E.set_dist(E_distribution)

    engine = EnumerationEngine(net)
    #    engine1.evidence[wear] = False
    #    engine1.evidence[weap] = True
    engine.evidence[A] = True
    engine.evidence[C] = True
    Q = engine.marginal(E)[0]
    index = Q.generate_index([True], range(Q.nDims))
    prob = Q[index]
    print prob
def make_exam_net():
    H = BayesNode(0, 2, name='H')
    G = BayesNode(1, 2, name='G')
    B = BayesNode(2, 2, name='B')
    O = BayesNode(3, 2, name='O')
    D = BayesNode(4, 2, name='D')
    C = BayesNode(5, 2, name='C')

    H.add_child(B)
    B.add_parent(H)
    B.add_parent(G)
    G.add_child(B)
    G.add_child(O)
    O.add_parent(G)
    O.add_child(D)
    O.add_child(C)
    D.add_parent(O)
    C.add_parent(O)
    B.add_child(D)
    D.add_parent(B)

    nodes = [B, C, D, G, H, O]
    net = BayesNet(nodes)

    sci = BayesNode(0, 2, name='sci')
    inf = BayesNode(1, 2, name='inf')
    weap = BayesNode(2, 2, name='weap')
    car = BayesNode(3, 2, name='car')
    wear = BayesNode(4, 2, name='wear')

    sci.add_child(weap)
    weap.add_parent(sci)
    inf.add_child(weap)
    weap.add_parent(inf)
    weap.add_child(car)
    car.add_parent(weap)
    weap.add_child(wear)
    wear.add_parent(weap)

    nodes1 = [sci, weap, wear, inf, car]
    net1 = BayesNet(nodes1)

    B = net.get_node_by_name('B')
    C = net.get_node_by_name('C')
    D = net.get_node_by_name('D')
    G = net.get_node_by_name('G')
    H = net.get_node_by_name('H')
    O = net.get_node_by_name('O')

    H_distribution = DiscreteDistribution(H)
    index = H_distribution.generate_index([], [])
    H_distribution[index] = [0.6, 0.4]
    H.set_dist(H_distribution)

    G_distribution = DiscreteDistribution(G)
    index = G_distribution.generate_index([], [])
    G_distribution[index] = [0.75, 0.25]
    G.set_dist(G_distribution)

    dist = zeros([O.size(), C.size()], dtype=float32)
    dist[0, :] = [0.55, 0.45]
    dist[1, :] = [0.75, 0.25]
    C_distribution = ConditionalDiscreteDistribution(nodes=[O, C], table=dist)
    C.set_dist(C_distribution)

    dist = zeros([G.size(), O.size()], dtype=float32)
    dist[0, :] = [0.55, 0.45]
    dist[1, :] = [0.45, 0.55]
    O_distribution = ConditionalDiscreteDistribution(nodes=[G, O], table=dist)
    O.set_dist(O_distribution)

    dist = zeros([B.size(), O.size(), D.size()], dtype=float32)
    dist[0, 0, :] = [0.72, 0.28]
    dist[0, 1, :] = [0.38, 0.62]
    dist[1, 0, :] = [0.85, 0.15]
    dist[1, 1, :] = [0.65, 0.35]
    D_distribution = ConditionalDiscreteDistribution(nodes=[B, O, D],
                                                     table=dist)
    D.set_dist(D_distribution)

    dist = zeros([H.size(), G.size(), B.size()], dtype=float32)
    dist[0, 0, :] = [0.92, 0.08]
    dist[0, 1, :] = [0.75, 0.25]
    dist[1, 0, :] = [0.55, 0.45]
    dist[1, 1, :] = [0.35, 0.65]
    B_distribution = ConditionalDiscreteDistribution(nodes=[H, G, B],
                                                     table=dist)
    B.set_dist(B_distribution)

    sci = net1.get_node_by_name('sci')
    weap = net1.get_node_by_name('weap')
    wear = net1.get_node_by_name('wear')
    inf = net1.get_node_by_name('inf')
    car = net1.get_node_by_name('car')

    sci_distribution = DiscreteDistribution(sci)
    index = sci_distribution.generate_index([], [])
    sci_distribution[index] = [0.2, 0.8]
    sci.set_dist(sci_distribution)

    inf_distribution = DiscreteDistribution(inf)
    index = inf_distribution.generate_index([], [])
    inf_distribution[index] = [0.4, 0.6]
    inf.set_dist(inf_distribution)

    dist = zeros([sci.size(), inf.size(), weap.size()], dtype=float32)
    dist[0, 0, :] = [0.6, 0.4]
    dist[0, 1, :] = [0.8, 0.2]
    dist[1, 0, :] = [0.1, 0.9]
    dist[1, 1, :] = [0.3, 0.7]
    weap_distribution = ConditionalDiscreteDistribution(nodes=[sci, inf, weap],
                                                        table=dist)
    weap.set_dist(weap_distribution)

    dist = zeros([weap.size(), wear.size()], dtype=float32)
    dist[0, :] = [0.88, 0.12]
    dist[1, :] = [0.15, 0.85]
    wear_distribution = ConditionalDiscreteDistribution(nodes=[weap, wear],
                                                        table=dist)
    wear.set_dist(wear_distribution)

    dist = zeros([weap.size(), car.size()], dtype=float32)
    dist[0, :] = [0.75, 0.25]
    dist[1, :] = [0.55, 0.45]
    car_distribution = ConditionalDiscreteDistribution(nodes=[weap, car],
                                                       table=dist)
    car.set_dist(car_distribution)

    ##    engine = JunctionTreeEngine(net)
    #    engine = EnumerationEngine(net)
    ##    engine.evidence[B] = True
    #    Q = engine.marginal(C)[0]
    #    index = Q.generate_index([True], range(Q.nDims))
    #    prob = Q[index]
    #    print "Thr ptob of O = T given B = T is  ", prob

    engine1 = EnumerationEngine(net1)
    engine1.evidence[wear] = False
    engine1.evidence[weap] = True
    #   engine1.evidence[sci] = False
    Q = engine1.marginal(car)[0]
    index = Q.generate_index([True], range(Q.nDims))
    prob = Q[index]
    print prob