Causal inference with a Bayesian network.

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


using BayesServer.Inference;
using BayesServer.Inference.RelevanceTree;
using BayesServer.Optimization;
using BayesServer.Optimization.Genetic;
using BayesServer.Statistics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BayesServer.HelpSamples
{
    public static class CausalInferenceExample
    {
        public static void Main()
        {
            var network = new Network();
            network.Load(@"C:\ProgramData\Bayes Server 9.5\Sample Networks\Causal Inference Simple.bayes");

            var drug = network.Variables["Drug", true];
            var drugTrue = drug.States["True", true];
            var drugFalse = drug.States["False", true];

            var recovered = network.Variables["Recovered", true];
            var recoveredTrue = recovered.States["True", true];

            var factory = new RelevanceTreeInferenceFactory();
            var inference = factory.CreateInferenceEngine(network);
            var queryOptions = factory.CreateQueryOptions();
            var queryOutput = factory.CreateQueryOutput();
            var queryRecovered = new Table(recovered);
            inference.QueryDistributions.Add(queryRecovered);

            {
                Console.WriteLine("Non-causal version (incorrect)...");

                // First lets calculate P(Recovered=True|Drug=True) - P(Recovered=True|Drug=False)
                // without an intervention. i.e. non-causally which will give us the wrong result

                inference.Evidence.SetState(drugTrue);
                inference.Query(queryOptions, queryOutput);

                var pRecoveredGivenDrugTrue = queryRecovered[recoveredTrue];
                inference.Evidence.SetState(drugFalse);
                inference.Query(queryOptions, queryOutput);
                var pRecoveredGivenDrugFalse = queryRecovered[recoveredTrue];

                var effectivenessNonCausal = pRecoveredGivenDrugTrue - pRecoveredGivenDrugFalse;
                Console.WriteLine($"Effectiveness of drug (non-causal) = {effectivenessNonCausal.ToString("P2")}");

            }

            Console.WriteLine();

            {
                Console.WriteLine("Causal version...");

                // Now lets calculate P(Recovered=True|Do(Drug=True)) - P(Recovered=True|Do(Drug=False))
                // with an intervention. i.e. causally which will give us the correct result

                inference.Evidence.SetState(drugTrue, null, InterventionType.Do);
                inference.Query(queryOptions, queryOutput);
                var pRecoveredGivenDoDrugTrue = queryRecovered[recoveredTrue];

                inference.Evidence.SetState(drugFalse, null, InterventionType.Do);
                inference.Query(queryOptions, queryOutput);
                var pRecoveredGivenDoDrugFalse = queryRecovered[recoveredTrue];

                var effectivenessCausal = pRecoveredGivenDoDrugTrue - pRecoveredGivenDoDrugFalse;
                Console.WriteLine($"Effectiveness of drug (causal) = {effectivenessCausal.ToString("P2")}");

            }

            // Expected output:

            // Non-causal version (incorrect)...
            // Effectiveness of drug(non-causal) = -4.91 %

            // Causal version...
            // Effectiveness of drug(causal) = 5.02 %
        }
    }
}