Tutorial 2: Inference with a Bayesian Network

<< Click to Display Table of Contents >>

Navigation:  Tutorials >

Tutorial 2: Inference with a Bayesian Network

Tutorial 2 starts with the model that we have previously created. We will perform multiple calls to a Bayesian inference algorithm through the DSL_network::UpdateBeliefs, starting with network without any evidence. After each UpdateBeliefs call, we retrieve and print the posterior probabilities of all outcomes of the nodes.

The Tutorial2 function itself is very simple and delegates work to helper functions declared at the top of the file and defined below Tutorial2.

The model is loaded with the DSL_network::ReadFile. We exit the program if the status code ReadFile returned is not DSL_OKAY.

DSL_network net;

int res = net.ReadFile("tutorial1.xdsl");

if (DSL_OKAY != res)

{

   printf("Load failed, did you run Tutorial1 before Tutorial2?\n");

   return res;

}

UpdateBeliefs is followed by the call to PrintAllPosteriors helper.

printf("Posteriors with no evidence set:\n");

net.UpdateBeliefs();

PrintAllPosteriors(net);

PrintAllPosteriors() displays posterior probabilities calculated by UpdateBeliefs() and stored in node values. To iterate over all nodes, we use DSL_network::GetFirstNode and GetNextNode. In the body of the loop, we call another locally defined helper function, PrintPosteriors().

for (int h = net.GetFirstNode(); h >= 0; h = net.GetNextNode(h))

{

   PrintPosteriors(net, h);

}

PrintPosteriors() converts node handle to node pointer. Then it checks if the node has evidence set with DSL_nodeVal::IsEvidence; if this is the case, the name of the evidence state is displayed. Otherwise, the function iterates over all states and displays the posterior probability of each state. We retrieve the state identifiers with DSL_nodeDef::GetOutcomeIds. The posterior probabilities are stored in a DSL_Dmatrix object, which has just one dimension in this case. The size of the dimension is equal to the number of states. DSL_nodeVal::GetMatrix. returns a pointer to the matrix.

static void PrintPosteriors(DSL_network &net, int handle)

{

    DSL_node *node = net.GetNode(handle);

    const char* nodeId = node->GetId();

    const DSL_nodeVal* val = node->Val();

    if (val->IsEvidence())

    {

        printf("%s has evidence set (%s)\n", 

            nodeId, val->GetEvidenceId());

    }

    else

    {

        const DSL_idArray& outcomeIds = *node->Def()->GetOutcomeIds();

        const DSL_Dmatrix& posteriors = *val->GetMatrix();

        for (int i = 0; i < posteriors.GetSize(); i++)

        {

            printf("P(%s=%s)=%g\n", nodeId, outcomeIds[i], posteriors[i]);

        }

    }

}

Going back to Tutorial2 function, we repeatedly call another locally defined helper function to change evidence, update network, and display posteriors:

printf("\nSetting Forecast=Good.\n");

ChangeEvidenceAndUpdate(net, "Forecast", "Good");

printf("\nAdding Economy=Up.\n");

ChangeEvidenceAndUpdate(net, "Economy", "Up");

printf("\nChanging Forecast to Poor, keeping Economy=Up.\n");

ChangeEvidenceAndUpdate(net, "Forecast", "Poor");

printf("\nRemoving evidence from Economy, keeping Forecast=Poor.\n");

ChangeEvidenceAndUpdate(net, "Economy", NULL);

Let us examine the ChangeEvidenceAndUpdate helper. The function is just a series of calls to various SMILE methods. The node identifier passed as the 2nd argument is validated and converted to DSL_node pointer. If the 3rd argument is NULL, the evidence is cleared with DSL_nodeVal::ClearEvidence. Otherwise, new evidence is set with DSL_nodeVal::SetEvidence, which has an overload accepting the outcome id directly. Finally, DSL_network::UpdateBeliefs performs inference and the posteriors are displayed by our PrintAllPosteriors function.

static int ChangeEvidenceAndUpdate(

    DSL_network &net, const char *nodeId, const char *outcomeId)

{

    DSL_node* node = net.GetNode(nodeId);

    if (NULL == node)

    {

        return DSL_OUT_OF_RANGE;

    }

    int res;

    if (NULL != outcomeId)

    {

        res = node->Val()->SetEvidence(outcomeId);

    }

    else

    {

        res = node->Val()->ClearEvidence();

    }

    if (DSL_OKAY != res)

    {

        return res;

    }

    res = net.UpdateBeliefs();

    if (DSL_OKAY != res)

    {

        return res;

    }

    PrintAllPosteriors(net);

    return DSL_OKAY;

}

Tutorial 2 ends here.