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.7 (main, Aug 5 2026, 10:29:49) [Clang 21.0.0 (clang-2100.1.1.101)]
IPython9.16.1
Matplotlib3.11.1
Numpy2.5.2
pyDot4.0.1
pyAgrum3.1.0
Tue Aug 18 12:00:01 2026 CEST
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 D D D->C E E F F E->F A A A->B A->D A->E
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 D D D->C E E F F E->F A A A->B A->D A->E
Bayes Net
B
A
0
1
2
0
0.49950.05210.4483
1
0.42350.55900.0175

CPT
G B B C C B->C D D D->C E E F F E->F A A A->B A->D A->E
Credal Net
B
A
0
1
2
0
0.49250.04510.4414
1
0.41650.55200.0105

CPTmin
B
A
0
1
2
0
0.50650.05910.4553
1
0.43050.56600.0245

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 D D D->C E E F F E->F A A A->B A->D A->E
Credal net
G B-v2 B-v2 C C D D D->C E E F F E->F A A A->D A->E B-b1 B-b1 A->B-b1 B-b0 B-b0 A->B-b0 B-v0 B-v0 B-b1->B-v2 B-b1->C B-b1->B-v0 B-v1 B-v1 B-b1->B-v1 B-b0->B-v2 B-b0->C B-b0->B-v0 B-b0->B-b1 B-b0->B-v1
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  25.03ms A 2026-08-18T12:00:02.849323 image/svg+xml Matplotlib v3.11.1, B 2026-08-18T12:00:02.888456 image/svg+xml Matplotlib v3.11.1, A->B D 2026-08-18T12:00:02.997523 image/svg+xml Matplotlib v3.11.1, A->D E 2026-08-18T12:00:03.022863 image/svg+xml Matplotlib v3.11.1, A->E C 2026-08-18T12:00:02.931764 image/svg+xml Matplotlib v3.11.1, B->C D->C F 2026-08-18T12:00:03.053213 image/svg+xml Matplotlib v3.11.1, E->F
structs Inference in  23.77ms A 2026-08-18T12:00:03.527415 image/svg+xml Matplotlib v3.11.1, B-b0 2026-08-18T12:00:03.563684 image/svg+xml Matplotlib v3.11.1, A->B-b0 B-b1 2026-08-18T12:00:03.590031 image/svg+xml Matplotlib v3.11.1, A->B-b1 D 2026-08-18T12:00:03.662676 image/svg+xml Matplotlib v3.11.1, A->D E 2026-08-18T12:00:03.699557 image/svg+xml Matplotlib v3.11.1, A->E B-b0->B-b1 C 2026-08-18T12:00:03.625067 image/svg+xml Matplotlib v3.11.1, B-b0->C B-v0 2026-08-18T12:00:03.782702 image/svg+xml Matplotlib v3.11.1, B-b0->B-v0 B-v1 2026-08-18T12:00:03.814555 image/svg+xml Matplotlib v3.11.1, B-b0->B-v1 B-v2 2026-08-18T12:00:03.848140 image/svg+xml Matplotlib v3.11.1, B-b0->B-v2 B-b1->C B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 D->C F 2026-08-18T12:00:03.740069 image/svg+xml Matplotlib v3.11.1, E->F
structs Inference in   2.45ms A 2026-08-18T12:00:04.172502 image/svg+xml Matplotlib v3.11.1, B-b0 2026-08-18T12:00:04.211086 image/svg+xml Matplotlib v3.11.1, A->B-b0 B-b1 2026-08-18T12:00:04.254806 image/svg+xml Matplotlib v3.11.1, A->B-b1 D 2026-08-18T12:00:04.335624 image/svg+xml Matplotlib v3.11.1, A->D E 2026-08-18T12:00:04.374635 image/svg+xml Matplotlib v3.11.1, A->E B-b0->B-b1 C 2026-08-18T12:00:04.295594 image/svg+xml Matplotlib v3.11.1, B-b0->C B-v0 2026-08-18T12:00:04.448576 image/svg+xml Matplotlib v3.11.1, B-b0->B-v0 B-v1 2026-08-18T12:00:04.484392 image/svg+xml Matplotlib v3.11.1, B-b0->B-v1 B-v2 2026-08-18T12:00:04.526201 image/svg+xml Matplotlib v3.11.1, B-b0->B-v2 B-b1->C B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 D->C F 2026-08-18T12:00:04.410411 image/svg+xml Matplotlib v3.11.1, 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 D D D->C E E F F E->F A A A->B A->D A->E
F
0
1
0.36610.3428
F
0
1
0.65720.6339
G B B C C B->C D D D->C E E F F E->F A A A->B A->D A->E
F
0
1
0.33590.3414
F
0
1
0.65860.6641
A:Range([0,1])
<> : [[0.467684 , 0.532316] , [0.771865 , 0.228135]]
B:Range([0,2])

<A:0> : [[0.492528 , 0.052124 , 0.455348] , [0.492528 , 0.0591216 , 0.448351] , [0.499528 , 0.0591216 , 0.44135] , [0.506527 , 0.0521224 , 0.44135] , [0.499528 , 0.0451237 , 0.455348] , [0.506527 , 0.0451237 , 0.448349]] <A:1> : [[0.416541 , 0.558962 , 0.0244969] , [0.416541 , 0.56596 , 0.0174983] , [0.423541 , 0.56596 , 0.0104987] , [0.430541 , 0.55896 , 0.0104987] , [0.423542 , 0.551961 , 0.0244969] , [0.430541 , 0.551961 , 0.0174984]]

C:Range([0,1])

<B:0|D:0> : [[0.405181 , 0.594819] , [0.41299 , 0.58701]] <B:1|D:0> : [[0.798842 , 0.201158] , [0.806649 , 0.193351]] <B:2|D:0> : [[0.504783 , 0.495217] , [0.512591 , 0.487409]] <B:0|D:1> : [[0.568387 , 0.431613] , [0.576196 , 0.423804]] <B:1|D:1> : [[0.469866 , 0.530134] , [0.477674 , 0.522326]] <B:2|D:1> : [[0.00585652 , 0.994143] , [0.0136646 , 0.986335]]

D:Range([0,1])

<A:0> : [[0.291036 , 0.708964] , [0.379995 , 0.620005]] <A:1> : [[0.0667203 , 0.93328] , [0.15568 , 0.84432]]

E:Range([0,1])

<A:0> : [[0.94357 , 0.0564304] , [0.975816 , 0.0241838]] <A:1> : [[0.417605 , 0.582395] , [0.449851 , 0.550149]]

F:Range([0,1])

<E:0> : [[0.396617 , 0.603383] , [0.684601 , 0.315399]] <E:1> : [[0.215986 , 0.784014] , [0.503971 , 0.496029]]

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 H H L L H->L B B E E B->E C C F F C->F D D G G D->G D->F E->H A A A->E F->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.203404648293022, 11.817699847864338, 12.10019505553209, 11.99476087981647, 11.966313382958862, 11.964867852223103, 11.965031829300205, 11.965013837826506, 11.965015808981818)
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

svg

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

svg