Tutorial 6: Dynamic model

<< Click to Display Table of Contents >>

Navigation:  Tutorials >

Tutorial 6: Dynamic model

Consider the following example, inspired by (Russell & Norvig, 1995), in which a security guard at some secret underground installation works on a shift of seven days and wants to know whether it is raining on the day of her return to the outside world. Her only access to the outside world occurs each morning when she sees the director coming in, with or without an umbrella. Furthermore, she knows that the government has two secret underground installations: one in Pittsburgh and one in the Sahara, but she does not know which one she is guarding. For each day t, the set of evidence contains a single variable Umbrellat (observation of an umbrella carried by the director) and the set of unobservable variables contains Raint (a propositional variable with two states true and false, denoting whether it is raining) and Location (with two possible states: Pittsburgh and Sahara). The prior probability of rain depends on the geographical location and on whether it rained on the previous day. For simplicity, we do not use the initial and terminal condition nodes in this tutorial.

dbn

The model contains three discrete chance nodes (CPT), created with a call to createCptNode helper function, just like in nodes in Tutorial 1. The Rain and Umbrella nodes are marked as belonging to the temporal plate by calling Network.SetNodeTemporalType:

Java:

net.setNodeTemporalType(rain, Network.NodeTemporalType.PLATE);

net.setNodeTemporalType(umb, Network.NodeTemporalType.PLATE);

Python:

net.set_node_temporal_type(rain, pysmile.NodeTemporalType.PLATE)

net.set_node_temporal_type(umb, pysmile.NodeTemporalType.PLATE)

C#:

net.SetNodeTemporalType(rain, Network.NodeTemporalType.Plate);

net.SetNodeTemporalType(umb, Network.NodeTemporalType.Plate);

Two of the three arcs in the model are created by Network.addArc. The temporal arc expressing the dependency of Raint on Raint-1 is created by the Network.addTemporalArc method. Please note the temporal order of the arc passed as the 3rd parameter:

Java:

net.addArc(loc, rain);

net.addTemporalArc(rain, rain, 1);

net.addArc(rain, umb);

Python:

net.add_arc(loc, rain)

net.add_temporal_arc(rain, rain, 1)

net.add_arc(rain, umb)

C#:

net.AddArc(loc, rain);

net.AddTemporalArc(rain, rain, 1);

net.AddArc(rain, umb);

CPTs for the nodes are initialized with Network.setNodeDefinition, as in Tutorial 1. However, the node Rain requires two CPTs, because it has an incoming temporal arc of order 1. The additional CPT is set by the call to Network.setNodeTemporalDefinition:

Java:

double[] rainDefTemporal = new double[] {

 0.7,   // P(Rain=true |Location=Pittsburgh,Rain[t-1]=true)

 0.3,   // P(Rain=false|Location=Pittsburgh,Rain[t-1]=true)

 0.3,   // P(Rain=true |Location=Pittsburgh,Rain[t-1]=false)

 0.7,   // P(Rain=false|Location=Pittsburgh,Rain[t-1]=false)

 0.001, // P(Rain=true |Location=Sahara,Rain[t-1]=true)

 0.999, // P(Rain=false|Location=Sahara,Rain[t-1]=true)

 0.01,  // P(Rain=true |Location=Sahara,Rain[t-1]=false)

 0.99  // P(Rain=false|Location=Sahara,Rain[t-1]=false)

};

net.setNodeTemporalDefinition(rain, 1, rainDefTemporal);

Python:

rain_def_temporal = [

 # probabilities go here

]

net.set_node_temporal_definition(rain, 1, rain_def_temporal)

C#:

double[] rainDefTemporal = new double[] 

{

 // probabilities go here

};

net.SetNodeTemporalDefinition(rain, 1, rainDefTemporal);

Finally, we adjust the number of slices created during the network unrolling with a call to Network.setSliceCount. The network is complete. The program proceeds to the inference, first without any evidence in the network, then with two observations of the Umbrella, set in the time steps t=1 and t=3:

Java:

net.setTemporalEvidence(umb, 1, 0);

net.setTemporalEvidence(umb, 3, 1);

Python:

net.set_temporal_evidence(umb, 1, 0)

net.set_temporal_evidence(umb, 3, 1

C#:

net.SetTemporalEvidence(umb, 1, 0);

net.SetTemporalEvidence(umb, 3, 1);

In dynamic Bayesian networks, the plate nodes have their beliefs calculated for each time slice. The number of elements in the node value matrix for these nodes is a product of outcome count and slice count. The helper function updateAndShowTemporalResults iterates over this matrix using two nested loops in order to print the results. Since the probabilities for the same slice are adjacent, the inner loop uses the product of the outcome count and slice index from the outer loop as a base index.

Java:

double[] v = net.getNodeValue(h);

for (int sliceIdx = 0; sliceIdx < sliceCount; sliceIdx++) {

 System.out.printf("\tt=%d:", sliceIdx);

 for (int i = 0; i < outcomeCount; i++) {

         System.out.printf(" %f", v[sliceIdx * outcomeCount + i]);

 }

 System.out.println();

}

Python:

v = net.get_node_value(h)

for slice_idx in range(0, slice_count):

    s = "\tt=" + str(slice_idx) + ":"

    for i in range(0, outcome_count):

        s = s + " " + str(v[slice_idx * outcome_count + i])

    print(s)

C#:

double[] v = net.GetNodeValue(h);

for (int sliceIdx = 0; sliceIdx < sliceCount; sliceIdx++)

{

 Console.Write("\tt={0}:", sliceIdx);

    for (int i = 0; i < outcomeCount; i++)

    {

                    Console.Write(" {0}", v[sliceIdx * outcomeCount + i]);

    }

    Console.WriteLine();

}