Credal Networks

Creative Commons License

aGrUM

interactive online version

In [1]:
%matplotlib inline
from pylab import *
import matplotlib.pyplot as plt
In [2]:
import pyagrum as gum
import pyagrum.lib.notebook as gnb

gnb.configuration()
LibraryVersion
OSposix [darwin]
Python3.13.2 (main, Feb 4 2025, 14:51:09) [Clang 16.0.0 (clang-1600.0.26.6)]
IPython9.0.2
Matplotlib3.10.1
Numpy2.2.4
pyDot3.0.4
pyAgrum2.0.0
Mon Mar 24 10:22:15 2025 CET

Credal Net from BN

In [3]:
bn = gum.fastBN("A->B[3]->C<-D<-A->E->F")
bn_min = gum.BayesNet(bn)
bn_max = gum.BayesNet(bn)
for n in bn.nodes():
  x = 0.4 * min(bn.cpt(n).min(), 1 - bn.cpt(n).max())
  bn_min.cpt(n).translate(-x)
  bn_max.cpt(n).translate(x)

cn = gum.CredalNet(bn_min, bn_max)
cn.intervalToCredal()

gnb.flow.row(
  bn, bn.cpt("B"), cn, bn_min.cpt("B"), bn_max.cpt("B"), captions=["Bayes Net", "CPT", "Credal Net", "CPTmin", "CPTmax"]
)
G C C F F A A B B A->B E E A->E D D A->D B->C E->F D->C
Bayes Net
B
A
0
1
2
0
0.27630.52250.2012
1
0.71690.00990.2732

CPT
G C C F F A A B B A->B E E A->E D D A->D B->C E->F D->C
Credal Net
B
A
0
1
2
0
0.27230.51850.1973
1
0.71300.00590.2692

CPTmin
B
A
0
1
2
0
0.28020.52640.2052
1
0.72090.01390.2771

CPTmax

We can use LBP on CN (L2U) only for binary credal networks (here B is not binary). We then propose the classical binarization (but warn the user that this leads to approximation in the inference)

In [4]:
cn2 = gum.CredalNet(bn_min, bn_max)
cn2.intervalToCredal()
cn2.approximatedBinarization()
cn2.computeBinaryCPTMinMax()

gnb.flow.row(cn, cn2, captions=["Credal net", "Binarized credal net"])
G C C F F A A B B A->B E E A->E D D A->D B->C E->F D->C
Credal net
G B-v2 B-v2 C C F F A A E E A->E B-b0 B-b0 A->B-b0 B-b1 B-b1 A->B-b1 D D A->D B-v1 B-v1 E->F B-b0->B-v2 B-b0->C B-b0->B-v1 B-v0 B-v0 B-b0->B-v0 B-b0->B-b1 B-b1->B-v2 B-b1->C B-b1->B-v1 B-b1->B-v0 D->C
Binarized credal net

Here, \(B\) becomes

  • \(B\)-b\(i\) : the \(i\)-th bit of B

  • instrumental \(B\)-v\(k\) : the indicator variable for each modality \(k\) of \(B\)

In [5]:
ie_mc = gum.CNMonteCarloSampling(cn)
ie2_lbp = gum.CNLoopyPropagation(cn2)
ie2_mc = gum.CNMonteCarloSampling(cn2)
In [6]:
gnb.sideBySide(
  gnb.getInference(cn, engine=ie_mc), gnb.getInference(cn2, engine=ie2_mc), gnb.getInference(cn2, engine=ie2_lbp)
)
structs Inference in 670.87ms A 2025-03-24T10:22:16.268633 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B 2025-03-24T10:22:16.286231 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->B D 2025-03-24T10:22:16.317784 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->D E 2025-03-24T10:22:16.332839 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->E C 2025-03-24T10:22:16.302501 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B->C D->C F 2025-03-24T10:22:16.347699 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ E->F
structs Inference in 845.21ms A 2025-03-24T10:22:17.414393 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B-b0 2025-03-24T10:22:17.432161 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->B-b0 B-b1 2025-03-24T10:22:17.451124 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->B-b1 D 2025-03-24T10:22:17.481552 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->D E 2025-03-24T10:22:17.497722 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->E B-b0->B-b1 C 2025-03-24T10:22:17.466484 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B-b0->C B-v0 2025-03-24T10:22:17.528844 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B-b0->B-v0 B-v1 2025-03-24T10:22:17.544287 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B-b0->B-v1 B-v2 2025-03-24T10:22:17.559823 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B-b0->B-v2 B-b1->C B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 D->C F 2025-03-24T10:22:17.513495 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ E->F
structs Inference in   0.50ms A 2025-03-24T10:22:17.735281 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B-b0 2025-03-24T10:22:17.751089 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->B-b0 B-b1 2025-03-24T10:22:17.766614 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->B-b1 D 2025-03-24T10:22:17.798493 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->D E 2025-03-24T10:22:17.815693 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ A->E B-b0->B-b1 C 2025-03-24T10:22:17.782412 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B-b0->C B-v0 2025-03-24T10:22:17.847550 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B-b0->B-v0 B-v1 2025-03-24T10:22:17.865764 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B-b0->B-v1 B-v2 2025-03-24T10:22:17.880774 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ B-b0->B-v2 B-b1->C B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 D->C F 2025-03-24T10:22:17.831978 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ E->F
In [7]:
gnb.sideBySide(
  ie_mc.CN(),
  ie_mc.marginalMin("F"),
  ie_mc.marginalMax("F"),
  ie_mc.CN(),
  ie2_lbp.marginalMin("F"),
  ie2_lbp.marginalMax("F"),
  ncols=3,
)
print(cn)
G C C F F A A B B A->B E E A->E D D A->D B->C E->F D->C
F
0
1
0.45520.2575
F
0
1
0.74250.5448
G C C F F A A B B A->B E E A->E D D A->D B->C E->F D->C
F
0
1
0.45520.2543
F
0
1
0.74570.5448

A:Range([0,1])
<> : [[0.0508721 , 0.949128] , [0.118701 , 0.881299]]

B:Range([0,2])
<A:0> : [[0.272306 , 0.522487 , 0.205207] , [0.272306 , 0.526444 , 0.20125] , [0.276264 , 0.526444 , 0.197292] , [0.280222 , 0.522486 , 0.197292] , [0.276263 , 0.51853 , 0.205207] , [0.280222 , 0.51853 , 0.201248]]
<A:1> : [[0.712977 , 0.00989435 , 0.277129] , [0.712977 , 0.0138504 , 0.273172] , [0.716936 , 0.0138504 , 0.269214] , [0.720892 , 0.0098943 , 0.269214] , [0.716935 , 0.00593668 , 0.277129] , [0.720892 , 0.00593668 , 0.273171]]

C:Range([0,1])
<B:0|D:0> : [[0.375199 , 0.624801] , [0.624738 , 0.375262]]
<B:1|D:0> : [[0.563307 , 0.436693] , [0.812846 , 0.187154]]
<B:2|D:0> : [[0.53187 , 0.46813] , [0.781407 , 0.218593]]
<B:0|D:1> : [[0.235162 , 0.764838] , [0.4847 , 0.5153]]
<B:1|D:1> : [[0.188552 , 0.811448] , [0.43809 , 0.56191]]
<B:2|D:1> : [[0.22119 , 0.77881] , [0.470729 , 0.529271]]

D:Range([0,1])
<A:0> : [[0.474761 , 0.525239] , [0.774898 , 0.225102]]
<A:1> : [[0.36248 , 0.63752] , [0.662617 , 0.337383]]

E:Range([0,1])
<A:0> : [[0.608869 , 0.391131] , [0.832374 , 0.167626]]
<A:1> : [[0.293474 , 0.706526] , [0.516978 , 0.483022]]

F:Range([0,1])
<E:0> : [[0.326565 , 0.673435] , [0.546482 , 0.453518]]
<E:1> : [[0.615145 , 0.384855] , [0.835062 , 0.164938]]


Credal Net from bif files

In [8]:
cn = gum.CredalNet("res/cn/2Umin.bif", "res/cn/2Umax.bif")
cn.intervalToCredal()
In [9]:
gnb.showCN(cn, "2")
../_images/notebooks_24-Models_credalNetworks_14_0.svg
In [10]:
ie = gum.CNMonteCarloSampling(cn)
ie.insertEvidenceFile("res/cn/L2U.evi")
In [11]:
ie.setRepetitiveInd(False)
ie.setMaxTime(1)
ie.setMaxIter(1000)

ie.makeInference()
In [12]:
cn
Out[12]:
G C C F F C->F H H F->H A A E E A->E B B B->E E->H L L H->L G G D D D->F D->G
In [13]:
gnb.showInference(cn, targets={"A", "H", "L", "D"}, engine=ie, evs={"L": [0, 1], "G": [1, 0]})
../_images/notebooks_24-Models_credalNetworks_18_0.svg

Comparing inference in credal networks

In [14]:
import pyagrum as gum


def showDiffInference(model, mc, lbp):
  for i in model.current_bn().nodes():
    a, b = mc.marginalMin(i)[:]
    c, d = mc.marginalMax(i)[:]

    e, f = lbp.marginalMin(i)[:]
    g, h = lbp.marginalMax(i)[:]

    plt.scatter([a, b, c, d], [e, f, g, h])


cn = gum.CredalNet("res/cn/2Umin.bif", "res/cn/2Umax.bif")
cn.intervalToCredal()

The two inference give quite the same result

In [15]:
ie_mc = gum.CNMonteCarloSampling(cn)
ie_mc.makeInference()

cn.computeBinaryCPTMinMax()
ie_lbp = gum.CNLoopyPropagation(cn)
ie_lbp.makeInference()

showDiffInference(cn, ie_mc, ie_lbp)
../_images/notebooks_24-Models_credalNetworks_22_0.svg

but not when evidence are inserted

In [16]:
ie_mc = gum.CNMonteCarloSampling(cn)
ie_mc.insertEvidenceFile("res/cn/L2U.evi")
ie_mc.makeInference()

ie_lbp = gum.CNLoopyPropagation(cn)
ie_lbp.insertEvidenceFile("res/cn/L2U.evi")
ie_lbp.makeInference()

showDiffInference(cn, ie_mc, ie_lbp)
../_images/notebooks_24-Models_credalNetworks_24_0.svg

Dynamical Credal Net

In [17]:
cn = gum.CredalNet("res/cn/bn_c_8.bif", "res/cn/den_c_8.bif")
cn.bnToCredal(0.8, False)
In [18]:
ie = gum.CNMonteCarloSampling(cn)
ie.insertModalsFile("res/cn/modalities.modal")

ie.setRepetitiveInd(True)
ie.setMaxTime(5)
ie.setMaxIter(1000)

ie.makeInference()
In [19]:
print(ie.dynamicExpMax("temp"))
(14.203404646911963, 11.630924864746593, 12.02223403338019, 11.958468951520764, 11.965797424106215, 11.964926735931694, 11.965025343870192, 11.965014533608835, 11.965015735850175)
In [20]:
fig = figure()
ax = fig.add_subplot(111)
ax.fill_between(range(9), ie.dynamicExpMax("temp"), ie.dynamicExpMin("temp"))
plt.show()
../_images/notebooks_24-Models_credalNetworks_29_0.svg
In [21]:
ie = gum.CNMonteCarloSampling(cn)
ie.insertModalsFile("res/cn/modalities.modal")

ie.setRepetitiveInd(False)
ie.setMaxTime(5)
ie.setMaxIter(1000)

ie.makeInference()
print(ie.messageApproximationScheme())
stopped with epsilon=0
In [22]:
fig = figure()
ax = fig.add_subplot(111)
ax.fill_between(range(9), ie.dynamicExpMax("temp"), ie.dynamicExpMin("temp"))
plt.show()
../_images/notebooks_24-Models_credalNetworks_31_0.svg
In [23]:
ie = gum.CNMonteCarloSampling(cn)
ie.insertModalsFile("res/cn/modalities.modal")

ie.setRepetitiveInd(False)
ie.setMaxTime(5)
ie.setMaxIter(5000)

gnb.animApproximationScheme(ie)
ie.makeInference()
../_images/notebooks_24-Models_credalNetworks_32_0.svg
In [24]:
fig = figure()
ax = fig.add_subplot(111)
ax.fill_between(range(9), ie.dynamicExpMax("temp"), ie.dynamicExpMin("temp"))
plt.show()
../_images/notebooks_24-Models_credalNetworks_33_0.svg