Online learning in C#

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


using BayesServer.Inference;
using BayesServer.Inference.RelevanceTree;
using BayesServer.Learning.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BayesServer.HelpSamples
{
    public static class OnlineLearningExample
    {
        public static void Main()
        {
            // Manually construct a network.  We could instead load from a file etc...
            var network = CreateNetwork();

            // Reference some variables and states
            var a = network.Variables["A", true];
            var b = network.Variables["B", true];
            var a1 = a.States["A1", true];
            var a2 = a.States["A2", true];
            var b1 = b.States["B1", true];
            var b2 = b.States["B2", true];

            var inferenceFactory = new RelevanceTreeInferenceFactory();
            var onlineLearning = new OnlineLearning(network, inferenceFactory);
            var options = new OnlineLearningOptions();

            // Now set some evidence...

            var evidence = onlineLearning.Evidence;

            // Note that we are using the 'Evidence' instance supplied by the OnlineLearning instance,
            // however we could instead ...

            // 1. Create our own evidence instance...
            //      var evidence = new Evidence(network);
            // 2. Use one created by an inference engine...
            //      var inference = new RelevanceTreeInference();
            //      var evidence = inference.Evidence;

            evidence.SetState(b1);

            // Note that at this point we have missing data on A which is supported.
            onlineLearning.Adapt(evidence, options);

            // Note that the same onlineLearning instance should be re-used.

            evidence.SetState(b2);
            evidence.SetState(a1);

            onlineLearning.Adapt(evidence, options);

            // We have now performed online learning twice.
            // Lets look at the distributions and experience tables

            var tableA = a.Node.Distribution.Table;
            Console.WriteLine("P(A) = [{0}, {1}]", tableA[a1], tableA[a2]);
            var experienceA = a.Node.Distributions[NodeDistributionKind.Experience].Table;
            Console.WriteLine("Experience (A) = [{0}]", experienceA[0]);

            Console.WriteLine();

            var tableB = b.Node.Distribution.Table;
            Console.WriteLine("P(B|A1) = [{0}, {1}]", tableB[a1, b1], tableB[a1, b2]);
            Console.WriteLine("P(B|A2) = [{0}, {1}]", tableB[a2, b1], tableB[a2, b2]);
            var experienceB = b.Node.Distributions[NodeDistributionKind.Experience].Table;
            Console.WriteLine("Experience (B) = [{0}, {1}]", experienceB[a1], experienceB[a2]);



        }

        private static Network CreateNetwork()
        {
            // Here we manually create a Bayesian network
            // showing how you can set experience tables manually.

            // Instead you can also use the following option with ParameterLearning
            // to automatically create Experience tables from data

            // var options = new ParameterLearningOptions();
            // options.SaveHyperparameters = true;

            var network = new Network();

            var a1 = new State("A1");
            var a2 = new State("A2");
            var a = new Variable("A", a1, a2);
            network.Nodes.Add(new Node(a));

            var b1 = new State("B1");
            var b2 = new State("B2");
            var b = new Variable("B", b1, b2);
            network.Nodes.Add(new Node(b));

            network.Links.Add(new Link(a.Node, b.Node));

            // Manually set the standard probability tables...
            // Note that you could instead learn these from data.
            var tableA = a.Node.NewDistribution().Table;
            tableA[a1] = 0.2;
            tableA[a2] = 0.8;
            a.Node.Distribution = tableA;

            var tableB = b.Node.NewDistribution().Table;
            tableB[a1, b1] = 0.35;
            tableB[a1, b2] = 0.65;
            tableB[a2, b1] = 0.55;
            tableB[a2, b2] = 0.45;
            b.Node.Distribution = tableB;

            // Now set some experience tables...
            // You could instead learn these from data (see notes above).

            var experienceA = a.Node.NewDistribution(NodeDistributionKind.Experience).Table;
            experienceA[0] = 1000.0;
            a.Node.Distributions[NodeDistributionKind.Experience] = experienceA;

            // Note that we could chose to set experience tables on some but not all nodes, 
            // if we only want to update a subset of nodes.

            var experienceB = b.Node.NewDistribution(NodeDistributionKind.Experience).Table;
            experienceB[a1] = 300.0;
            experienceB[a2] = 700.0;
            b.Node.Distributions[NodeDistributionKind.Experience] = experienceB;

            return network;


        }
    }
}