Batch query C#

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

namespace BayesServer.HelpSamples
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using BayesServer.Data;
    using System.Data;
    using BayesServer.Inference.RelevanceTree;

    public static class BatchQueryExample
    {
        public static void Main()
        {
            var network = new Network();
            network.Load("Waste.bayes");  // TODO change this path to the 'Waste' example network installed with Bayes Server

            // discrete
            var burningRegimen = network.Variables["Burning Regimen"];
            var wasteType = network.Variables["Waste type", true];
            var filterState = network.Variables["Filter state", true];

            var burningRegimenStable = burningRegimen.States["Stable", true];

            // continuous
            var filterEfficiency = network.Variables["Filter efficiency", true];
            var dustEmission = network.Variables["Dust emission", true];
            var metalsInWaste = network.Variables["Metals in waste", true];
            var co2Concentration = network.Variables["CO2 concentration", true];
            var lightPenetrability = network.Variables["Light penetrability", true];
            var metalsEmission = network.Variables["Metals emission", true];

            // Create an inference engine to calculate the queries.
            // The same inference engine can be re-used for multiple rows of data.
            // Although not shown here, you can also create multiple inference engines,
            // to take advantage of multiple threads.

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

            // add some marginal queries
            var queryBurningRegimen = new Table(burningRegimen);
            inference.QueryDistributions.Add(queryBurningRegimen);
            var queryLightPenetrability = new CLGaussian(lightPenetrability);
            inference.QueryDistributions.Add(queryLightPenetrability);
            // You can also add joint queries over > 1 variable
            var queryJoint = new CLGaussian(new Variable[] { filterEfficiency, burningRegimen });
            inference.QueryDistributions.Add(queryJoint);

            // we will also query the log-likelihood
            queryOptions.LogLikelihood = true;


            var evidenceReaderCommand = CreateEvidenceReaderCommand(network);

            var readOptions = new ReadOptions();

            // Iterate through the data, perform queries for each row.
            // In this example, the output is simply written to the console, but the output 
            // could be streamed into a database or another data store or endpoint.

            using (var evidenceReader = evidenceReaderCommand.ExecuteReader())
            {
                while (evidenceReader.Read(inference.Evidence, readOptions))
                {
                    inference.Query(queryOptions, queryOutput);

                    var logLikelihood = queryOutput.LogLikelihood.Value;
                    var probStable = queryBurningRegimen[burningRegimenStable];
                    var meanLightPenetrability = queryLightPenetrability.GetMean(lightPenetrability);
                    var varianceLightPenetrability = queryLightPenetrability.GetVariance(lightPenetrability);
                    var jointElement = queryJoint.GetMean(filterEfficiency, burningRegimenStable);


                    Console.WriteLine($"{logLikelihood}\t{probStable}\t{meanLightPenetrability}\t{varianceLightPenetrability}\t{jointElement}");
                }
            }
        }

        /// <summary>
        /// Create an evidence reader command, than maps data to variables.
        /// 
        /// This can connect to a database, a DataTable or you can create a custom reader.
        /// </summary>
        private static IEvidenceReaderCommand CreateEvidenceReaderCommand(Network network)
        {
            var dataReaderCommand = CreateDataReaderCommand();

            var wasteType = network.Variables["Waste type", true];
            var co2Concentration = network.Variables["CO2 concentration", true];

            return new EvidenceReaderCommand(
                dataReaderCommand,
                new VariableReference[]
                {
                    new VariableReference(wasteType, ColumnValueType.Name, wasteType.Name),
                    new VariableReference(co2Concentration, ColumnValueType.Value, co2Concentration.Name),
                },
                new ReaderOptions()
                );

        }

        /// <summary>
        /// Manually create some data here to keep the example self contained.
        /// This could also be queried from a database, 
        /// or another data source.
        /// </summary>
        private static IDataReaderCommand CreateDataReaderCommand()
        {
            var table = new DataTable();
            var wasteType = table.Columns.Add("Waste type", typeof(string));
            var co2Concentration = table.Columns.Add("CO2 concentration", typeof(double));

            // you can use null for missing data

            table.Rows.Add("Industrial", -1.7);
            table.Rows.Add("Household", -2.0);
            table.Rows.Add(null, -1.7);
            table.Rows.Add("Industrial", null);
            table.Rows.Add("Industrial", 0.5);

            return new DataTableDataReaderCommand(table);
        }
    }
}