Represents a Bayesian Network, or a Dynamic Bayesian Network. To perform inference with a network see the BayesServer.Inference namespace.
Namespace:
BayesServerAssembly: BayesServer (in BayesServer.dll)
Version: 2.2.0.0 (2.2.0.0)
Syntax
| C# |
|---|
public sealed class Network |
| Visual Basic (Declaration) |
|---|
Public NotInheritable Class Network |
| Visual C++ |
|---|
public ref class Network sealed |
Remarks
A Bayesian network consists of nodes which contain one or more variables. Each node can be connected with a directed link
(A link in a Dynamic Bayesian Network can have an associated order which links nodes in different time slices).
Each node in a Bayesian network must have a distribution specified over its own variables conditional on its parents variables. For example if a network contains nodes A and B each with a single variable of the same name, and A is a parent of B, then the distribution at A equals P(A), since A has no parents, and the distribution at B equals P(B|A).
Once the nodes, links, and distributions in a Bayesian network have been specified, one or more inference engines can be created based on the network, to perform probabilistic inference. See IInference.
Examples
using System; using BayesServer; using System.IO; using BayesServer.Inference; using BayesServer.Inference.VariableElimination; namespace BayesServer.HelpSamples { public static class NetworkExample { public static void Main() { // create a simple Bayesian network Network network = new Network("Demo"); string[] defaultStates = new string[]{"True", "False"}; // add the nodes (variables) Node a = new Node("A", defaultStates); Node b = new Node("B", defaultStates); Node c = new Node("C", defaultStates); Node d = new Node("D", defaultStates); network.Nodes.Add(a); network.Nodes.Add(b); network.Nodes.Add(c); network.Nodes.Add(d); // add some directed links network.Links.Add(new Link(a, b)); network.Links.Add(new Link(a, c)); network.Links.Add(new Link(b, d)); network.Links.Add(new Link(c, d)); // at this point we have fully specified the structural (graphical) specification of the Bayesian Network. // next we must define the necessary probability distributions. // Each node in a Bayesian Network requires a probability distribution conditioned on it's parents. // NewDistribution() can be called on a Node to create the appropriate probability distribution for a node // or it can be created manually. // The interface IDistribution has been designed to represent both discrete and continuous variables, // As we are currently dealing with discrete distributions, we will use the // Table class. // To access the discrete part of a distribution, we use IDistribution.Table. // The Table class is used to define distributions over a number of discrete variables. Table tableA = a.NewDistribution().Table; // access the table property of the Distribution // IMPORTANT // Note that calling Node.NewDistribution() does NOT assign the distribution to the node. // A distribution cannot be assigned to a node until it is correctly specified. // If a distribution becomes invalid (e.g. a parent node is added), it is automatically set to null. // as node A has no parents there is no ambiguity about the order of variables in the distribution tableA[0] = 0.1; tableA[1] = 0.9; // now tableA is correctly specified we can assign it to Node A; a.Distribution = tableA; // node B has node A as a parent // here we use a TableIterator to access the values in the table ( sequentially ), with a particular ordering of the nodes, // the right most node always toggles fastest // e.g. // A, B // True, True // True, False // False, True // False, False Table tableB = b.NewDistribution().Table; TableIterator iteratorB = new TableIterator(tableB, new Node[] { a, b }); double[] values = new double[] { 0.2, 0.8, 0.15, 0.85 }; // see later use of TableIterator for an example of using CopyTo(). for (int i = 0; i < tableB.Count; i++, iteratorB++) { iteratorB.Value = values[i]; } b.Distribution = tableB; Table tableC = c.NewDistribution().Table; // we could also update the values using a TableAccessor ( which allows random access ). TableAccessor accessor = new TableAccessor(tableC, new Node[] { a, c }); accessor[0] = 0.3; accessor[1] = 0.7; accessor[2] = 0.4; accessor[3] = 0.6; c.Distribution = tableC; Table tableD = d.NewDistribution().Table; TableIterator iteratorD = new TableIterator(tableD, new Node[] { b, c, d }); iteratorD.CopyFrom(new double[] { 0.4, 0.6, 0.55, 0.45, 0.32, 0.68, 0.01, 0.99 }); d.Distribution = tableD; // The network is now fully specified // If required the network can be saved... if (false) // change this to true to save the network { network.Save("fileName.bayes"); // replace 'fileName.bayes' with your own path } // Now we will calculate P(A|D=True), i.e. the probability of A given the evidence that D is true // use the factory design pattern to create the necessary inference related objects IInferenceFactory factory = new VariableEliminationInferenceFactory(); IInference inference = factory.CreateInferenceEngine(network); IQueryOptions queryOptions = factory.CreateQueryOptions(); IQueryOutput queryOutput = factory.CreateQueryOutput(); // we could have created these objects explicitly instead, but as the number of algorithms grows // this makes it easier to switch between them inference.Evidence.SetState(d, 0); // set P(A|D=True) Table queryA = new Table(a); inference.QueryDistributions.Add(queryA); if (inference.Query(queryOptions, queryOutput)) { Console.WriteLine("P(A|D=True) = {" + queryA[0] + "," + queryA[1] + "}."); // Expected output ... // P(A|D=True) = {0.0980748663101604,0.90192513368984} } else { Console.WriteLine("Inconsistent evidence was detected."); } // to perform another query we reuse all the objects // now lets calculate P(A|D=True, C=True) inference.Evidence.SetState(c, 0); // we will also return the log-likelihood of the case queryOptions.LogLikelihood = true; // only request the log-likelihood if you really need it, as extra computation is involved if (inference.Query(queryOptions, queryOutput)) { Console.WriteLine(string.Format("P(A|D=True, C=True) = {{{0},{1}}}, log-likelihood = {2}.", queryA[0], queryA[1], queryOutput.LogLikelihood.Value)); // Expected output ... // P(A|D=True, C=True) = {0.0777777777777778,0.922222222222222}, log-likelihood = -2.04330249506396. } else { Console.WriteLine("Inconsistent evidence was detected."); } } } }
Examples
using System; using System.Collections.Generic; using System.Text; using BayesServer.Inference.VariableElimination; namespace BayesServer.HelpSamples { public static class DbnExample { public static void Main() { Network network = new Network("DBN"); Variable varTransition = new Variable("Transition", new string[]{"Cluster1", "Cluster2", "Cluster3"}); Node nodeTransition = new Node(varTransition); // make the node temporal, so that it appears in each time slice nodeTransition.TemporalType = TemporalType.Temporal; Variable varObs1 = new Variable("Obs1", VariableValueType.Continuous); Variable varObs2 = new Variable("Obs2", VariableValueType.Continuous); Variable varObs3 = new Variable("Obs3", VariableValueType.Continuous); Variable varObs4 = new Variable("Obs4", VariableValueType.Continuous); // observation node is a multi variable node, consisting of 4 continuous variables Node nodeObservation = new Node("Observation", new Variable[] { varObs1, varObs2, varObs3, varObs4 }); nodeObservation.TemporalType = TemporalType.Temporal; network.Nodes.Add(nodeTransition); network.Nodes.Add(nodeObservation); // link the transition node to the observation node within each time slice network.Links.Add(new Link(nodeTransition, nodeObservation)); // add a temporal link of order 1. This links the transition node to itself in the next time slice network.Links.Add(new Link(nodeTransition, nodeTransition, 1)); // at this point the structural specification is complete // now complete the distributions // because the transition node has an incoincoming temporal link of order 1 (from itself), we must specify // two distributions, the first of which is specified for time = 0 Table prior = nodeTransition.NewDistribution(0).Table; prior[0] = 0.2; prior[1] = 0.3; prior[2] = 0.5; // NewDistribution does not assign the new distribution, so it still must be assigned nodeTransition.Distribution = prior; // the second is specified for time >= 1 Table transition = nodeTransition.NewDistribution(1).Table; // when specifying temporal distributions, variables which belong to temporal nodes must have times associated // NOTE: Each time is specified relative to the current point in time which is defined as zero, // therfore the time for variables at the previous time step is -1 new TableAccessor(transition, new Variable[] { varTransition, varTransition }, new int?[] { -1, 0 }).CopyFrom(new double[] { 0.2, 0.3, 0.5, 0.4, 0.4, 0.2, 0.9, 0.09, 0.01 }); nodeTransition.Distributions[1] = transition; // Node observation does not have any incoming temporal links, so // only requires a distribution sepcified at time >=0 // Calling NewDistribution without specifying a time assumes time zero. CLGaussian gaussian = (CLGaussian)nodeObservation.NewDistribution(); // set the gaussian parameters corresponding to the state "Cluster1" of variable "transition" gaussian.SetMean(0, 0, 3.2); gaussian.SetMean(0, 1, 2.4); gaussian.SetMean(0, 2, -1.7); gaussian.SetMean(0, 3, 6.2); gaussian.SetVariance(0, 0, 2.3); gaussian.SetVariance(0, 1, 2.1); gaussian.SetVariance(0, 2, 3.2); gaussian.SetVariance(0, 3, 1.4); gaussian.SetCovariance(0, 0, 1, -0.3); gaussian.SetCovariance(0, 0, 2, 0.5); gaussian.SetCovariance(0, 0, 3, 0.35); gaussian.SetCovariance(0, 1, 2, 0.12); gaussian.SetCovariance(0, 1, 3, 0.1); gaussian.SetCovariance(0, 2, 3, 0.23); // set the gaussian parameters corresponding to the state "Cluster2" of variable "transition" gaussian.SetMean(1, 0, 3.0); gaussian.SetMean(1, 1, 2.8); gaussian.SetMean(1, 2, -2.5); gaussian.SetMean(1, 3, 6.9); gaussian.SetVariance(1, 0, 2.1); gaussian.SetVariance(1, 1, 2.2); gaussian.SetVariance(1, 2, 3.3); gaussian.SetVariance(1, 3, 1.5); gaussian.SetCovariance(1, 0, 1, -0.4); gaussian.SetCovariance(1, 0, 2, 0.5); gaussian.SetCovariance(1, 0, 3, 0.45); gaussian.SetCovariance(1, 1, 2, 0.22); gaussian.SetCovariance(1, 1, 3, 0.15); gaussian.SetCovariance(1, 2, 3, 0.24); // set the gaussian parameters corresponding to the state "Cluster3" of variable "transition" gaussian.SetMean(2, 0, 3.8); gaussian.SetMean(2, 1, 2.0); gaussian.SetMean(2, 2, -1.9); gaussian.SetMean(2, 3, 6.25); gaussian.SetVariance(2, 0, 2.34); gaussian.SetVariance(2, 1, 2.11); gaussian.SetVariance(2, 2, 3.22); gaussian.SetVariance(2, 3, 1.43); gaussian.SetCovariance(2, 0, 1, -0.31); gaussian.SetCovariance(2, 0, 2, 0.52); gaussian.SetCovariance(2, 0, 3, 0.353); gaussian.SetCovariance(2, 1, 2, 0.124); gaussian.SetCovariance(2, 1, 3, 0.15); gaussian.SetCovariance(2, 2, 3, 0.236); nodeObservation.Distribution = gaussian; // optional check to validate network network.Validate(new ValidationOptions()); // at this point the network has been fully specified // we will now perform some queries on the network VariableEliminationInference inference = new VariableEliminationInference(network); VariableEliminationQueryOptions queryOptions = new VariableEliminationQueryOptions(); VariableEliminationQueryOutput queryOutput = new VariableEliminationQueryOutput(); // set some temporal evidence inference.Evidence.Set(varObs1, new double?[] { 2.2, 2.4, 2.6, 2.9}, 0, 0, 4); inference.Evidence.Set(varObs2, new double?[] { null, 4.0, 4.1, 4.88}, 0, 0, 4); inference.Evidence.Set(varObs3, new double?[] {-2.5, -2.3, null, -4.0 }, 0, 0, 4); inference.Evidence.Set(varObs4, new double?[] { 4.0, 6.5, 4.9, 4.4}, 0, 0, 4); queryOptions.LogLikelihood = true; // only ask for this if you really need it // predict the observation variables one time step in the future CLGaussian[] gaussianFuture = new CLGaussian[nodeObservation.Variables.Count]; for(int i = 0; i < gaussianFuture.Length; i++) { gaussianFuture[i] = new CLGaussian(nodeObservation.Variables[i], 4); inference.QueryDistributions.Add(gaussianFuture[i]); } // we will also demonstrate querying a joint distribution CLGaussian jointFuture = new CLGaussian(new Variable[] { varObs1, varObs2 }, 4); inference.QueryDistributions.Add(jointFuture); bool ok = inference.Query(queryOptions, queryOutput); Console.WriteLine("LogLikelihood: " + queryOutput.LogLikelihood.Value); Console.WriteLine(); for (int h = 0; h < gaussianFuture.Length; h++) { Console.WriteLine("P({0}(t=4)|evidence)={1}", nodeObservation.Variables[h].Name, gaussianFuture[h].GetMean(0, 0)); } Console.WriteLine(); Console.WriteLine("P({0},{1}|evidence)=", varObs1.Name, varObs2.Name); Console.WriteLine(jointFuture.GetMean(0, 0) + "\t" + jointFuture.GetMean(0, 1)); Console.WriteLine(jointFuture.GetVariance(0, 0) + "\t" + jointFuture.GetCovariance(0, 0, 1)); Console.WriteLine(jointFuture.GetCovariance(0, 1, 0) + "\t" + jointFuture.GetVariance(0, 1)); // Expected output... // LogLikelihood: -26.3688322999762 // P(Obs1(t=4)|evidence)=3.33914912825023 // P(Obs2(t=4)|evidence)=2.38039739886759 // P(Obs3(t=4)|evidence)=-1.98416436694525 // P(Obs4(t=4)|evidence)=6.40822262492584 // P(Obs1,Obs2|evidence)= // 3.33914912825023 2.38039739886759 // 2.36608725717058 -0.427500059391733 // -0.427500059391733 2.22592296205311 } } }
Inheritance Hierarchy
System..::.Object
BayesServer..::.Network
BayesServer..::.Network
