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)