Skip to main content

Construction & inference (hybrid) in C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CLGaussianExample.cs" company="Bayes Server">
// Copyright (C) Bayes Server. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace BayesServer.HelpSamples
{
using System;

using BayesServer.Inference.RelevanceTree;

public static class CLGaussianExample
{
public static void Main()
{
// In this example we programatically create a simple Bayesian network
// that has some continuous variables.
// Note that you can automatically define nodes from data using
// classes in BayesServer.Data.Discovery,
// and you can automatically learn the parameters using classes in
// BayesServer.Learning.Parameters,
// however here we build a Bayesian network from scratch.

var network = new Network("Demo");

// add the nodes (variables)

var dFalse = new State("False");
var dTrue = new State("True");
var d = new Variable("D", dFalse, dTrue);

var c1 = new Variable("C1", VariableValueType.Continuous);
var c2 = new Variable("C2", VariableValueType.Continuous);

network.Nodes.Add(new Node(d));
network.Nodes.Add(new Node(c1));
network.Nodes.Add(new Node(c2));

// add some directed links

network.Links.Add(new Link(d.Node, c2.Node));
network.Links.Add(new Link(c1.Node, c2.Node));

// at this point we have fully specified the structural (graphical) specification of the Bayesian Network.

// We must define the necessary probability distributions for each node.

// 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,

var tableD = d.Node.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.

tableD[dFalse] = 0.2;
tableD[dTrue] = 0.8;

// now tableD is correctly specified we can assign it to Node D;
d.Node.Distribution = tableD;


var gaussianC1 = (CLGaussian)c1.Node.NewDistribution();
gaussianC1.SetMean(c1, 3.5);
gaussianC1.SetVariance(c1, 12.2);
c1.Node.Distribution = gaussianC1;

var clgaussianC2 = (CLGaussian)c2.Node.NewDistribution();
clgaussianC2.SetMean(c2, 22.2, dFalse);
clgaussianC2.SetMean(c2, 54.6, dTrue);
clgaussianC2.SetVariance(c2, 14.6, dFalse);
clgaussianC2.SetVariance(c2, 3.2, dTrue);
clgaussianC2.SetWeight(c2, c1, 1.2, dFalse);
clgaussianC2.SetWeight(c2, c1, -2.1, dTrue);
c2.Node.Distribution = clgaussianC2;


// 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 and uncomment start of line
}

// Now we will calculate P(C2|C1=4)

// use the factory design pattern to create the necessary inference related objects
var factory = new RelevanceTreeInferenceFactory();
var inference = factory.CreateInferenceEngine(network);
var queryOptions = factory.CreateQueryOptions();
var queryOutput = factory.CreateQueryOutput();

inference.Evidence.Set(c1, 4.0); // set c1 = 4

var queryC2 = new CLGaussian(c2);
inference.QueryDistributions.Add(queryC2);
inference.Query(queryOptions, queryOutput); // note that this can raise an exception (see help for details)

Console.WriteLine("P(C2|C1=4) = (mean " + queryC2.GetMean(c2) + ", variance " + queryC2.GetVariance(c2) + ")");

// Expected output ...
// P(C2|C1=4) = (mean 42.36, variance 64.46240000000002)

// Note that we could also calculate other queries such as P(C1,C2|D=True) or P(C2|C1,D=True) or P(C2,D|C1=4), etc...

}
}
}