Time Series Parameter learning in C#

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

namespace BayesServer.HelpSamples
{
    using System;
    using System.Data.SqlClient;

    using BayesServer.Data;
    using BayesServer.Inference.RelevanceTree;
    using BayesServer.Learning.Parameters;

    public static class ParameterLearningTemporal
    {
        public static void Main()
        {
            // we manually construct the network here, but it could be loaded from a file
            var network = CreateNetworkStructure();
            var x1 = network.Variables["X1"];
            var x2 = network.Variables["X2"];
            
            // now learn the parameters from the data in Walkthrough 3 - Time Series network

            // This example uses Sql Server as the data source and assumes the data has been copied to
            // a table called TimeSeriesWalkthrough
            // We will use the RelevanceTree algorithm here, as it is optimized for parameter learning
            var learning = new ParameterLearning(network, new RelevanceTreeInferenceFactory());
            var learningOptions = new ParameterLearningOptions();

            // sql server connection string
            string sqlServer = @"localhost\sqlexpress"; // change this to your sql server instance name
            string database = "BayesServer";    // change this to your database name

            string connectionString = string.Format(
                @"Data Source={0};Initial Catalog={1};Integrated Security=True;", sqlServer, database);

            IDataReaderCommand temporalDataReaderCommand = new DatabaseDataReaderCommand(
                SqlClientFactory.Instance,
                connectionString,
                "Select [Case], Time, X1, X2 From TimeSeriesWalkthrough ORDER BY [Case], Time");

            bool cacheDataInMemory = true;  // set this to false for large data sets

            if (cacheDataInMemory)
            {
                temporalDataReaderCommand = new DataTableDataReaderCommand(temporalDataReaderCommand.ExecuteReader());
            }

            var temporalReaderOptions = new TemporalReaderOptions("Case", "Time", TimeValueType.Index);

            // here we map variables to database columns
            // in this case the variables and database columns have the same name
            var temporalVariableReferences = new VariableReference[]
                {
                    new VariableReference(x1, ColumnValueType.Value, x1.Name),
                    new VariableReference(x2, ColumnValueType.Value, x2.Name)
                };

            // note that although this example only has temporal data
            // we could have included additional non temporal variables and data

            var evidenceReaderCommand = new EvidenceReaderCommand(
                temporalDataReaderCommand,
                temporalVariableReferences,
                temporalReaderOptions);

            var result = learning.Learn(evidenceReaderCommand, learningOptions);

            Console.WriteLine("Log likelihood = {0}", result.LogLikelihood.Value);

        }

        private static Network CreateNetworkStructure()
        {
            var network = new Network();

            var x1 = new Variable("X1", VariableValueType.Continuous);
            var x2 = new Variable("X2", VariableValueType.Continuous);

            // add a temporal (time series) node, with two continuous variables
            var nodeX = new Node("X", new Variable[] { x1, x2 })
            {
                TemporalType = BayesServer.TemporalType.Temporal
            };

            network.Nodes.Add(nodeX);

            // add temporal links
            for (int order = 1; order <= 4; order++)
            {
                network.Links.Add(new Link(nodeX, nodeX, order));
            }

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

            return network;
        }
    }
}