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