Data Sampling in C#

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

namespace BayesServer.HelpSamples
{
    using System;

    using BayesServer.Data.Sampling;
    using BayesServer.Inference;

    public static class DataSampling
    {
        public static void Main()
        {
            // we manually construct the network here, but it could be loaded from a file
            var network = CreateNetwork();
            var gender = network.Variables["Gender"];
            var height = network.Variables["Height"];
            var hairLength = network.Variables["Hair Length"];

            // You can set evidence on 'fixedEvidence' if you wish to fix
            // certain variables.  Here we fix Gender.
            var fixedEvidence = new Evidence(network);
            fixedEvidence.SetState(gender.States["Female", true]);

            // prepare to sample data from the Bayesian network
            var sampler = new DataSampler(network, fixedEvidence);
            var options = new DataSamplingOptions();

            // If you want to simulate missing data, you can use the following line of code...
            // options.MissingDataProbability = 0.05;  // set 5% of the data to missing

            var random = new Random(0);
            var evidence = new Evidence(network);

            // output 100 samples

            Console.WriteLine("Gender\tHeight\tHair Length");
            Console.WriteLine("------------------------------");

            for (int i = 0; i < 100; i++)
            {
                try
                {
                    sampler.TakeSample(evidence, random, options);
                    Console.WriteLine("{0}\t{1}\t{2}",
                        ValueAsText(gender, evidence),
                        ValueAsText(height, evidence),
                        ValueAsText(hairLength, evidence));
                }
                catch (InconsistentEvidenceException)
                {
                    Console.WriteLine("Inconsistent evidence exception was raised.");
                }
            }
        }

        private static string ValueAsText(Variable variable, IEvidence evidence)
        {
            if(evidence.GetEvidenceType(variable) == EvidenceType.None)
                return "(null)";

            if (variable.ValueType == VariableValueType.Continuous)
            {
                return evidence.Get(variable).Value.ToString("N2");
            }
            else
            {
                return variable.States[evidence.GetState(variable).Value].Name;
            }
        }

        private static Network CreateNetwork()
        {
            var network = new Network();
            var nodeGender = new Node("Gender", new string[] { "Female", "Male" });
            network.Nodes.Add(nodeGender);

            var nodeHeight = new Node("Height", VariableValueType.Continuous);
            network.Nodes.Add(nodeHeight);

            var nodeHairLength = new Node("Hair Length", new string[] { "Short", "Medium", "Long" });
            network.Nodes.Add(nodeHairLength);

            network.Links.Add(new Link(nodeGender, nodeHeight));
            network.Links.Add(new Link(nodeGender, nodeHairLength));

            // at this point the structure of the Bayesian network is fully specified

            // now set the parameters

            var tableGender = nodeGender.NewDistribution().Table;
            tableGender.CopyFrom(new double[] { 0.51, 0.49 });
            nodeGender.Distribution = tableGender;

            var tableHairLength = nodeHairLength.NewDistribution().Table;
            var iteratorHairLength = new TableIterator(tableHairLength, new Node[] { nodeGender, nodeHairLength });
            iteratorHairLength.CopyFrom(new double[] { 0.1, 0.4, 0.5, 0.8, 0.15, 0.05 });
            nodeHairLength.Distribution = tableHairLength;

            var gaussianHeight = (CLGaussian)nodeHeight.NewDistribution();
            // set the mean and variance for females
            gaussianHeight.SetMean(0, 0, 162.56);
            gaussianHeight.SetVariance(0, 0, 50.58);

            // set the mean and variance for males
            gaussianHeight.SetMean(1, 0, 176.022);
            gaussianHeight.SetVariance(1, 0, 50.58);

            nodeHeight.Distribution = gaussianHeight;

            // check that the Bayesian network is specified correctly
            network.Validate(new ValidationOptions());

            return network;
        }
    }
}