Influence diagram

Creative Commons License

aGrUM

interactive online version

In [1]:
import math

import pyagrum.influence_diagram as gum
import pyagrum.lib.notebook as gnb

Build a Influence Diagram

fast build with string

In [2]:
gum.fastID("A->*B->$C<-D<-*E->*G->H->*I<-D")
Out[2]:
A A B B A->B D D I I D->I C C D->C H H H->I B->C E E E->D G G E->G G->H

bgum format file

In [3]:
diag = gum.loadID("res/diag.bgum")
gnb.showInfluenceDiagram(diag)
../_images/notebooks_21-Models_InfluenceDiagram_6_0.svg
In [4]:
diag
Out[4]:
chanceVar1 chanceVar1 chanceVar2 chanceVar2 chanceVar1->chanceVar2 utilityVar1 utilityVar1 chanceVar1->utilityVar1 decisionVar2 decisionVar2 chanceVar2->decisionVar2 decisionVar3 decisionVar3 chanceVar2->decisionVar3 chanceVar3 chanceVar3 chanceVar5 chanceVar5 chanceVar3->chanceVar5 chanceVar4 chanceVar4 chanceVar4->chanceVar5 utilityVar2 utilityVar2 chanceVar5->utilityVar2 decisionVar1 decisionVar1 decisionVar1->chanceVar1 decisionVar2->chanceVar4 decisionVar2->utilityVar1 decisionVar3->chanceVar3 decisionVar4 decisionVar4 decisionVar4->utilityVar2

the hard way :-)

In [5]:
F = diag.addChanceNode(gum.LabelizedVariable("F", "F", 2))
diag.addArc(diag.idFromName("decisionVar1"), F)

U = diag.addUtilityNode(gum.LabelizedVariable("U", "U", 1))
diag.addArc(diag.idFromName("decisionVar3"), U)
diag.addArc(diag.idFromName("F"), U)
gnb.showInfluenceDiagram(diag)
../_images/notebooks_21-Models_InfluenceDiagram_9_0.svg
In [6]:
diag.cpt(F)[{"decisionVar1": 0}] = [0.9, 0.1]
diag.cpt(F)[{"decisionVar1": 1}] = [0.3, 0.7]

diag.utility(U)[{"F": 0, "decisionVar3": 0}] = 2
diag.utility(U)[{"F": 0, "decisionVar3": 1}] = 4
diag.utility(U)[{"F": 1}] = [[0], [5]]

Optimization in an influence diagram (actually LIMID)

In [7]:
oil = gum.loadID("res/OilWildcatter.bgum")
gnb.flow.row(oil, gnb.getInference(oil))
Out[7]:
TestResult TestResult Drilling Drilling TestResult->Drilling OilContents OilContents OilContents->TestResult Reward Reward OilContents->Reward Testing Testing Testing->TestResult Testing->Drilling Cost Cost Testing->Cost Drilling->Reward
structs MEU 22.50 (stdev=87.46) Inference in   0.24ms TestResult 2026-09-28T17:47:27.641700 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Drilling 2026-09-28T17:47:27.780169 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ TestResult->Drilling OilContents 2026-09-28T17:47:27.693346 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ OilContents->TestResult Reward Reward : 32.50 (87.46) OilContents->Reward Cost Cost : -10.00 (0.00) Testing 2026-09-28T17:47:27.746047 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Testing->TestResult Testing->Cost Testing->Drilling Drilling->Reward

Inference in the LIMID optimizing the decisions nodes

In [8]:
# a function to show results on decision nodes T and D
def show_decisions(ie):
  gnb.flow.row(
    ie.optimalDecision("Testing"),
    ie.optimalDecision("Drilling"),
    f"$${ie.MEU()['mean']:5.3f}\\ (stdev : {math.sqrt(ie.MEU()['variance']):5.3f})$$",
    captions=["Strategy for T", "Strategy for D", "MEU and its standard deviation"],
  )
  gnb.flow.row(
    ie.posterior("Testing"),
    ie.posteriorUtility("Testing"),
    ie.posterior("Drilling"),
    ie.posteriorUtility("Drilling"),
    captions=[
      "Final decision for Testing",
      "Final reward for Testing",
      "Final decision for Drilling",
      "Final reward for Drilling",
    ],
  )


ie = gum.ShaferShenoyLIMIDInference(oil)
ie.makeInference()
show_decisions(ie)

Graphical inference with evidence and targets (developped nodes)

In [9]:
gnb.sideBySide(
  oil,
  gnb.getInference(oil, evs={"TestResult": "closed"}),
  gnb.getInference(oil, evs={"TestResult": "open"}),
  gnb.getInference(oil, evs={"TestResult": "diffuse"}),
  oil,
  gnb.getInference(oil, evs={"OilContents": "Dry"}),
  gnb.getInference(oil, evs={"OilContents": "Wet"}),
  gnb.getInference(oil, evs={"OilContents": "Soaking"}),
  ncols=4,
)
TestResult TestResult Drilling Drilling TestResult->Drilling OilContents OilContents OilContents->TestResult Reward Reward OilContents->Reward Testing Testing Testing->TestResult Testing->Drilling Cost Cost Testing->Cost Drilling->Reward
structs MEU 77.50 (stdev=104.73) Inference in   0.19ms TestResult 2026-09-28T17:47:28.361770 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Drilling 2026-09-28T17:47:28.481222 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ TestResult->Drilling OilContents 2026-09-28T17:47:28.403692 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ OilContents->TestResult Reward Reward : 87.50 (104.73) OilContents->Reward Cost Cost : -10.00 (0.00) Testing 2026-09-28T17:47:28.447683 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Testing->TestResult Testing->Cost Testing->Drilling Drilling->Reward
structs MEU 22.86 (stdev=104.98) Inference in   0.21ms TestResult 2026-09-28T17:47:28.780169 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Drilling 2026-09-28T17:47:28.923243 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ TestResult->Drilling OilContents 2026-09-28T17:47:28.830008 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ OilContents->TestResult Reward Reward : 32.86 (104.98) OilContents->Reward Cost Cost : -10.00 (0.00) Testing 2026-09-28T17:47:28.880561 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Testing->TestResult Testing->Cost Testing->Drilling Drilling->Reward
structs MEU 20.00 (stdev=103.92) Inference in   0.21ms TestResult 2026-09-28T17:47:29.268854 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Drilling 2026-09-28T17:47:29.380326 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ TestResult->Drilling OilContents 2026-09-28T17:47:29.310080 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ OilContents->TestResult Reward Reward : 20.00 (103.92) OilContents->Reward Cost Cost : 0.00 (0.00) Testing 2026-09-28T17:47:29.345412 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Testing->TestResult Testing->Cost Testing->Drilling Drilling->Reward
TestResult TestResult Drilling Drilling TestResult->Drilling OilContents OilContents OilContents->TestResult Reward Reward OilContents->Reward Testing Testing Testing->TestResult Testing->Drilling Cost Cost Testing->Cost Drilling->Reward
structs MEU 0.00 (stdev=0.00) Inference in   0.22ms TestResult 2026-09-28T17:47:29.647420 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Drilling 2026-09-28T17:47:29.734582 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ TestResult->Drilling OilContents 2026-09-28T17:47:29.680953 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ OilContents->TestResult Reward Reward : 0.00 (0.00) OilContents->Reward Cost Cost : 0.00 (0.00) Testing 2026-09-28T17:47:29.712412 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Testing->TestResult Testing->Cost Testing->Drilling Drilling->Reward
structs MEU 50.00 (stdev=0.00) Inference in   0.22ms TestResult 2026-09-28T17:47:30.001556 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Drilling 2026-09-28T17:47:30.122978 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ TestResult->Drilling OilContents 2026-09-28T17:47:30.047160 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ OilContents->TestResult Reward Reward : 50.00 (0.00) OilContents->Reward Cost Cost : 0.00 (0.00) Testing 2026-09-28T17:47:30.087707 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Testing->TestResult Testing->Cost Testing->Drilling Drilling->Reward
structs MEU 200.00 (stdev=0.00) Inference in   0.23ms TestResult 2026-09-28T17:47:30.500955 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Drilling 2026-09-28T17:47:30.619645 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ TestResult->Drilling OilContents 2026-09-28T17:47:30.549034 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ OilContents->TestResult Reward Reward : 200.00 (0.00) OilContents->Reward Cost Cost : 0.00 (0.00) Testing 2026-09-28T17:47:30.592192 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Testing->TestResult Testing->Cost Testing->Drilling Drilling->Reward

Soft evidence on chance node

In [10]:
gnb.showInference(oil, evs={"OilContents": [0.7, 0.5, 0.8]})
../_images/notebooks_21-Models_InfluenceDiagram_18_0.svg

Forced decision

In [11]:
gnb.showInference(oil, evs={"Drilling": "Yes"})
../_images/notebooks_21-Models_InfluenceDiagram_20_0.svg

LIMID versus Influence Diagram

The default inference for influence diagram actually an inference for LIMIDs. In order to use it for classical (and solvable) influence diagram, do not forget to add the sequence of decision nodes using addNoForgettingAssumption.

In [12]:
infdiag = gum.fastID("Chance->*Decision1->Chance2->$Utility<-Chance3<-*Decision2<-Chance->Utility")
infdiag
Out[12]:
Chance Chance Decision1 Decision1 Chance->Decision1 Decision2 Decision2 Chance->Decision2 Utility Utility Chance->Utility Chance2 Chance2 Chance2->Utility Chance3 Chance3 Chance3->Utility Decision1->Chance2 Decision2->Chance3
In [13]:
ie = gum.ShaferShenoyLIMIDInference(infdiag)
try:
  ie.makeInference()
except gum.GumException as e:
  print(e)
[pyAgrum] Fatal error: This LIMID/Influence Diagram is not solvable.
In [14]:
ie.addNoForgettingAssumption(["Decision1", "Decision2"])
gnb.sideBySide(ie.reducedLIMID(), ie.junctionTree(), gnb.getInference(infdiag, engine=ie))
Chance Chance Decision1 Decision1 Chance->Decision1 Decision2 Decision2 Chance->Decision2 Utility Utility Chance->Utility Chance2 Chance2 Chance2->Utility Chance3 Chance3 Chance3->Utility Decision1->Chance2 Decision1->Decision2 Decision2->Chance3
InfluenceDiagram Chance-Chance2-Decision1-Decision2 (0):Chance,Chance2,Decision1,Decision2 Chance-Chance2-Decision1-Decision2+Chance-Chance2-Chance3-Decision2 Chance,Chance2,Decision2 Chance-Chance2-Decision1-Decision2--Chance-Chance2-Decision1-Decision2+Chance-Chance2-Chance3-Decision2 Chance-Chance2-Chance3-Decision2 (1):Chance,Chance2,Chance3,Decision2 Chance-Chance2-Decision1-Decision2+Chance-Chance2-Chance3-Decision2--Chance-Chance2-Chance3-Decision2
structs MEU 6.70 (stdev=17.22) Inference in   0.24ms Chance 2026-09-28T17:47:32.823754 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Decision1 2026-09-28T17:47:32.866525 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Chance->Decision1 Utility Utility : 6.70 (17.22) Chance->Utility Decision2 2026-09-28T17:47:32.981448 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Chance->Decision2 Chance2 2026-09-28T17:47:32.912674 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Decision1->Chance2 Chance2->Utility Chance3 2026-09-28T17:47:32.951683 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Chance3->Utility Decision2->Chance3

Customizing visualization of the results

Using pyagrum.config, it is possible to adapt the graphical representations for Influence Diagram (see the notebook 99-Tools_configForPyAgrum.ipynb).

In [15]:
gum.config.reset()
gnb.showInference(infdiag, engine=ie, size="7!")
../_images/notebooks_21-Models_InfluenceDiagram_26_0.svg

Many visual options can be changed when displaing an inference (especially for influence diagrams)

In [16]:
# do not show inference time
gum.config["notebook", "show_inference_time"] = False
# more digits for probabilities
gum.config["notebook", "histogram_horizontal_visible_digits"] = 3

gnb.showInference(infdiag, engine=ie, size="7!")
../_images/notebooks_21-Models_InfluenceDiagram_28_0.svg
In [17]:
# specificic for influence diagram :
# more digits for utilities
gum.config["influenceDiagram", "utility_visible_digits"] = 5
# disabling stdev for utility and MEU
gum.config["influenceDiagram", "utility_show_stdev"] = False
# showing loss (=-utility) and mEL (minimum Expected Loss) instead of MEU
gum.config["influenceDiagram", "utility_show_loss"] = True

gnb.showInference(infdiag, engine=ie, size="7!")
../_images/notebooks_21-Models_InfluenceDiagram_29_0.svg
In [18]:
# visual changes for influence diagram and inference
gum.config.reset()
gum.config.push()  # keep the current state
gum.config["notebook", "graph_rankdir"] = "LR"
gnb.sideBySide(infdiag, gnb.getInference(infdiag, engine=ie, targets=["Decision1", "Chance3"]))
Chance Chance Decision1 Decision1 Chance->Decision1 Decision2 Decision2 Chance->Decision2 Utility Utility Chance->Utility Chance2 Chance2 Chance2->Utility Chance3 Chance3 Chance3->Utility Decision1->Chance2 Decision2->Chance3
structs MEU 6.70 (stdev=17.22) Inference in   0.86ms Chance Chance Decision1 2026-09-28T17:47:35.141248 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Chance->Decision1 Utility Utility : 6.70 (17.22) Chance->Utility Decision2 Decision2 Chance->Decision2 Chance2 Chance2 Decision1->Chance2 Chance2->Utility Chance3 2026-09-28T17:47:35.173045 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Chance3->Utility Decision2->Chance3
In [19]:
# more visual changes for influence diagram and inference
gum.config.pop()  # back to the last state

# shape (https://graphviz.org/doc/info/shapes.html)
gum.config["influenceDiagram", "chance_shape"] = "cylinder"
gum.config["influenceDiagram", "utility_shape"] = "star"
gum.config["influenceDiagram", "decision_shape"] = "box3d"

# colors
gum.config["influenceDiagram", "default_chance_bgcolor"] = "green"
gum.config["influenceDiagram", "default_utility_bgcolor"] = "MediumVioletRed"
gum.config["influenceDiagram", "default_decision_bgcolor"] = "DarkSalmon"

gum.config["influenceDiagram", "utility_show_stdev"] = False

gnb.sideBySide(infdiag, gnb.getInference(infdiag, engine=ie, targets=["Decision1", "Chance3"]))
Chance Chance Decision1 Decision1 Chance->Decision1 Decision2 Decision2 Chance->Decision2 Utility Utility Chance->Utility Chance2 Chance2 Chance2->Utility Chance3 Chance3 Chance3->Utility Decision1->Chance2 Decision2->Chance3
structs MEU 6.70 Inference in   0.27ms Chance Chance Decision1 2026-09-28T17:47:35.829143 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Chance->Decision1 Utility Utility : 6.70 Chance->Utility Decision2 Decision2 Chance->Decision2 Chance2 Chance2 Decision1->Chance2 Chance2->Utility Chance3 2026-09-28T17:47:35.871239 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ Chance3->Utility Decision2->Chance3
In [ ]: