Skip to content

Credal Networks

Creative Commons LicenseaGrUMinteractive online version
import matplotlib.pyplot as plt
import pyagrum.credal_net 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.17.1
Matplotlib3.11.2
Numpy2.5.3
pyDot4.0.1
pyAgrum3.2.0
Mon Sep 28 17:47:26 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 E E F F E->F A A A->E D D A->D B B A->B C C D->C B->C
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 E E F F E->F A A A->E D D A->D B B A->B C C D->C B->C
Bayes Net
B
A
0
1
2
0
0.59690.37950.0236
1
0.39380.52700.0792

CPT
G E E F F E->F A A A->E D D A->D B B A->B C C D->C B->C
Credal Net
B
A
0
1
2
0
0.58740.37010.0142
1
0.38440.51750.0698

CPTmin
B
A
0
1
2
0
0.60630.38900.0331
1
0.40330.53640.0887

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 E E F F E->F A A A->E D D A->D B B A->B C C D->C B->C
Credal net
G B-b1 B-b1 B-v1 B-v1 B-b1->B-v1 B-v2 B-v2 B-b1->B-v2 B-v0 B-v0 B-b1->B-v0 C C B-b1->C E E F F E->F B-b0 B-b0 B-b0->B-b1 B-b0->B-v1 B-b0->B-v2 B-b0->B-v0 B-b0->C A A A->B-b1 A->E A->B-b0 D D A->D D->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  25.11ms A 2026-09-28T17:47:27.379862 image/svg+xml Matplotlib v3.11.2, B 2026-09-28T17:47:27.412510 image/svg+xml Matplotlib v3.11.2, A->B D 2026-09-28T17:47:27.484679 image/svg+xml Matplotlib v3.11.2, A->D E 2026-09-28T17:47:27.520900 image/svg+xml Matplotlib v3.11.2, A->E C 2026-09-28T17:47:27.449544 image/svg+xml Matplotlib v3.11.2, B->C D->C F 2026-09-28T17:47:27.561497 image/svg+xml Matplotlib v3.11.2, E->F
structs Inference in  39.26ms A 2026-09-28T17:47:28.052843 image/svg+xml Matplotlib v3.11.2, B-b0 2026-09-28T17:47:28.110020 image/svg+xml Matplotlib v3.11.2, A->B-b0 B-b1 2026-09-28T17:47:28.147811 image/svg+xml Matplotlib v3.11.2, A->B-b1 D 2026-09-28T17:47:28.204759 image/svg+xml Matplotlib v3.11.2, A->D E 2026-09-28T17:47:28.242190 image/svg+xml Matplotlib v3.11.2, A->E B-b0->B-b1 C 2026-09-28T17:47:28.173494 image/svg+xml Matplotlib v3.11.2, B-b0->C B-v0 2026-09-28T17:47:28.322323 image/svg+xml Matplotlib v3.11.2, B-b0->B-v0 B-v1 2026-09-28T17:47:28.349667 image/svg+xml Matplotlib v3.11.2, B-b0->B-v1 B-v2 2026-09-28T17:47:28.385352 image/svg+xml Matplotlib v3.11.2, B-b0->B-v2 B-b1->C B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 D->C F 2026-09-28T17:47:28.297417 image/svg+xml Matplotlib v3.11.2, E->F
structs Inference in   1.53ms A 2026-09-28T17:47:28.680839 image/svg+xml Matplotlib v3.11.2, B-b0 2026-09-28T17:47:28.721021 image/svg+xml Matplotlib v3.11.2, A->B-b0 B-b1 2026-09-28T17:47:28.757938 image/svg+xml Matplotlib v3.11.2, A->B-b1 D 2026-09-28T17:47:28.825320 image/svg+xml Matplotlib v3.11.2, A->D E 2026-09-28T17:47:28.861689 image/svg+xml Matplotlib v3.11.2, A->E B-b0->B-b1 C 2026-09-28T17:47:28.789474 image/svg+xml Matplotlib v3.11.2, B-b0->C B-v0 2026-09-28T17:47:28.942604 image/svg+xml Matplotlib v3.11.2, B-b0->B-v0 B-v1 2026-09-28T17:47:28.991330 image/svg+xml Matplotlib v3.11.2, B-b0->B-v1 B-v2 2026-09-28T17:47:29.026760 image/svg+xml Matplotlib v3.11.2, B-b0->B-v2 B-b1->C B-b1->B-v0 B-b1->B-v1 B-b1->B-v2 D->C F 2026-09-28T17:47:28.900617 image/svg+xml Matplotlib v3.11.2, 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 E E F F E->F A A A->E D D A->D B B A->B C C D->C B->C
F
0
1
0.58420.2667
F
0
1
0.73330.4158
G E E F F E->F A A A->E D D A->D B B A->B C C D->C B->C
F
0
1
0.56430.2667
F
0
1
0.73330.4357
A:Range([0,1])
<> : [[0.596302 , 0.403698] , [0.826986 , 0.173014]]
B:Range([0,2])

<A:0> : [[0.587421 , 0.379505 , 0.0330739] , [0.587421 , 0.388956 , 0.023623] , [0.596871 , 0.388956 , 0.0141732] , [0.606319 , 0.379507 , 0.0141732] , [0.59687 , 0.370056 , 0.0330739] , [0.606319 , 0.370056 , 0.0236241]] <A:1> : [[0.384359 , 0.526956 , 0.088685] , [0.384359 , 0.536406 , 0.0792351] , [0.393808 , 0.536406 , 0.0697865] , [0.403259 , 0.526955 , 0.0697865] , [0.393809 , 0.517506 , 0.088685] , [0.403259 , 0.517506 , 0.0792349]]

C:Range([0,1])

<B:0|D:0> : [[0.472727 , 0.527273] , [0.620529 , 0.379471]] <B:1|D:0> : [[0.713883 , 0.286117] , [0.861685 , 0.138315]] <B:2|D:0> : [[0.274834 , 0.725166] , [0.422636 , 0.577364]] <B:0|D:1> : [[0.741346 , 0.258654] , [0.889148 , 0.110852]] <B:1|D:1> : [[0.428827 , 0.571173] , [0.576628 , 0.423372]] <B:2|D:1> : [[0.435561 , 0.564439] , [0.583364 , 0.416636]]

D:Range([0,1])

<A:0> : [[0.691702 , 0.308298] , [0.817262 , 0.182738]] <A:1> : [[0.0941685 , 0.905832] , [0.219728 , 0.780272]]

E:Range([0,1])

<A:0> : [[0.358324 , 0.641676] , [0.471637 , 0.528363]] <A:1> : [[0.0849858 , 0.915014] , [0.198298 , 0.801702]]

F:Range([0,1])

<E:0> : [[0.801695 , 0.198305] , [0.915011 , 0.084989]] <E:1> : [[0.486038 , 0.513962] , [0.599356 , 0.400644]]

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

svg

import pyagrum.credal_net 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.203404648128334, 11.911090684366485, 12.10019505553209, 12.031555584857191, 12.003107180947513, 12.007979271958872, 12.007860641421736, 12.007652604938034, 12.007725006693335)
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