Skip to main content

Noisy nodes in C#

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

namespace BayesServer.HelpSamples
{
using System;

using BayesServer.Inference.RelevanceTree;

public static class NoisyNodesExample
{
public static void Main()
{
// In this example we programatically create a Bayesian network with Noisy nodes.
// The network created can also be found within the example network (called Noisy Or) installed with Bayes Server.

// 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 the 'Noisy OR' network manually.

var network = new Network("Noisy Or");

// add the nodes (variables)

var infectionFalse = new State("False");
var infectionTrue = new State("True");
var infection = new Variable("Infection", infectionFalse, infectionTrue);
var infectionNode = new Node(infection);

var osteoFalse = new State("False");
var osteoTrue = new State("True");
var osteo = new Variable("Osteoarthritis", osteoFalse, osteoTrue);
var osteoNode = new Node(osteo);

var rheumatoidFalse = new State("False");
var rheumatoidTrue = new State("True");
var rheumatoid = new Variable("Rheumatoid arthritis", rheumatoidFalse, rheumatoidTrue);
var rheumatoidNode = new Node(rheumatoid);

var temperaturesFalse = new State("False");
var temperaturesTrue = new State("True");
var temperatures = new Variable("Temperatures", temperaturesFalse, temperaturesTrue);
var temperaturesNode = new Node(temperatures);
temperaturesNode.DistributionOptions.NoisyType = NoisyType.NoisyOrMax;

var soreJointsFalse = new State("False");
var soreJointsTrue = new State("True");
var soreJoints = new Variable("Sore joints", soreJointsFalse, soreJointsTrue);
var soreJointsNode = new Node(soreJoints);
soreJointsNode.DistributionOptions.NoisyType = NoisyType.NoisyOrMax;

var nailProblemsFalse = new State("False");
var nailProblemsTrue = new State("True");
var nailProblems = new Variable("Nail problems", nailProblemsFalse, nailProblemsTrue);
var nailProblemsNode = new Node(nailProblems);
nailProblemsNode.DistributionOptions.NoisyType = NoisyType.NoisyOrMax;


network.Nodes.Add(infectionNode);
network.Nodes.Add(osteoNode);
network.Nodes.Add(rheumatoidNode);
network.Nodes.Add(temperaturesNode);
network.Nodes.Add(soreJointsNode);
network.Nodes.Add(nailProblemsNode);


// add some directed links

network.Links.Add(new Link(infectionNode, temperaturesNode));
network.Links.Add(new Link(infectionNode, soreJointsNode));
network.Links.Add(new Link(infectionNode, nailProblemsNode));
network.Links.Add(new Link(osteoNode, temperaturesNode));
network.Links.Add(new Link(osteoNode, soreJointsNode));
network.Links.Add(new Link(osteoNode, nailProblemsNode));
network.Links.Add(new Link(rheumatoidNode, temperaturesNode));
network.Links.Add(new Link(rheumatoidNode, soreJointsNode));
network.Links.Add(new Link(rheumatoidNode, nailProblemsNode));

// All the links in this particular network have ascending causal effects
foreach(var link in network.Links)
{
link.NoisyOrder = NoisyOrder.Ascending;
}

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

// We will setup the nodes which are not 'Noisy' first in the usual way

{
var tableInfection = infectionNode.NewDistribution().Table;
tableInfection[infectionFalse] = 0.95;
tableInfection[infectionTrue] = 0.05;
infectionNode.Distribution = tableInfection;
}

{
var tableOsteoarthritis = osteoNode.NewDistribution().Table;
tableOsteoarthritis[osteoFalse] = 0.99;
tableOsteoarthritis[osteoTrue] = 0.01;
osteoNode.Distribution = tableOsteoarthritis;
}

{
var tableRheumatoidArthritis = rheumatoidNode.NewDistribution().Table;
tableRheumatoidArthritis[rheumatoidFalse] = 0.9999;
tableRheumatoidArthritis[rheumatoidTrue] = 0.0001;
rheumatoidNode.Distribution = tableRheumatoidArthritis;

}

// For noisy nodes, we require a distribution given each parent and an additional leak distribution.

// Define the distribution for the 'Temperatures' node
{
{
var keyInfection = new NodeDistributionKey(infectionNode);
var tableInfectionTemperatures = temperaturesNode.NewDistribution(keyInfection).Table;
tableInfectionTemperatures[infectionTrue, temperaturesFalse] = 0.4;
tableInfectionTemperatures[infectionTrue, temperaturesTrue] = 0.6;
temperaturesNode.Distributions[keyInfection] = tableInfectionTemperatures;
}

{
var keyOsteo = new NodeDistributionKey(osteoNode);
var tableOsteoTemperatures = temperaturesNode.NewDistribution(keyOsteo).Table;
tableOsteoTemperatures[osteoTrue, temperaturesFalse] = 1.0;
tableOsteoTemperatures[osteoTrue, temperaturesTrue] = 0.0;
temperaturesNode.Distributions[keyOsteo] = tableOsteoTemperatures;
}

{
var keyRheumatoid = new NodeDistributionKey(rheumatoidNode);
var tableRheumatoidTemperatures = temperaturesNode.NewDistribution(keyRheumatoid).Table;
tableRheumatoidTemperatures[rheumatoidTrue, temperaturesFalse] = 0.3;
tableRheumatoidTemperatures[rheumatoidTrue, temperaturesTrue] = 0.7;
temperaturesNode.Distributions[keyRheumatoid] = tableRheumatoidTemperatures;
}

{
var keyLeak = new NodeDistributionKey(temperaturesNode);
var tableLeakTemperatures = temperaturesNode.NewDistribution(keyLeak).Table;
tableLeakTemperatures[temperaturesFalse] = 0.9;
tableLeakTemperatures[temperaturesTrue] = 0.1;
temperaturesNode.Distributions[keyLeak] = tableLeakTemperatures;
}
}

// Define the distribution for the 'Sore Joints' node
{
{
var keyInfection = new NodeDistributionKey(infectionNode);
var tableInfectionSoreJoints = soreJointsNode.NewDistribution(keyInfection).Table;
tableInfectionSoreJoints[infectionTrue, soreJointsFalse] = 0.9;
tableInfectionSoreJoints[infectionTrue, soreJointsTrue] = 0.1;
soreJointsNode.Distributions[keyInfection] = tableInfectionSoreJoints;
}

{
var keyOsteo = new NodeDistributionKey(osteoNode);
var tableOsteoSoreJoints = soreJointsNode.NewDistribution(keyOsteo).Table;
tableOsteoSoreJoints[osteoTrue, soreJointsFalse] = 0.01;
tableOsteoSoreJoints[osteoTrue, soreJointsTrue] = 0.99;
soreJointsNode.Distributions[keyOsteo] = tableOsteoSoreJoints;
}

{
var keyRheumatoid = new NodeDistributionKey(rheumatoidNode);
var tableRheumatoidSoreJoints = soreJointsNode.NewDistribution(keyRheumatoid).Table;
tableRheumatoidSoreJoints[rheumatoidTrue, soreJointsFalse] = 0.01;
tableRheumatoidSoreJoints[rheumatoidTrue, soreJointsTrue] = 0.99;
soreJointsNode.Distributions[keyRheumatoid] = tableRheumatoidSoreJoints;
}

{
var keyLeak = new NodeDistributionKey(soreJointsNode);
var tableLeakSoreJoints = soreJointsNode.NewDistribution(keyLeak).Table;
tableLeakSoreJoints[soreJointsFalse] = 0.9;
tableLeakSoreJoints[soreJointsTrue] = 0.1;
soreJointsNode.Distributions[keyLeak] = tableLeakSoreJoints;
}
}


// Define the distribution for the 'Nail Problems' node
{
{
var keyInfection = new NodeDistributionKey(infectionNode);
var tableInfectionNailProblems = nailProblemsNode.NewDistribution(keyInfection).Table;
tableInfectionNailProblems[infectionTrue, nailProblemsFalse] = 0.85;
tableInfectionNailProblems[infectionTrue, nailProblemsTrue] = 0.15;
nailProblemsNode.Distributions[keyInfection] = tableInfectionNailProblems;
}

{
var keyOsteo = new NodeDistributionKey(osteoNode);
var tableOsteoNailProblems = nailProblemsNode.NewDistribution(keyOsteo).Table;
tableOsteoNailProblems[osteoTrue, nailProblemsFalse] = 1.0;
tableOsteoNailProblems[osteoTrue, nailProblemsTrue] = 0.0;
nailProblemsNode.Distributions[keyOsteo] = tableOsteoNailProblems;
}

{
var keyRheumatoid = new NodeDistributionKey(rheumatoidNode);
var tableRheumatoidNailProblems = nailProblemsNode.NewDistribution(keyRheumatoid).Table;
tableRheumatoidNailProblems[rheumatoidTrue, nailProblemsFalse] = 0.5;
tableRheumatoidNailProblems[rheumatoidTrue, nailProblemsTrue] = 0.5;
nailProblemsNode.Distributions[keyRheumatoid] = tableRheumatoidNailProblems;
}

{
var keyLeak = new NodeDistributionKey(nailProblemsNode);
var tableLeakNailProblems = nailProblemsNode.NewDistribution(keyLeak).Table;
tableLeakNailProblems[nailProblemsFalse] = 0.9;
tableLeakNailProblems[nailProblemsTrue] = 0.1;
nailProblemsNode.Distributions[keyLeak] = tableLeakNailProblems;
}
}

network.Validate(new ValidationOptions());


// Setup an inference engine to allow us to make predictions

var factory = new RelevanceTreeInferenceFactory();
var inference = factory.CreateInferenceEngine(network);
var queryOptions = factory.CreateQueryOptions();
var queryOutputs = factory.CreateQueryOutput();

// Now lets make some predictions (queries).

// Scenario A - Predict disease from Symptoms (not all symptoms have been accounted for)

var queryInfection = new Table(infection);
inference.QueryDistributions.Add(queryInfection);

var queryOsteo = new Table(osteo);
inference.QueryDistributions.Add(queryOsteo);

var queryRheumatoid = new Table(rheumatoid);
inference.QueryDistributions.Add(queryRheumatoid);

var evidence = inference.Evidence;

evidence.SetState(temperaturesFalse);
evidence.SetState(soreJointsTrue);

inference.Query(queryOptions, queryOutputs);

Console.WriteLine("Scenario A");
Console.WriteLine("-----------");
Console.WriteLine("P(Infection=True | evidence) = " + queryInfection[infectionTrue]);
Console.WriteLine("P(Osteoarthritis=True | evidence) = " + queryOsteo[osteoTrue]);
Console.WriteLine("P(Rheumatoid arthritis=True | evidence) = " + queryRheumatoid[rheumatoidTrue]);
Console.WriteLine();

// Scenario B - Predict disease from Symptoms having tested and ruled out certain diseases

evidence.SetState(infectionFalse);

inference.Query(queryOptions, queryOutputs);

Console.WriteLine("Scenario B");
Console.WriteLine("-----------");
Console.WriteLine("P(Osteoarthritis=True | evidence) = " + queryOsteo[osteoTrue]);
Console.WriteLine("P(Rheumatoid arthritis=True | evidence) = " + queryRheumatoid[rheumatoidTrue]);
Console.WriteLine();

// Scenario C - Also predict Symptom given other Symptoms having ruled out certain diseases

var queryNailProblems = new Table(nailProblems);
inference.QueryDistributions.Add(queryNailProblems);

inference.Query(queryOptions, queryOutputs);

Console.WriteLine("Scenario C");
Console.WriteLine("-----------");
Console.WriteLine("P(Nail Problem=True | evidence) = " + queryNailProblems[nailProblemsTrue]);
Console.WriteLine();




}
}
}