# Credal Networks

In [1]:
import os

%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.12.3 (main, Apr 9 2024, 08:09:14) [Clang 15.0.0 (clang-1500.3.9.4)]
IPython8.25.0
Matplotlib3.9.0
Numpy1.26.4
pyDot2.0.0
pyAgrum1.13.2.9
Fri Jun 07 18:03:26 2024 CEST

## 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"])

Bayes Net
B
A
0
1
2
0
0.29980.22130.4789
1
0.37000.33140.2985

CPT

Credal Net
B
A
0
1
2
0
0.21130.13280.3904
1
0.28150.24290.2100

CPTmin
B
A
0
1
2
0
0.38840.30980.5674
1
0.45860.41990.3870

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"])

Credal net

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 838.54ms A 2024-06-07T18:03:30.332680 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B 2024-06-07T18:03:30.358323 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->B D 2024-06-07T18:03:30.404529 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->D E 2024-06-07T18:03:30.420200 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->E C 2024-06-07T18:03:30.381503 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B->C D->C F 2024-06-07T18:03:30.442137 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} E->F structs Inference in 1055.93ms A 2024-06-07T18:03:31.831532 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B-b0 2024-06-07T18:03:31.847954 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->B-b0 B-b1 2024-06-07T18:03:31.870953 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->B-b1 D 2024-06-07T18:03:31.909796 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->D E 2024-06-07T18:03:31.931726 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->E B-b0->B-b1 C 2024-06-07T18:03:31.887602 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B-b0->C B-v0 2024-06-07T18:03:31.969329 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B-b0->B-v0 B-v1 2024-06-07T18:03:31.992174 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B-b0->B-v1 B-v2 2024-06-07T18:03:32.007635 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B-b0->B-v2 B-b1->C B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 D->C F 2024-06-07T18:03:31.947718 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} E->F structs Inference in   0.28ms A 2024-06-07T18:03:32.293190 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B-b0 2024-06-07T18:03:32.316753 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->B-b0 B-b1 2024-06-07T18:03:32.337668 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->B-b1 D 2024-06-07T18:03:32.378300 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->D E 2024-06-07T18:03:32.399912 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} A->E B-b0->B-b1 C 2024-06-07T18:03:32.356304 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B-b0->C B-v0 2024-06-07T18:03:32.472380 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B-b0->B-v0 B-v1 2024-06-07T18:03:32.493110 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B-b0->B-v1 B-v2 2024-06-07T18:03:32.511519 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} B-b0->B-v2 B-b1->C B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 D->C F 2024-06-07T18:03:32.415935 image/svg+xml Matplotlib v3.9.0, https://matplotlib.org/ *{stroke-linejoin: round; stroke-linecap: butt} 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)
F
0
1
0.31060.3014
F
0
1
0.69860.6894
F
0
1
0.31060.3014
F
0
1
0.69860.6894

A:Range([0,1])
<> : [[0.865546 , 0.134454] , [0.942377 , 0.057623]]

B:Range([0,2])
<A:0> : [[0.211332 , 0.22128 , 0.567388] , [0.211332 , 0.309791 , 0.478876] , [0.299845 , 0.309791 , 0.390364] , [0.388357 , 0.22128 , 0.390364] , [0.299844 , 0.132768 , 0.567388] , [0.388357 , 0.132768 , 0.478875]]
<A:1> : [[0.281532 , 0.331423 , 0.387046] , [0.281532 , 0.419935 , 0.298534] , [0.370044 , 0.419935 , 0.210021] , [0.458554 , 0.331425 , 0.210021] , [0.370043 , 0.242911 , 0.387046] , [0.458554 , 0.242911 , 0.298535]]

C:Range([0,1])
<B:0|D:0> : [[0.447533 , 0.552467] , [0.582929 , 0.417071]]
<B:1|D:0> : [[0.520944 , 0.479056] , [0.656341 , 0.343659]]
<B:2|D:0> : [[0.413253 , 0.586747] , [0.548649 , 0.451351]]
<B:0|D:1> : [[0.716776 , 0.283224] , [0.852172 , 0.147828]]
<B:1|D:1> : [[0.101547 , 0.898453] , [0.236944 , 0.763056]]
<B:2|D:1> : [[0.508691 , 0.491309] , [0.644087 , 0.355913]]

D:Range([0,1])
<A:0> : [[0.0253682 , 0.974632] , [0.059194 , 0.940806]]
<A:1> : [[0.501645 , 0.498355] , [0.535469 , 0.464531]]

E:Range([0,1])
<A:0> : [[0.235258 , 0.764742] , [0.548938 , 0.451062]]
<A:1> : [[0.359223 , 0.640777] , [0.672903 , 0.327097]]

F:Range([0,1])
<E:0> : [[0.266187 , 0.733813] , [0.621103 , 0.378897]]
<E:1> : [[0.368537 , 0.631463] , [0.723453 , 0.276547]]

## 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")
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]:
In [13]:
gnb.showInference(cn,targets={"A","H","L","D"},engine=ie,evs={"L":[0,1],"G":[1,0]})

## 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)

### 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)

## 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.20340464862347, 11.624746572528684, 12.173214728164902, 11.806818398445738, 11.930313918300863, 11.888693561594575, 11.902720501820909, 11.897993116124194, 11.899586384013908)
In [20]:
fig=figure()
ax.fill_between(range(9),ie.dynamicExpMax("temp"),ie.dynamicExpMin("temp"))
plt.show()
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.fill_between(range(9),ie.dynamicExpMax("temp"),ie.dynamicExpMin("temp"))
plt.show()
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()
In [24]:
fig=figure()