<< Click to Display Table of Contents >> Navigation: Tutorials > Tutorial 1: Creating a Bayesian Network |
Consider a slight twist on the problem described in the Hello SMILE! section of this manual.
The twist will include adding an additional variable State of the economy (with the identifier Economy) with three outcomes (Up, Flat, and Down) modeling the developments in the economy. These developments are relevant to the decision, as they are impacting expert forecast. When the economy is heading Up, our expert makes more optimistic predictions, when it is heading Down, the expert makes more pessimistic predictions for the same venture. This is reflected by a directed arc from the node State of the economy to the node Expert forecast. State of the economy also impacts the probability of venture being successful, which we model by adding another arc.
We will show how to create this model using SMILE and how to save it to disk. In subsequent tutorials, we will show how to enter observations (evidence), how to perform inference, and how to retrieve the results of SMILE’s calculations.
We start by redirecting error and warning messages to the console and declaring our network variable. The three nodes in the network are subsequently created by calling a helper function CreateCptNode declared beforehand and defined below the Tutorial1 function.
DSL_errorH().RedirectToFile(stdout);
DSL_network net;
int e = CreateCptNode(net, "Economy", "State of the economy",
{ "Up", "Flat", "Down" }, 160, 40);
int s = CreateCptNode(net, "Success", "Success of the venture",
{ "Success", "Failure" }, 60, 40);
int f = CreateCptNode(net, "Forecast", "Expert forecast",
{ "Good", "Moderate", "Poor" }, 110, 140);
Before connecting the nodes with arcs, let us have a look at the CreateCptNode function.
static int CreateCptNode(
DSL_network &net, const char *id, const char *name,
std::initializer_list<const char *> outcomes, int xPos, int yPos)
{
int handle = net.AddNode(DSL_CPT, id);
DSL_node *node = net.GetNode(handle);
node->SetName(name);
node->Def()->SetNumberOfOutcomes(outcomes);
DSL_rectangle &position = node->Info().Screen().position;
position.center_X = xPos;
position.center_Y = yPos;
position.width = 85;
position.height = 55;
return handle;
}
The function creates a CPT node with a specified identifier, name, outcomes, and position on the screen. The handle returned by DSL_network::AddNode is converted to a DSL_node* pointer with a call to DSL_network::GetNode. Next, we set the name of the node with DSL_node::SetName.
The default outcomes of the CPT nodes are named State0 and State1. To change the number of outcomes and their identifiers in one step, we call DSL_nodeDef::SetNumberOfOutcomes. To obtain a pointer to a node definition object, we use DSL_node::Def. The outcome identifiers are specified in the std::initializer_list passed as outcomes parameter to CreateCptNode.
Finally, we set the location and size of the node by direcly writing to the DSL_rectangle object in node's screen info block.
Back in the Tutorial1 function, we add arcs between nodes.
net.AddArc(e, s);
net.AddArc(s, f);
net.AddArc(e, f);
Next step is to initialize the conditional probability tables of the nodes. See the Multidimensional arrays section in this manual for the description of the CPT memory layout. For each of the three nodes in our network, we obtain a pointer to the node definition object. To change the numbers (probabilities) in the CPT, we will call DSL_nodeDef::SetDefinition method and pass a std::initializer_list<double> with the probabilities. We show the code snippet for the Success node below, two other nodes are initialized in the same way.
res = net.GetNode(s)->Def()->SetDefinition({
0.3, // P(Success=S|Economy=U)
0.7, // P(Success=F|Economy=U)
0.2, // P(Success=S|Economy=F)
0.8, // P(Success=F|Economy=F)
0.1, // P(Success=S|Economy=D)
0.9 // P(Success=F|Economy=D)
});
With CPTs initialized, our network is complete. We write its contents to the tutorial1.xdsl file.
res = net.WriteFile("tutorial1.xdsl");
Tutorial 2 will load this file and perform inference. The split between tutorials is artificial, your program can use networks right after its creation without the need to write/read to/from the file system.