Examples¶
The following examples show how the HUGIN Python API can be used to manipulate belief networks and LIMIDs.
Running the examples
To run the examples, the python interpreter must be able to load the HUGIN Python API module. Depending on where the HUGIN python module is placed one of the following command lines should work (i.e. for the build and propagate example):
bap.py
python bap.py
PYTHONPATH=<PATH-TO-PYHUGIN-DIR> python bap.py
set PYTHONPATH=<PATH-TO-PYHUGIN-DIR>
python bap.py
Example: Build And Propagate¶
This example describes how a belief network can be constructed using the HUGIN Python API. The network consists of three numbered nodes. Two of the nodes take on values 0, 1, and 2. The third node is the sum of the two other nodes. Once the Bayesian network is constructed, the network is saved as a NET specification file, and an initial propagation is performed. Finally, the marginals of the nodes are printed on standard output.
1#!/usr/bin/python
2
3"""Example: Build And Propagate
4
5This example describes how a Bayesian network can be constructed using
6the HUGIN Python API. The Bayesian network constructed consists of
7three numbered nodes. Two of the nodes take on values 0, 1, and 2. The
8third node is the sum of the two other nodes. Once the Bayesian
9network is constructed, the network is saved to a NET specification
10file and an initial propagation is performed. Finally, the marginals
11of the nodes are printed on standard output.
12
13
14Example:
15 bap.py
16 - or -
17 python bap.py
18 - or (on unix) -
19 PYTHONPATH=<PATH-TO-PYHUGIN-DIR> python bap.py
20 - or (on windows) -
21 set PYTHONPATH=<PATH-TO-PYHUGIN-DIR>
22 python bap.py
23
24
25"""
26
27
28import sys
29from pyhugin98 import *
30
31
32
33def bap():
34 """Build a Bayesian network and propagate evidence."""
35 domain = None
36 try:
37 # create domain
38 domain = Domain()
39
40 # create nodes
41 nodeA = Node(domain, CATEGORY.CHANCE, KIND.DISCRETE, SUBTYPE.NUMBER)
42 nodeA.set_name("A")
43 nodeA.set_label("A1234567890123")
44 nodeA.set_number_of_states(3)
45 for i in range(3):
46 nodeA.set_state_value(i, i)
47
48 nodeB = Node(domain, CATEGORY.CHANCE, KIND.DISCRETE, SUBTYPE.NUMBER)
49 nodeB.set_name("B")
50 nodeB.set_label("B")
51 nodeB.set_number_of_states(3)
52 for i in range(3):
53 nodeB.set_state_value(i, i)
54
55 nodeC = Node(domain, CATEGORY.CHANCE, KIND.DISCRETE, SUBTYPE.NUMBER)
56 nodeC.set_name("C")
57 nodeC.set_label("C")
58 nodeC.set_number_of_states(5)
59 for i in range(5):
60 nodeC.set_state_value(i, i)
61
62 # build structure
63 nodeC.add_parent(nodeA)
64 nodeC.add_parent(nodeB)
65
66 # build expression for C
67 modelC = Model(nodeC)
68 modelC.set_expression(0, "A + B")
69
70 # tables
71 tableA = nodeA.get_table()
72 tableA.set_data([0.1, 0.2, 0.7])
73
74 tableB = nodeB.get_table()
75 tableB.set_data([0.2, 0.2, 0.6])
76
77 # save as net-file
78 domain.save_as_net("builddomain.net")
79
80 # compile
81 domain.compile()
82
83 # print node marginals
84 for node in domain.get_nodes():
85 print(node.get_label())
86 for i in range(node.get_number_of_states()):
87 print("-{} {}".format(node.get_state_label(i), node.get_belief(i)))
88 except HuginException:
89 print("A Hugin Exception was raised!")
90 raise
91 finally:
92 if domain is not None:
93 domain.delete()
94
95
96
97# Run the Build And Propagate example
98if __name__ == "__main__":
99 bap()
Example: Load And Propagate¶
This example shows how to load a belief network or a LIMID specified as a (non-OOBN) NET file: A Domain object is constructed from the NET file. The domain is then triangulated using the “best greedy” heuristic, and the compilation process is completed. The (prior) beliefs and expected utilities (if the network is a LIMID) are then printed. If a case file is given, the file is loaded, the evidence is propagated, and the updated results are printed.
1#!/usr/bin/python
2
3"""Example: Load And Propagate
4
5This example shows how to load a belief network or a LIMID specified
6as a (non-OOBN) NET file: A Domain object is constructed from the NET
7file. The domain is then triangulated using the "best greedy"
8heuristic, and the compilation process is completed. The (prior)
9beliefs and expected utilities (if the network is a LIMID) are then
10printed. If a case file is given, the file is loaded, the evidence is
11propagated, and the updated results are printed.
12
13
14Example:
15 lap.py ChestClinic ChestClinic.hcs
16 - or -
17 python lap.py ChestClinic ChestClinic.hcs
18 - or (on unix) -
19 PYTHONPATH=<PATH-TO-PYHUGIN-DIR> python lap.py ChestClinic ChestClinic.hcs
20 - or (on windows) -
21 set PYTHONPATH=<PATH-TO-PYHUGIN-DIR>
22 python lap.py ChestClinic ChestClinic.hcs
23
24"""
25
26
27import sys
28from pyhugin98 import *
29
30
31def lap(net_name, case_name = None):
32 """This function parses the given NET file, compiles the network, and
33 prints the prior beliefs and expected utilities of all nodes. If a
34 case file is given, the function loads the file, propagates the
35 evidence, and prints the updated results.
36
37 If the network is a LIMID, we assume that we should compute policies
38 for all decisions (rather than use the ones specified in the NET
39 file). Likewise, we update the policies when new evidence arrives.
40 """
41 domain = None
42 try:
43 domain = Domain.parse_domain("{}.net".format(net_name), parse_listener)
44 domain.open_log_file("{}.log".format(net_name))
45 domain.triangulate()
46 domain.compile()
47 domain.close_log_file()
48 has_utilities = any(node.get_category() == CATEGORY.UTILITY for node in domain.get_nodes())
49 if not has_utilities:
50 print("Prior beliefs:")
51 else:
52 domain.update_policies()
53 print("Overall expected utility: {}".format(domain.get_expected_utility()))
54 print("Prior beliefs (and expected utilities):")
55 print_beliefs_and_utilities(domain)
56 if case_name:
57 domain.parse_case(case_name)
58 print("Propagating the evidence specified in '{}'".format(case_name))
59 domain.propagate()
60 print("P(evidence) = {}".format(domain.get_normalization_constant()))
61 if has_utilities:
62 print("Updated beliefs:")
63 else:
64 domain.update_policies()
65 print("Overall expected utility: {}".format(domain.get_expected_utility()))
66 print("Updated beliefs (and expected utilities):")
67 print_beliefs_and_utilities(domain)
68 except HuginException:
69 print("A Hugin Exception was raised!")
70 raise
71 finally:
72 if domain is not None:
73 domain.delete()
74
75
76def print_beliefs_and_utilities(domain):
77 """Print the beliefs and expected utilities of all nodes in the domain."""
78 nodes = domain.get_nodes()
79 has_utilities = any(node.get_category() == CATEGORY.UTILITY for node in domain.get_nodes())
80
81 for node in nodes:
82 if node.get_category() == CATEGORY.UTILITY:
83 print("{} ({}) - Expected utility: {}".format(node.get_label(), node.get_name(), node.get_expected_utility()))
84 elif node.get_category() == CATEGORY.FUNCTION and node.get_kind() == KIND.OTHER:
85 try:
86 print("{} ({}) - Value: {}".format(node.get_label(), node.get_name(), node.get_value()))
87 except HuginException:
88 print("{} ({}) - Value: N/A".format(node.get_label(), node.get_name()))
89 elif node.get_kind() == KIND.DISCRETE:
90 print("{} ({})".format(node.get_label(), node.get_name()))
91 for i in range(node.get_number_of_states()):
92 if has_utilities:
93 print(" - {} {} ({})".format(node.get_state_label(i), node.get_belief(i), node.get_expected_utility(i)))
94 else:
95 print(" - {} {}".format(node.get_state_label(i), node.get_belief(i)))
96 elif node.get_kind() == KIND.CONTINUOUS:
97 print("{} ({})".format(node.get_label(), node.get_name()))
98 print(" - Mean: {}".format(node.get_mean()))
99 print(" - SD : {}".format(node.get_variance()))
100
101
102def parse_listener(line, description):
103 """A parse listener that prints the line number and error description."""
104 print("Parse error line {}: {}".format(line, description))
105
106
107# Run the Load And Propagate example
108if __name__ == "__main__":
109 if len(sys.argv) == 2:
110 lap(sys.argv[1])
111 elif len(sys.argv) == 3:
112 lap(sys.argv[1], sys.argv[2])
113 else:
114 print("Usage: {} <netName> [<caseName>]".format(sys.argv[0]))
115 sys.exit(1)
116