This pyAgrum's notebook is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License
Author: Aymen Merrouche and Pierre-Henri Wuillemin.
from IPython.display import display, Math, Latex,HTML
import pyAgrum as gum
import pyAgrum.lib.notebook as gnb
import pyAgrum.causal as csl
import pyAgrum.causal.notebook as cslnb
import os
In order for a prisoner to be executed, a certain chain of events must take place. First, the court gives the execution order to the captain. Then, the captain gives the signal to the firing squad (two soldiers A and B) to shoot the prisoner. Finally, the soldiers obey the commandment and shoot at the prisoner.
The corresponding causal diagram is the following:
mtt = gum.fastBN("court order->captain->soldier A->death<-soldier B<-captain")
mtt
# filling the CPTs
def smallPertubation(cpt,epsilon=0.0001):
cpt.fillWith(cpt.translate(epsilon).normalizeAsCPT())
mtt.cpt("court order")[:] = [0.5, 0.5]
# The captain will give the signal only if the court gives the order.
mtt.cpt("captain")[{"court order":0}] = [1,0]
mtt.cpt("captain")[{"court order":1}] = [0,1]
# The soldiers only fire if the captain gives them the signal.
mtt.cpt("soldier A")[{"captain":0}] = [1, 0] # c=0
mtt.cpt("soldier A")[{"captain":1}] = [0, 1] # c=1
smallPertubation(mtt.cpt("soldier A"))
mtt.cpt("soldier B")[{"captain":0}] = [1, 0] # c=0
mtt.cpt("soldier B")[{"captain":1}] = [0, 1] # c=1
smallPertubation(mtt.cpt("soldier B"))
# It only takes one of the two soldiers to shoot for the prisoner to die.
mtt.cpt("death")[{"soldier A":0,"soldier B":0}] = [1, 0] # a=0,b=0
mtt.cpt("death")[{"soldier A":0,"soldier B":1}] = [0, 1] # a=0,b=1
mtt.cpt("death")[{"soldier A":1,"soldier B":0}] = [0, 1] # a=1,b=0
mtt.cpt("death")[{"soldier A":1,"soldier B":1}] = [0, 1] # a=1,b=1
smallPertubation(mtt.cpt("death"))
gnb.sideBySide(mtt,
mtt.cpt("court order"),
mtt.cpt("captain"),
mtt.cpt("soldier A"),
mtt.cpt("soldier B"),
mtt.cpt("death"),
captions=["the BN","the marginal for $court order$","the CPT for $captain$","the CPT for $soldier A$","the CPT for $soldier B$","the CPT for $death$"])
#gum.saveBN(mtt,os.path.join("out","MiniTuringTest.o3prm"))
Consists of finding variables that are associated by collecting and analyzing raw data. It allows us to answer queries based on passive observation of data If I observe variable $ X $, what can I say about variable $ Y $? (i.e $ P (Y \mid X) $)
i.e. We are interested in distribution: $$P(court order \mid death = 1)$$
# inference engine : LazyPropagation
ie = gum.LazyPropagation(mtt)
# Knowing that death = 1
ie.setEvidence({'death':1})
ie.makeInference()
gnb.sideBySide(ie.posterior("court order"),gnb.getInference(mtt,evs={'death':1}),
captions=["$P(court order|death=1)","Complete inference with evidence={deah:1}"])
If the prisoner is dead, this means that both soldiers fired, the captain gave the signal to the firing squad and the court ordered the execution.
i.e. We are interested in distribution: $$P(soldierB \mid soldierA = 1)$$
gnb.showInference(mtt,evs={'soldier A':1})
Following the diagram, we can say that B fired too since A wouldn't have fired if the captain didn't give the signal.
Consists of predicting the effect of a deliberate intervention What would $ X $ be, if I do $ Y $? (i.e. $P(X \mid do(Y))$) Interventional queries can not be answered using only passively collected data.
mttModele = csl.CausalModel(mtt)
# We do(soldier A = 1) (a deliberate intervention)
cslnb.showCausalImpact(mttModele,"death",doing="soldier A",values={"soldier A":1})
Even if the captain didn't give the command to the firing squad, the prisoner still died we soldier A decided to shoot him.
Subset {captain} meets the back-door criterion relative to (soldier A, death) because:
- 1- no node in {captain} is a descendant of "soldier A"
- 2- {captain} blocks every path between "soldier A" and "death" that contains an arrow into "death"
So {captain} satisfies the back-door criterion relative to (soldier A, death), the causal effect of "soldier A" over "death" is given by the formula $$P(death ∣ do(soldierA = 1)) = \sum_{captain}{P(death ∣ captain,soldierA).P(captain)}$$
mttModele = csl.CausalModel(mtt)
# We do(soldier A = 1) (a deliberate intervention)
cslnb.showCausalImpact(mttModele,on="soldier B",doing="soldier A", values={"soldier A":1})
A’s spontaneous decision shouldn't affect variables in the model that are not descendants of A. If we see that A shot, we conclude that B shot too (he wouldn't have shot without the captain's order). But if we make A shoot spontaneously without waiting for the captain's order, we have no information about B. This is the difference between seeing and doing.
mttModele = csl.CausalModel(mtt)
# We do(soldier A = 1) (a deliberate intervention)
cslnb.showCausalImpact(mttModele,"death",doing="captain",values={"captain":1})
Subset {soldier A, soldier B} meets the front-door criterion relative to (captain, death) because:
- 1- {soldier A, soldier B} intercepts all directed paths from "captain" to "death"
- 2- There is no back-door path from "captain" to {soldier A, soldier B}.
- 3- All back-door paths from {soldier A, soldier B} to "death" are blocked by "captain."
Consists of reasoning about hypothetical situations What would have happened if?
To answer this question we need to compare the real world where the prisoner is lying dead on the ground, A shot, B shot, the captain gave the signal to the firing squad and the court gave the order : $$death = 1 \mid soldier A = 1 \mid soldier B = 1 \mid captain=1 \mid court order = 1$$ With a counterfactual world where "$soldier A = 0$", and where the arrow leading into A is erased (since he decided on his own not to shoot we emancipate it from the effect of the captain).
mttCounterfactual = gum.BayesNet(mtt)
# The court did give the order
mttCounterfactual.cpt("court order")[:] = [0, 1]
# Soldier A decides not to shoot
mttCounterfactual.cpt("soldier A")[0,:] = [1, 0] # c=0
mttCounterfactual.cpt("soldier A")[1,:] = [1, 0] # c=1
# We emancipate soldier A
mttCounterfactual.eraseArc("captain","soldier A")
gnb.showBNDiff(mtt, mttCounterfactual, size='4')
gnb.sideBySide(mttCounterfactual,
mttCounterfactual.cpt("court order"),
mttCounterfactual.cpt("captain"),
mttCounterfactual.cpt("soldier A"),
mttCounterfactual.cpt("soldier B"),
mttCounterfactual.cpt("death"),
captions=["the BN","the marginal for $court order$","the CPT for $captain$","the CPT for $soldier A$","the CPT for $soldier B$","the CPT for $death$"])
gnb.showInference(mttCounterfactual)
Even if A decides not to shoot in the counterfactual world, the court did give the order to the captain who gave the signal to the firing squad including A who decided not to shoot, however, B shot and killed the prisoner.
Mathematically, this counterfactual is the following conditional probability: $$P(death^* \mid soldier A^*=0,soldier A=1, captain=1,court order=1,death=1)$$ where variables with an ∗ are unobserved (and unobservable) variables that live in the counterfactual world, while variables without ∗ are observable.