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