Skip to content

Credal Networks

Creative Commons LicenseaGrUMinteractive online version
import matplotlib.pyplot as plt
import pyagrum as gum
import pyagrum.lib.notebook as gnb
gnb.configuration()
LibraryVersion
OSposix [darwin]
Python3.14.0 (main, Oct 7 2025, 09:34:52) [Clang 17.0.0 (clang-1700.3.19.1)]
IPython9.6.0
Matplotlib3.10.7
Numpy2.3.4
pyDot4.0.1
pyAgrum2.3.0.9
Wed Oct 29 14:15:41 2025 CET
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()
cn
G B B C C B->C A A A->B D D A->D E E A->E F F D->C E->F
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 B B C C B->C A A A->B D D A->D E E A->E F F D->C E->F
Bayes Net
B
A
0
1
2
0
0.45460.38110.1643
1
0.12530.48960.3851

CPT
G B B C C B->C A A A->B D D A->D E E A->E F F D->C E->F
Credal Net
B
A
0
1
2
0
0.40450.33090.1142
1
0.07520.43940.3350

CPTmin
B
A
0
1
2
0
0.50480.43120.2144
1
0.17550.53970.4352

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)

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 B B C C B->C A A A->B D D A->D E E A->E F F D->C E->F
Credal net
G E E F F E->F A A A->E D D A->D B-b0 B-b0 A->B-b0 B-b1 B-b1 A->B-b1 B-v0 B-v0 B-v1 B-v1 B-v2 B-v2 C C D->C B-b0->B-v0 B-b0->B-v1 B-b0->B-v2 B-b0->C B-b0->B-b1 B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 B-b1->C
Binarized credal net

Here, BB becomes

  • BB-bii : the ii-th bit of B
  • instrumental BB-vkk : the indicator variable for each modality kk of BB
ie_mc = gum.CNMonteCarloSampling(cn)
ie2_lbp = gum.CNLoopyPropagation(cn2)
ie2_mc = gum.CNMonteCarloSampling(cn2)
gnb.sideBySide(
gnb.getInference(cn, engine=ie_mc), gnb.getInference(cn2, engine=ie2_mc), gnb.getInference(cn2, engine=ie2_lbp)
)
structs Inference in 518.51ms A 2025-10-29T14:15:42.549493 image/svg+xml Matplotlib v3.10.7, B 2025-10-29T14:15:42.571180 image/svg+xml Matplotlib v3.10.7, A->B D 2025-10-29T14:15:42.618328 image/svg+xml Matplotlib v3.10.7, A->D E 2025-10-29T14:15:42.635379 image/svg+xml Matplotlib v3.10.7, A->E C 2025-10-29T14:15:42.601369 image/svg+xml Matplotlib v3.10.7, B->C D->C F 2025-10-29T14:15:42.652410 image/svg+xml Matplotlib v3.10.7, E->F
structs Inference in 663.13ms A 2025-10-29T14:15:43.570453 image/svg+xml Matplotlib v3.10.7, B-b0 2025-10-29T14:15:43.589354 image/svg+xml Matplotlib v3.10.7, A->B-b0 B-b1 2025-10-29T14:15:43.607901 image/svg+xml Matplotlib v3.10.7, A->B-b1 D 2025-10-29T14:15:43.643344 image/svg+xml Matplotlib v3.10.7, A->D E 2025-10-29T14:15:43.661042 image/svg+xml Matplotlib v3.10.7, A->E B-b0->B-b1 C 2025-10-29T14:15:43.625909 image/svg+xml Matplotlib v3.10.7, B-b0->C B-v0 2025-10-29T14:15:43.695912 image/svg+xml Matplotlib v3.10.7, B-b0->B-v0 B-v1 2025-10-29T14:15:43.714165 image/svg+xml Matplotlib v3.10.7, B-b0->B-v1 B-v2 2025-10-29T14:15:43.731696 image/svg+xml Matplotlib v3.10.7, B-b0->B-v2 B-b1->C B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 D->C F 2025-10-29T14:15:43.678391 image/svg+xml Matplotlib v3.10.7, E->F
structs Inference in   0.49ms A 2025-10-29T14:15:43.919976 image/svg+xml Matplotlib v3.10.7, B-b0 2025-10-29T14:15:43.937542 image/svg+xml Matplotlib v3.10.7, A->B-b0 B-b1 2025-10-29T14:15:43.954604 image/svg+xml Matplotlib v3.10.7, A->B-b1 D 2025-10-29T14:15:43.988323 image/svg+xml Matplotlib v3.10.7, A->D E 2025-10-29T14:15:44.005292 image/svg+xml Matplotlib v3.10.7, A->E B-b0->B-b1 C 2025-10-29T14:15:43.971515 image/svg+xml Matplotlib v3.10.7, B-b0->C B-v0 2025-10-29T14:15:44.040532 image/svg+xml Matplotlib v3.10.7, B-b0->B-v0 B-v1 2025-10-29T14:15:44.057690 image/svg+xml Matplotlib v3.10.7, B-b0->B-v1 B-v2 2025-10-29T14:15:44.075496 image/svg+xml Matplotlib v3.10.7, B-b0->B-v2 B-b1->C B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 D->C F 2025-10-29T14:15:44.023066 image/svg+xml Matplotlib v3.10.7, E->F
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 B B C C B->C A A A->B D D A->D E E A->E F F D->C E->F
F
0
1
0.36420.3075
F
0
1
0.69250.6358
G B B C C B->C A A A->B D D A->D E E A->E F F D->C E->F
F
0
1
0.36420.3075
F
0
1
0.69250.6358
A:Range([0,1])
<> : [[0.564403 , 0.435597] , [0.813316 , 0.186684]]
B:Range([0,2])

<A:0> : [[0.404503 , 0.381073 , 0.214425] , [0.404503 , 0.431208 , 0.164289] , [0.454634 , 0.431208 , 0.114158] , [0.50477 , 0.381072 , 0.114158] , [0.454634 , 0.330941 , 0.214425] , [0.50477 , 0.330941 , 0.164289]] <A:1> : [[0.0752 , 0.489576 , 0.435224] , [0.0752 , 0.53971 , 0.38509] , [0.125334 , 0.53971 , 0.334956] , [0.175468 , 0.489575 , 0.334956] , [0.125335 , 0.439441 , 0.435224] , [0.175468 , 0.439441 , 0.385091]]

C:Range([0,1])

<B:0|D:0> : [[0.274878 , 0.725122] , [0.378155 , 0.621845]] <B:1|D:0> : [[0.394721 , 0.605279] , [0.497997 , 0.502003]] <B:2|D:0> : [[0.390519 , 0.609481] , [0.493797 , 0.506203]] <B:0|D:1> : [[0.373125 , 0.626875] , [0.476401 , 0.523599]] <B:1|D:1> : [[0.0774566 , 0.922543] , [0.180733 , 0.819267]] <B:2|D:1> : [[0.566948 , 0.433052] , [0.670225 , 0.329775]]

D:Range([0,1])

<A:0> : [[0.169429 , 0.830571] , [0.395333 , 0.604667]] <A:1> : [[0.192405 , 0.807595] , [0.41831 , 0.58169]]

E:Range([0,1])

<A:0> : [[0.487658 , 0.512342] , [0.594354 , 0.405646]] <A:1> : [[0.813281 , 0.186719] , [0.919977 , 0.0800234]]

F:Range([0,1])

<E:0> : [[0.494737 , 0.505263] , [0.768817 , 0.231183]] <E:1> : [[0.20556 , 0.79444] , [0.47964 , 0.52036]]

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

svg

ie = gum.CNMonteCarloSampling(cn)
ie.insertEvidenceFile("res/cn/L2U.evi")
ie.setRepetitiveInd(False)
ie.setMaxTime(1)
ie.setMaxIter(1000)
ie.makeInference()
cn
G B B E E B->E G G A A A->E F F H H F->H C C C->F L L H->L D D D->G D->F E->H
gnb.showInference(cn, targets={"A", "H", "L", "D"}, engine=ie, evs={"L": [0, 1], "G": [1, 0]})

svg

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

ie_mc = gum.CNMonteCarloSampling(cn)
ie_mc.makeInference()
cn.computeBinaryCPTMinMax()
ie_lbp = gum.CNLoopyPropagation(cn)
ie_lbp.makeInference()
showDiffInference(cn, ie_mc, ie_lbp)

svg

When evidence are inserted, there are some divergence.

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)

svg

cn = gum.CredalNet("res/cn/bn_c_8.bif", "res/cn/den_c_8.bif")
cn.bnToCredal(0.8, False)
ie = gum.CNMonteCarloSampling(cn)
ie.insertModalsFile("res/cn/modalities.modal")
ie.setRepetitiveInd(True)
ie.setMaxTime(5)
ie.setMaxIter(1000)
ie.makeInference()
print(ie.dynamicExpMax("temp"))
(14.20340464862347, 11.911090684366485, 12.0406461626149, 12.031555584857191, 12.003107180947513, 12.008870898650432, 12.007860641421736, 12.007682925808101, 12.007727248106775)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.fill_between(range(9), ie.dynamicExpMax("temp"), ie.dynamicExpMin("temp"))
plt.show()

svg

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
fig = plt.figure()
ax = fig.add_subplot(111)
ax.fill_between(range(9), ie.dynamicExpMax("temp"), ie.dynamicExpMin("temp"))
plt.show()

svg

ie = gum.CNMonteCarloSampling(cn)
ie.insertModalsFile("res/cn/modalities.modal")
ie.setRepetitiveInd(False)
ie.setMaxTime(5)
ie.setMaxIter(5000)
gnb.animApproximationScheme(ie)
ie.makeInference()

svg

fig = plt.figure()
ax = fig.add_subplot(111)
ax.fill_between(range(9), ie.dynamicExpMax("temp"), ie.dynamicExpMin("temp"))
plt.show()

svg