Skip to main content

Causal optimization and non-causal optimization in a Bayesian network.

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CausalOptimizationExample.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 CausalOptimizationExample
{
public static void Main()
{
var network = LoadNetwork();

// reference some variables and their states
var gender = network.Variables["Gender", true];
var genderMale = gender.States["Male", true];

var drugA = network.Variables["DrugA", true];
var drugB = network.Variables["DrugB", true];

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

// the objective here is to maximize the recovery rate of patients
var objective = new Objective(recoveredTrue, ObjectiveKind.Maximize);

var optimizer = new GeneticOptimizer();
var optimizerOptions = new GeneticOptimizerOptions();

// simplification is optional, but tests whether
// fewer variables having evidence provides a 'close enough' solution
var simplify = new GeneticSimplification();
var simplifyOptions = new GeneticSimplificationOptions();

{
// Example 1. Non-causal optimization
var designVariables = new List<DesignVariable>
{
new DesignVariable(drugA, 0.0, 1.0, true, InterventionType.None), // 'None' does not permit interventions
new DesignVariable(drugB, 0.0, 1.0, true, InterventionType.None) // 'None' does not permit interventions
};

var output = optimizer.Optimize(
network,
objective,
designVariables,
null,
optimizerOptions);

simplifyOptions.EvidenceToSimplify = output.Evidence;

var outputSimple = simplify.Optimize(
network,
objective,
designVariables,
null,
simplifyOptions);


Console.WriteLine($"Example 1 (Non-causal), objective = {outputSimple.ObjectiveValue:P2}.");
Console.WriteLine($" Drug A = {EvidenceToString(outputSimple.Evidence, drugA)}");
Console.WriteLine($" Drug B = {EvidenceToString(outputSimple.Evidence, drugB)}");
Console.WriteLine($" Gender = {EvidenceToString(outputSimple.Evidence, gender)}");
}

{
// Example 2. Causal optimization
var designVariables = new List<DesignVariable>
{
new DesignVariable(drugA, 0.0, 1.0, true, InterventionType.Do),
new DesignVariable(drugB, 0.0, 1.0, true, InterventionType.Do)
};

var options = new GeneticOptimizerOptions();

var output = optimizer.Optimize(
network,
objective,
designVariables,
null,
options);

simplifyOptions.EvidenceToSimplify = output.Evidence;

var outputSimple = simplify.Optimize(
network,
objective,
designVariables,
null,
simplifyOptions);


Console.WriteLine($"Example 2 (Causal), objective = {outputSimple.ObjectiveValue:P2}.");
Console.WriteLine($" Drug A = {EvidenceToString(outputSimple.Evidence, drugA)}");
Console.WriteLine($" Drug B = {EvidenceToString(outputSimple.Evidence, drugB)}");
Console.WriteLine($" Gender = {EvidenceToString(outputSimple.Evidence, gender)}");
}

{
// Example 3. Mixed causal/non-causal optimization

var designVariables = new List<DesignVariable>
{
new DesignVariable(drugA, 0.0, 1.0, true, InterventionType.Do),
new DesignVariable(drugB, 0.0, 1.0, true, InterventionType.Do),
new DesignVariable(gender, 0.0, 1.0, true, InterventionType.None),
};

var options = new GeneticOptimizerOptions();

var output = optimizer.Optimize(
network,
objective,
designVariables,
null,
options);

simplifyOptions.EvidenceToSimplify = output.Evidence;

var outputSimple = simplify.Optimize(
network,
objective,
designVariables,
null,
simplifyOptions);


Console.WriteLine($"Example 3 (Mixed causal/non-causal), objective = {outputSimple.ObjectiveValue:P2}.");
Console.WriteLine($" Drug A = {EvidenceToString(outputSimple.Evidence, drugA)}");
Console.WriteLine($" Drug B = {EvidenceToString(outputSimple.Evidence, drugB)}");
Console.WriteLine($" Gender = {EvidenceToString(outputSimple.Evidence, gender)}");
}

// The following example use fixed evidence, which allow
// us to explore solutions within specified sub-populations

{
// Example 4. Non-causal optimization with fixed evidence

var designVariables = new List<DesignVariable>
{
new DesignVariable(drugA, 0.0, 1.0, true, InterventionType.None),
new DesignVariable(drugB, 0.0, 1.0, true, InterventionType.None)
};

var fixedEvidence = new Evidence(network);
fixedEvidence.SetState(genderMale);

var options = new GeneticOptimizerOptions();

var output = optimizer.Optimize(
network,
objective,
designVariables,
fixedEvidence,
options);

simplifyOptions.EvidenceToSimplify = output.Evidence;

var outputSimple = simplify.Optimize(
network,
objective,
designVariables,
fixedEvidence,
simplifyOptions);


Console.WriteLine($"Example 4 (Non-causal, Fixed evidence), objective = {outputSimple.ObjectiveValue:P2}.");
Console.WriteLine($" Drug A = {EvidenceToString(outputSimple.Evidence, drugA)}");
Console.WriteLine($" Drug B = {EvidenceToString(outputSimple.Evidence, drugB)}");
Console.WriteLine($" Gender = {EvidenceToString(outputSimple.Evidence, gender)}");
}

{
// Example 5. Causal optimization with fixed evidence

var designVariables = new List<DesignVariable>
{
new DesignVariable(drugA, 0.0, 1.0, true, InterventionType.Do),
new DesignVariable(drugB, 0.0, 1.0, true, InterventionType.Do)
};

var fixedEvidence = new Evidence(network);
fixedEvidence.SetState(genderMale);

var options = new GeneticOptimizerOptions();

var output = optimizer.Optimize(
network,
objective,
designVariables,
fixedEvidence,
options);

simplifyOptions.EvidenceToSimplify = output.Evidence;

var outputSimple = simplify.Optimize(
network,
objective,
designVariables,
fixedEvidence,
simplifyOptions);


Console.WriteLine($"Example 5 (Causal with fixed evidence), objective = {outputSimple.ObjectiveValue:P2}.");
Console.WriteLine($" Drug A = {EvidenceToString(outputSimple.Evidence, drugA)}");
Console.WriteLine($" Drug B = {EvidenceToString(outputSimple.Evidence, drugB)}");
Console.WriteLine($" Gender = {EvidenceToString(outputSimple.Evidence, gender)}");
}

// Expected output ...

// Example 1 (Non-causal), objective = 85.83 %.
// Drug A = False
// Drug B = False
// Gender = <missing>
// Example 2 (Causal), objective = 87.65 %.
// Drug A = Do(True)
// Drug B = Do(True)
// Gender = <missing>
// Example 3 (Mixed causal / non-causal), objective = 95.00 %.
// Drug A = Do(True)
// Drug B = Do(True)
// Gender = Male
// Example 4 (Non - causal, Fixed evidence), objective = 95.00 %.
// Drug A = True
// Drug B = True
// Gender = Male
// Example 5 (Causal with fixed evidence), objective = 95.00 %.
// Drug A = Do(True)
// Drug B = Do(True)
// Gender = Male


}


private static string EvidenceToString(IEvidence evidence, Variable variable)
{
var evdTypes = evidence.GetEvidenceTypes(variable);

if (evdTypes.EvidenceType == EvidenceType.None)
return "<missing>";

var text = string.Empty;

if (variable.ValueType == VariableValueType.Discrete)
{
text = variable.States[evidence.GetState(variable).Value].Name;
}
else
{
text = evidence.Get(variable).Value.ToString();
}

if(evdTypes.InterventionType == InterventionType.Do)
{
text = "Do(" + text + ")";
}

return text;
}

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

// you can load a network in a number of different ways

// a) Load from a file...
//network.Load(@"C:\ProgramData\Bayes Server 9.3\Sample Networks\Asia.bayes");

// b) Load from a stream

// c) Load from a string

// d) construct manually, which is what we do here

var genderFemale = new State("Female");
var genderMale = new State("Male");
var gender = new Variable("Gender", genderFemale, genderMale);
network.Nodes.Add(new Node(gender));
gender.Node.Bounds = new Bounds(404.5, 23.0, 183.5, 102.5);

var drugAFalse = new State("False");
var drugATrue = new State("True");
var drugA = new Variable("DrugA", drugAFalse, drugATrue);
network.Nodes.Add(new Node(drugA));
drugA.Node.Bounds = new Bounds(50.5, 136.0, 183.5, 102.5);

var drugBFalse = new State("False");
var drugBTrue = new State("True");
var drugB = new Variable("DrugB", drugBFalse, drugBTrue);
network.Nodes.Add(new Node(drugB));
drugB.Node.Bounds = new Bounds(45.5, 340, 183.5, 102.5);

var recoveredFalse = new State("False");
var recoveredTrue = new State("True");
var recovered = new Variable("Recovered", recoveredFalse, recoveredTrue);
network.Nodes.Add(new Node(recovered));
recovered.Node.Bounds = new Bounds(665, 240, 183.5, 102.5);

network.Links.Add(new Link(gender.Node, drugA.Node));
network.Links.Add(new Link(gender.Node, drugB.Node));
network.Links.Add(new Link(gender.Node, recovered.Node));
network.Links.Add(new Link(drugA.Node, recovered.Node));
network.Links.Add(new Link(drugB.Node, recovered.Node));

// at this stage you could learn the parameters from data
// but to keep this example self contained
// we are specifiying the parameters manually
{
var table = gender.Node.NewDistribution().Table;
table[genderFemale] = 0.49;
table[genderMale] = 0.51;
gender.Node.Distribution = table;
}

{
var table = drugA.Node.NewDistribution().Table;

table[drugAFalse, genderFemale] = 0.233236151603499;
table[drugATrue, genderFemale] = 0.766763848396501;

table[drugAFalse, genderMale] = 0.756302521008403;
table[drugATrue, genderMale] = 0.243697478991597;

drugA.Node.Distribution = table;
}

{
var table = drugB.Node.NewDistribution().Table;

table[drugBFalse, genderFemale] = 0.2;
table[drugBTrue, genderFemale] = 0.8;

table[drugBFalse, genderMale] = 0.85;
table[drugBTrue, genderMale] = 0.15;

drugB.Node.Distribution = table;
}

{
var table = recovered.Node.NewDistribution().Table;
table[genderFemale, drugAFalse, drugBFalse, recoveredFalse] = 0.31;
table[genderFemale, drugAFalse, drugBFalse, recoveredTrue] = 0.69;

table[genderFemale, drugAFalse, drugBTrue, recoveredFalse] = 0.22;
table[genderFemale, drugAFalse, drugBTrue, recoveredTrue] = 0.78;

table[genderFemale, drugATrue, drugBFalse, recoveredFalse] = 0.27;
table[genderFemale, drugATrue, drugBFalse, recoveredTrue] = 0.73;

table[genderFemale, drugATrue, drugBTrue, recoveredFalse] = 0.2;
table[genderFemale, drugATrue, drugBTrue, recoveredTrue] = 0.8;

table[genderMale, drugAFalse, drugBFalse, recoveredFalse] = 0.13;
table[genderMale, drugAFalse, drugBFalse, recoveredTrue] = 0.87;

table[genderMale, drugAFalse, drugBTrue, recoveredFalse] = 0.1;
table[genderMale, drugAFalse, drugBTrue, recoveredTrue] = 0.9;

table[genderMale, drugATrue, drugBFalse, recoveredFalse] = 0.07;
table[genderMale, drugATrue, drugBFalse, recoveredTrue] = 0.93;

table[genderMale, drugATrue, drugBTrue, recoveredFalse] = 0.05;
table[genderMale, drugATrue, drugBTrue, recoveredTrue] = 0.95;

recovered.Node.Distribution = table;
}


return network;
}
}
}