Represents a Bayesian Network, or a Dynamic Bayesian Network. To perform inference with a network see the BayesServer.Inference namespace.

Namespace:  BayesServer
Assembly:  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

CopyC#
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

CopyC#
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

See Also