<< Click to Display Table of Contents >> Navigation: Tutorials > Tutorial 3: Exploring the contents of a model |
This tutorial will not perform any calculations. Instead, we will display the information about the network structure (nodes and arcs) and parameters (in this case, conditional probability tables). The Tutorial3 function itself is again very simple. We load the network created by Tutorial1 and for each node invoke a locally defined helper function PrintNodeInfo(). This is where real work is done. The first node attribute displayed is its name, followed by the outcome identifiers:
DSL_node *node = net.GetNode(nodeHandle);
printf("Node: %s\n", node->GetName());
printf(" Outcomes:");
const DSL_idArray &outcomes = *node->Def()->GetOutcomeIds();
for (const char* oid : outcomes)
{
printf(" %s", oid);
}
printf("\n");
The parents of the node follow.
const DSL_intArray &parents = net.GetParents(nodeHandle);
if (!parents.IsEmpty())
{
printf(" Parents:");
for (int p: parents)
{
printf(" %s", net.GetNode(p)->GetId());
}
printf("\n");
}
Node’s children are next. The code fragment is virtually identical to the iteration over parents above.
Finally, the node definition is checked. If its type is DSL_CPT (general chance node) or DSL_TRUTHTABLE (deterministic discrete node), we retrieve the probabilities from the node’s definition with the DSL_nodeDef::GetMatrix. Note that all the nodes in the network created in Tutorial 1 are DSL_CPT. The if statement is there to keep the function general enough to be copied and pasted into other program using SMILE.
const DSL_nodeDef *def = node->Def();
int defType = def->GetType();
printf(" Definition type: %s\n", def->GetTypeName());
if (DSL_CPT == defType || DSL_TRUTHTABLE == defType)
{
const DSL_Dmatrix &cpt = *def->GetMatrix();
PrintMatrix(net, cpt, outcomes, parents);
}
PrintMatrix is another locally defined helper function. It iterates over all entries in the CPT. For each entry, the outcome of the node and its parents’ outcomes are displayed along with the probability value. Let us inspect the main loop of the function:
for (int elemIdx = 0; elemIdx < mtx.GetSize(); elemIdx++)
{
const char *outcome = outcomes[coords[dimCount - 1]];
printf(" P(%s", outcome);
if (dimCount > 1)
{
printf(" | ");
for (int parentIdx = 0; parentIdx < dimCount - 1; parentIdx++)
{
if (parentIdx > 0) printf(",");
DSL_node *parentNode = net.GetNode(parents[parentIdx]);
const DSL_idArray &parentOutcomes =
*parentNode->Def()->GetOutcomeIds();
printf("%s=%s",
parentNode->GetId(), parentOutcomes[coords[parentIdx]]);
}
}
double prob = mtx[elemIdx];
printf(")=%g\n", prob);
mtx.NextCoordinates(coords);
}
The loop uses both linear index (elemIdx variable) and multidimensional coordinates (coords variable of DSL_intArray type, initialized to zeros before the loop). Both are kept in sync, the equivalent of increasing linear index by one (elemIdx++) is a call to DSL_Dmatrix::NextCoordinates (mtx.NextCoordinates(coords)). Note that we could use elemIdx to convert into coordinates during each iteration with IndexToCoordinates. Conversely, it is also possible to convert coords into linear index with DSL_Dmatrix::CoordinatesToIndex. While it is not important for this tutorial, the coordinate-based loop performance over large CPTs is computationally more efficient when NextCoordinates approach is used (NextCoordinates , on the other hand, is more efficient than IndexToCoordinates). Of course, the iteration with plain linear index only will be fastest.
The node outcome is the rightmost entry in the coordinates. The parents’ outcome indices start from the left at index 0 in the coords. Part of the Tutorial3 output for the node Forecast is show below. All lines starting with “P”( were printed by PrintMatrix.
Node: Expert forecast
Outcomes: Good Moderate Poor
Parents: Success Economy
Definition type: CPT
P(Good | Success=Success,Economy=Up)=0.7
P(Moderate | Success=Success,Economy=Up)=0.29
P(Poor | Success=Success,Economy=Up)=0.01
P(Good | Success=Success,Economy=Flat)=0.65
P(Moderate | Success=Success,Economy=Flat)=0.3
P(Poor | Success=Success,Economy=Flat)=0.05
P(Good | Success=Success,Economy=Down)=0.6
P(Moderate | Success=Success,Economy=Down)=0.3
P(Poor | Success=Success,Economy=Down)=0.1
P(Good | Success=Failure,Economy=Up)=0.15
P(Moderate | Success=Failure,Economy=Up)=0.3
P(Poor | Success=Failure,Economy=Up)=0.55
P(Good | Success=Failure,Economy=Flat)=0.1
P(Moderate | Success=Failure,Economy=Flat)=0.3
P(Poor | Success=Failure,Economy=Flat)=0.6
P(Good | Success=Failure,Economy=Down)=0.05
P(Moderate | Success=Failure,Economy=Down)=0.25
P(Poor | Success=Failure,Economy=Down)=0.7
Tutorial 3 ends here.