pyAgrum-nightly 2.3.0.9.dev202512061764412981__cp310-abi3-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. pyagrum/__init__.py +165 -0
  2. pyagrum/_pyagrum.so +0 -0
  3. pyagrum/bnmixture/BNMInference.py +268 -0
  4. pyagrum/bnmixture/BNMLearning.py +376 -0
  5. pyagrum/bnmixture/BNMixture.py +464 -0
  6. pyagrum/bnmixture/__init__.py +60 -0
  7. pyagrum/bnmixture/notebook.py +1058 -0
  8. pyagrum/causal/_CausalFormula.py +280 -0
  9. pyagrum/causal/_CausalModel.py +436 -0
  10. pyagrum/causal/__init__.py +81 -0
  11. pyagrum/causal/_causalImpact.py +356 -0
  12. pyagrum/causal/_dSeparation.py +598 -0
  13. pyagrum/causal/_doAST.py +761 -0
  14. pyagrum/causal/_doCalculus.py +361 -0
  15. pyagrum/causal/_doorCriteria.py +374 -0
  16. pyagrum/causal/_exceptions.py +95 -0
  17. pyagrum/causal/_types.py +61 -0
  18. pyagrum/causal/causalEffectEstimation/_CausalEffectEstimation.py +1175 -0
  19. pyagrum/causal/causalEffectEstimation/_IVEstimators.py +718 -0
  20. pyagrum/causal/causalEffectEstimation/_RCTEstimators.py +132 -0
  21. pyagrum/causal/causalEffectEstimation/__init__.py +46 -0
  22. pyagrum/causal/causalEffectEstimation/_backdoorEstimators.py +774 -0
  23. pyagrum/causal/causalEffectEstimation/_causalBNEstimator.py +324 -0
  24. pyagrum/causal/causalEffectEstimation/_frontdoorEstimators.py +396 -0
  25. pyagrum/causal/causalEffectEstimation/_learners.py +118 -0
  26. pyagrum/causal/causalEffectEstimation/_utils.py +466 -0
  27. pyagrum/causal/notebook.py +171 -0
  28. pyagrum/clg/CLG.py +658 -0
  29. pyagrum/clg/GaussianVariable.py +111 -0
  30. pyagrum/clg/SEM.py +312 -0
  31. pyagrum/clg/__init__.py +63 -0
  32. pyagrum/clg/canonicalForm.py +408 -0
  33. pyagrum/clg/constants.py +54 -0
  34. pyagrum/clg/forwardSampling.py +202 -0
  35. pyagrum/clg/learning.py +776 -0
  36. pyagrum/clg/notebook.py +480 -0
  37. pyagrum/clg/variableElimination.py +271 -0
  38. pyagrum/common.py +60 -0
  39. pyagrum/config.py +319 -0
  40. pyagrum/ctbn/CIM.py +513 -0
  41. pyagrum/ctbn/CTBN.py +573 -0
  42. pyagrum/ctbn/CTBNGenerator.py +216 -0
  43. pyagrum/ctbn/CTBNInference.py +459 -0
  44. pyagrum/ctbn/CTBNLearner.py +161 -0
  45. pyagrum/ctbn/SamplesStats.py +671 -0
  46. pyagrum/ctbn/StatsIndepTest.py +355 -0
  47. pyagrum/ctbn/__init__.py +79 -0
  48. pyagrum/ctbn/constants.py +54 -0
  49. pyagrum/ctbn/notebook.py +264 -0
  50. pyagrum/defaults.ini +199 -0
  51. pyagrum/deprecated.py +95 -0
  52. pyagrum/explain/_ComputationCausal.py +75 -0
  53. pyagrum/explain/_ComputationConditional.py +48 -0
  54. pyagrum/explain/_ComputationMarginal.py +48 -0
  55. pyagrum/explain/_CustomShapleyCache.py +110 -0
  56. pyagrum/explain/_Explainer.py +176 -0
  57. pyagrum/explain/_Explanation.py +70 -0
  58. pyagrum/explain/_FIFOCache.py +54 -0
  59. pyagrum/explain/_ShallCausalValues.py +204 -0
  60. pyagrum/explain/_ShallConditionalValues.py +155 -0
  61. pyagrum/explain/_ShallMarginalValues.py +155 -0
  62. pyagrum/explain/_ShallValues.py +296 -0
  63. pyagrum/explain/_ShapCausalValues.py +208 -0
  64. pyagrum/explain/_ShapConditionalValues.py +126 -0
  65. pyagrum/explain/_ShapMarginalValues.py +191 -0
  66. pyagrum/explain/_ShapleyValues.py +298 -0
  67. pyagrum/explain/__init__.py +81 -0
  68. pyagrum/explain/_explGeneralizedMarkovBlanket.py +152 -0
  69. pyagrum/explain/_explIndependenceListForPairs.py +146 -0
  70. pyagrum/explain/_explInformationGraph.py +264 -0
  71. pyagrum/explain/notebook/__init__.py +54 -0
  72. pyagrum/explain/notebook/_bar.py +142 -0
  73. pyagrum/explain/notebook/_beeswarm.py +174 -0
  74. pyagrum/explain/notebook/_showShapValues.py +97 -0
  75. pyagrum/explain/notebook/_waterfall.py +220 -0
  76. pyagrum/explain/shapley.py +225 -0
  77. pyagrum/lib/__init__.py +46 -0
  78. pyagrum/lib/_colors.py +390 -0
  79. pyagrum/lib/bn2graph.py +299 -0
  80. pyagrum/lib/bn2roc.py +1026 -0
  81. pyagrum/lib/bn2scores.py +217 -0
  82. pyagrum/lib/bn_vs_bn.py +605 -0
  83. pyagrum/lib/cn2graph.py +305 -0
  84. pyagrum/lib/discreteTypeProcessor.py +1102 -0
  85. pyagrum/lib/discretizer.py +58 -0
  86. pyagrum/lib/dynamicBN.py +390 -0
  87. pyagrum/lib/explain.py +57 -0
  88. pyagrum/lib/export.py +84 -0
  89. pyagrum/lib/id2graph.py +258 -0
  90. pyagrum/lib/image.py +387 -0
  91. pyagrum/lib/ipython.py +307 -0
  92. pyagrum/lib/mrf2graph.py +471 -0
  93. pyagrum/lib/notebook.py +1821 -0
  94. pyagrum/lib/proba_histogram.py +552 -0
  95. pyagrum/lib/utils.py +138 -0
  96. pyagrum/pyagrum.py +31495 -0
  97. pyagrum/skbn/_MBCalcul.py +242 -0
  98. pyagrum/skbn/__init__.py +49 -0
  99. pyagrum/skbn/_learningMethods.py +282 -0
  100. pyagrum/skbn/_utils.py +297 -0
  101. pyagrum/skbn/bnclassifier.py +1014 -0
  102. pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/LICENSE.md +12 -0
  103. pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/LICENSES/LGPL-3.0-or-later.txt +304 -0
  104. pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/LICENSES/MIT.txt +18 -0
  105. pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/METADATA +145 -0
  106. pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/RECORD +107 -0
  107. pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/WHEEL +4 -0
@@ -0,0 +1,58 @@
1
+ ############################################################################
2
+ # This file is part of the aGrUM/pyAgrum library. #
3
+ # #
4
+ # Copyright (c) 2005-2025 by #
5
+ # - Pierre-Henri WUILLEMIN(_at_LIP6) #
6
+ # - Christophe GONZALES(_at_AMU) #
7
+ # #
8
+ # The aGrUM/pyAgrum library is free software; you can redistribute it #
9
+ # and/or modify it under the terms of either : #
10
+ # #
11
+ # - the GNU Lesser General Public License as published by #
12
+ # the Free Software Foundation, either version 3 of the License, #
13
+ # or (at your option) any later version, #
14
+ # - the MIT license (MIT), #
15
+ # - or both in dual license, as here. #
16
+ # #
17
+ # (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) #
18
+ # #
19
+ # This aGrUM/pyAgrum library is distributed in the hope that it will be #
20
+ # useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #
21
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS #
22
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
23
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
24
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, #
25
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
26
+ # OTHER DEALINGS IN THE SOFTWARE. #
27
+ # #
28
+ # See LICENCES for more details. #
29
+ # #
30
+ # SPDX-FileCopyrightText: Copyright 2005-2025 #
31
+ # - Pierre-Henri WUILLEMIN(_at_LIP6) #
32
+ # - Christophe GONZALES(_at_AMU) #
33
+ # SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
34
+ # #
35
+ # Contact : info_at_agrum_dot_org #
36
+ # homepage : http://agrum.gitlab.io #
37
+ # gitlab : https://gitlab.com/agrumery/agrum #
38
+ # #
39
+ ############################################################################
40
+
41
+ """
42
+ This module contains the deprecated Discretizer class. See the new DiscreteTypeProcessor class.
43
+ """
44
+
45
+ import warnings
46
+
47
+
48
+ def Discretizer(*args, **kwargs):
49
+ """
50
+ Warnings
51
+ ------
52
+ DeprecationWarning
53
+ If the function is called it warns the deprecation of this class, creates a discreteTypeProcessor object and returns it.
54
+ """
55
+ warnings.warn("Discretizer is deprecated since pyAgrum>=2.0.0. Use DiscreteTypeProcessor instead", DeprecationWarning)
56
+ from .discreteTypeProcessor import DiscreteTypeProcessor
57
+
58
+ return DiscreteTypeProcessor(*args, **kwargs)
@@ -0,0 +1,390 @@
1
+ ############################################################################
2
+ # This file is part of the aGrUM/pyAgrum library. #
3
+ # #
4
+ # Copyright (c) 2005-2025 by #
5
+ # - Pierre-Henri WUILLEMIN(_at_LIP6) #
6
+ # - Christophe GONZALES(_at_AMU) #
7
+ # #
8
+ # The aGrUM/pyAgrum library is free software; you can redistribute it #
9
+ # and/or modify it under the terms of either : #
10
+ # #
11
+ # - the GNU Lesser General Public License as published by #
12
+ # the Free Software Foundation, either version 3 of the License, #
13
+ # or (at your option) any later version, #
14
+ # - the MIT license (MIT), #
15
+ # - or both in dual license, as here. #
16
+ # #
17
+ # (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) #
18
+ # #
19
+ # This aGrUM/pyAgrum library is distributed in the hope that it will be #
20
+ # useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #
21
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS #
22
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
23
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
24
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, #
25
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
26
+ # OTHER DEALINGS IN THE SOFTWARE. #
27
+ # #
28
+ # See LICENCES for more details. #
29
+ # #
30
+ # SPDX-FileCopyrightText: Copyright 2005-2025 #
31
+ # - Pierre-Henri WUILLEMIN(_at_LIP6) #
32
+ # - Christophe GONZALES(_at_AMU) #
33
+ # SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
34
+ # #
35
+ # Contact : info_at_agrum_dot_org #
36
+ # homepage : http://agrum.gitlab.io #
37
+ # gitlab : https://gitlab.com/agrumery/agrum #
38
+ # #
39
+ ############################################################################
40
+
41
+ """
42
+ The purpose of this module is to provide basic tools for dealing with dynamic Bayesian Network (and inference) : modeling, visualisation, inference.
43
+ """
44
+
45
+ import numpy as np
46
+ import pydot as dot
47
+
48
+ import matplotlib.pyplot as plt
49
+ from matplotlib.patches import Rectangle
50
+
51
+ import pyagrum as gum
52
+
53
+ noTimeCluster = "void"
54
+
55
+
56
+ def _splitName(name):
57
+ """
58
+ By convention, name of dynamic variable "X" in dBN may be
59
+ - "X0" for timeslice 0 both in unrolled BN and in 2TBN
60
+ - "Xt" for timeslice t in a 2TBN
61
+ - "X"+str(i) for timelice i with integer i>0 in unrolled BN
62
+ - other naes are not in a timeslice
63
+ @argument name : str (name of the dynamic variable)
64
+ @return static_name,timeslice with timeslice =noTimeCluster,"t" or str(i)
65
+ """
66
+ if name[-1] == "t":
67
+ return name[:-1], "t"
68
+ i = len(name) - 1
69
+ if not name[i].isdigit():
70
+ return name, noTimeCluster
71
+
72
+ while name[i].isdigit():
73
+ if i == 0:
74
+ return name, noTimeCluster
75
+ i -= 1
76
+
77
+ return name[: i + 1], name[i + 1 :]
78
+
79
+
80
+ def _isInFirstTimeSlice(name):
81
+ """
82
+ @return true if there is a 0 at the end of name
83
+ """
84
+ return name[-1] == "0"
85
+
86
+
87
+ def _isInSecondTimeSlice(name):
88
+ """
89
+ @return true if there is a t at the end of name
90
+ """
91
+ return name[-1] == "t"
92
+
93
+
94
+ def _isInNoTimeSlice(name):
95
+ return name[-1] not in ["0", "t"]
96
+
97
+
98
+ def realNameFrom2TBNname(name, ts):
99
+ """
100
+ @return dynamic name from static name and timeslice (no check)
101
+ """
102
+ return f"{name[:-1]}{ts}" if not _isInNoTimeSlice(name) else name
103
+
104
+
105
+ def getTimeSlicesRange(dbn):
106
+ """
107
+ get the range and (name,radical) of each variables
108
+
109
+ Parameters
110
+ ----------
111
+ dbn: gum.BayesNet
112
+ a 2TBN or an unrolled BN
113
+
114
+
115
+ Returns
116
+ ------
117
+ Dict[str,List[T[str,str]]]
118
+ all the timeslice of a dbn : ['0','t'] for a classic 2TBN, range(T) for a classic unrolled BN
119
+ """
120
+ timeslices = {}
121
+
122
+ for i in dbn.nodes():
123
+ n = dbn.variable(i).name()
124
+ label, ts = _splitName(n)
125
+ if ts in timeslices:
126
+ timeslices[ts].append((n, label))
127
+ else:
128
+ timeslices[ts] = [(n, label)]
129
+
130
+ return timeslices
131
+
132
+
133
+ def is2TBN(bn):
134
+ """
135
+ Check if bn is a 2 TimeSlice Bayesian network
136
+
137
+ Parameters
138
+ ----------
139
+ bn: pyagrum.BayesNet
140
+ the Bayesian network
141
+
142
+ Returns
143
+ -------
144
+ bool
145
+ True if the BN is syntaxically correct to be a 2TBN
146
+ """
147
+ ts = getTimeSlicesRange(bn)
148
+ if not set(ts.keys()) <= {noTimeCluster, "0", "t"}:
149
+ return False, "Some variables are not correctly suffixed."
150
+
151
+ domainSizes = dict()
152
+ for name, radical in ts["t"]:
153
+ domainSizes[radical] = bn.variable(name).domainSize()
154
+
155
+ res = ""
156
+ for name, radical in ts["0"]:
157
+ if radical in domainSizes:
158
+ if domainSizes[radical] != bn.variable(name).domainSize():
159
+ res = f"\n - for variables {name}/{radical}t"
160
+
161
+ if res != "":
162
+ return False, "Domain size mismatch : " + res
163
+
164
+ return True, ""
165
+
166
+
167
+ def _TimeSlicesToDot(dbn):
168
+ """
169
+ Try to correctly represent dBN and 2TBN in dot format
170
+
171
+ Parameters
172
+ ----------
173
+ dbn: pyagrum.BayesNet
174
+ a 2TBN or an unrolled BN
175
+ """
176
+ timeslices = getTimeSlicesRange(dbn)
177
+ kts = sorted(timeslices.keys(), key=lambda x: -1 if x == noTimeCluster else 1e8 if x == "t" else int(x))
178
+
179
+ # dynamic member makes pylink unhappy
180
+ # pylint: disable=no-member
181
+ g = dot.Dot(graph_type="digraph")
182
+ g.set_rankdir("LR")
183
+ g.set_splines("ortho")
184
+ g.set_node_defaults(color="#000000", fillcolor="white", style="filled")
185
+
186
+ for k in kts:
187
+ if k != noTimeCluster:
188
+ cluster = dot.Cluster(k, label=f"Time slice {k}", bgcolor="#DDDDDD", rankdir="same")
189
+ g.add_subgraph(cluster)
190
+ else:
191
+ cluster = g # small trick to add in graph variable in no timeslice
192
+ for n, label in sorted(timeslices[k]):
193
+ cluster.add_node(dot.Node('"' + n + '"', label='"' + label + '"'))
194
+
195
+ g.set_edge_defaults(color="blue", constraint="False")
196
+ for tail, head in dbn.arcs():
197
+ g.add_edge(dot.Edge('"' + dbn.variable(tail).name() + '"', '"' + dbn.variable(head).name() + '"'))
198
+
199
+ g.set_edge_defaults(style="invis", constraint="True")
200
+ for x in timeslices["0"]:
201
+ name = x[1]
202
+ prec = None
203
+ for k in kts:
204
+ if k == noTimeCluster:
205
+ continue
206
+ if prec is not None:
207
+ g.add_edge(dot.Edge(f'"{name}{prec}"', f'"{name}{k}"'))
208
+ prec = k
209
+
210
+ return g
211
+
212
+
213
+ def showTimeSlices(dbn, size=None):
214
+ """
215
+ Try to correctly display dBN and 2TBN
216
+
217
+ Parameters
218
+ ----------
219
+ dbn: pyagrum.BayesNet
220
+ a 2TBN or an unrolled BN
221
+ size: int or str
222
+ size of the fig
223
+ """
224
+
225
+ # jupyter notebooks is optional
226
+ # pylint: disable=import-outside-toplevel
227
+ from pyagrum.lib.notebook import showGraph
228
+
229
+ if size is None:
230
+ size = gum.config["dynamicBN", "default_graph_size"]
231
+
232
+ showGraph(_TimeSlicesToDot(dbn), size)
233
+
234
+
235
+ def getTimeSlices(dbn, size=None):
236
+ """
237
+ Try to correctly represent dBN and 2TBN as an HTML string
238
+
239
+ Parameters
240
+ ----------
241
+ dbn: pyagrum.BayesNet
242
+ a 2TBN or an unrolled BN
243
+ size: int or str
244
+ size of the fig
245
+ """
246
+ # jupyter notebooks is optional
247
+ # pylint: disable=import-outside-toplevel
248
+ from pyagrum.lib.notebook import getGraph
249
+
250
+ if size is None:
251
+ size = gum.config["dynamicBN", "default_graph_size"]
252
+
253
+ return getGraph(_TimeSlicesToDot(dbn), size)
254
+
255
+
256
+ def unroll2TBN(dbn, nbr):
257
+ """
258
+ unroll a 2TBN given the nbr of timeslices
259
+
260
+ Parameters
261
+ ----------
262
+ dbn: pyagrum.BayesNet
263
+ a 2TBN or an unrolled BN
264
+ nbr: int
265
+ the number of timeslice
266
+
267
+ Returns
268
+ -------
269
+ pyagrum.BayesNet
270
+ unrolled BN from a 2TBN and the nbr of timeslices
271
+ """
272
+ ts = getTimeSlicesRange(dbn)
273
+ if not {noTimeCluster, "0", "t"}.issuperset(ts.keys()) and {"0", "t"}.issubset(ts.keys()):
274
+ raise TypeError("unroll2TBN needs a 2-TimeSlice BN")
275
+
276
+ bn = gum.BayesNet()
277
+
278
+ # variable creation
279
+ for dbn_id in dbn.nodes():
280
+ name = dbn.variable(dbn_id).name()
281
+ if _isInNoTimeSlice(name):
282
+ bn.add(dbn.variable(dbn_id))
283
+ elif _isInFirstTimeSlice(name):
284
+ # create a clone of the variable in the new bn
285
+ bn.add(dbn.variable(dbn_id))
286
+ else:
287
+ for ts in range(1, nbr):
288
+ # create a clone of the variable in the new bn
289
+ nid = bn.add(dbn.variable(dbn_id))
290
+ bn.changeVariableName(nid, realNameFrom2TBNname(name, ts)) # create the true name
291
+
292
+ # add parents
293
+ # the main pb : to have the same order for parents w.r.t the order in 2TBN
294
+ for dbn_id in dbn.nodes():
295
+ name = dbn.variable(dbn_id).name()
296
+ # right order for parents
297
+ lvarnames = list(reversed(dbn.cpt(dbn_id).names))
298
+ lvarnames.pop() # remove the node itself, parents remain
299
+ lvarnames.reverse()
300
+
301
+ for name_parent in lvarnames:
302
+ if not _isInSecondTimeSlice(name):
303
+ if not _isInSecondTimeSlice(name_parent):
304
+ bn.addArc(bn.idFromName(name_parent), bn.idFromName(name))
305
+ else:
306
+ if _isInFirstTimeSlice(name):
307
+ raise TypeError("An arc from timeslice t to timeslice is impossible in dBN")
308
+ for ts in range(1, nbr):
309
+ new_name_parent = realNameFrom2TBNname(name_parent, ts) # current TimeSlice
310
+ bn.addArc(bn.idFromName(new_name_parent), bn.idFromName(name))
311
+ else:
312
+ for ts in range(1, nbr):
313
+ if _isInFirstTimeSlice(name_parent):
314
+ new_name_parent = realNameFrom2TBNname(name_parent, ts - 1) # last TimeSlice
315
+ else:
316
+ new_name_parent = realNameFrom2TBNname(name_parent, ts) # current TimeSlice
317
+ new_name = realNameFrom2TBNname(name, ts) # necessary current TimeSlice
318
+ bn.addArc(bn.idFromName(new_name_parent), bn.idFromName(new_name))
319
+
320
+ # tensor creation
321
+ for dbn_id in dbn.nodes():
322
+ name = dbn.variable(dbn_id).name()
323
+ if not _isInSecondTimeSlice(name):
324
+ bn.cpt(bn.idFromName(name))[:] = dbn.cpt(dbn_id)[:]
325
+ else:
326
+ for ts in range(1, nbr):
327
+ bn.cpt(bn.idFromName(realNameFrom2TBNname(name, ts)))[:] = dbn.cpt(dbn_id)[:]
328
+
329
+ return bn
330
+
331
+
332
+ def plotFollowUnrolled(lovars, dbn, T, evs, vars_title=None):
333
+ """
334
+ plot the dynamic evolution of a list of vars with a dBN
335
+
336
+ :param lovars: list of variables to follow
337
+ :param dbn: the unrolled dbn
338
+ :param T: the time range
339
+ :param evs: observations
340
+ :param vars_title: string for default or a dictionary with the variable name as key and the respective title as value.
341
+ """
342
+ ie = gum.LazyPropagation(dbn)
343
+ ie.setEvidence(evs)
344
+ ie.makeInference()
345
+
346
+ x = np.arange(T)
347
+
348
+ for var in lovars:
349
+ v0 = dbn.variableFromName(var + "0")
350
+ lpots = []
351
+ for i in range(v0.domainSize()):
352
+ serie = []
353
+ for t in range(T):
354
+ serie.append(ie.posterior(dbn.idFromName(var + str(t)))[i])
355
+ lpots.append(serie)
356
+
357
+ _, ax = plt.subplots()
358
+ plt.xlim(left=0, right=T - 1)
359
+ plt.ylim(top=1, bottom=0)
360
+ ax.xaxis.grid()
361
+
362
+ # Setting a customized title
363
+ if vars_title is None:
364
+ plt.title(f"Following variable {var}", fontsize=20)
365
+ elif len(vars_title) != 0:
366
+ plt.title(vars_title[var], fontsize=20)
367
+ else:
368
+ raise TypeError("Incorrect format of the plots title dictionary")
369
+
370
+ plt.xlabel("time")
371
+
372
+ stack = ax.stackplot(x, lpots)
373
+
374
+ proxy_rects = [Rectangle((0, 0), 1, 1, fc=pc.get_facecolor()[0]) for pc in stack]
375
+ labels = [v0.label(i) for i in range(v0.domainSize())]
376
+ plt.legend(proxy_rects, labels, loc="center left", bbox_to_anchor=(1, 0.5), ncol=1, fancybox=True, shadow=True)
377
+
378
+ plt.show()
379
+
380
+
381
+ def plotFollow(lovars, twoTdbn, T, evs):
382
+ """
383
+ plots modifications of variables in a 2TDN knowing the size of the time window (T) and the evidence on the sequence.
384
+
385
+ :param lovars: list of variables to follow
386
+ :param twoTdbn: the two-timeslice dbn
387
+ :param T: the time range
388
+ :param evs: observations
389
+ """
390
+ plotFollowUnrolled(lovars, unroll2TBN(twoTdbn, T), T, evs)
pyagrum/lib/explain.py ADDED
@@ -0,0 +1,57 @@
1
+ ############################################################################
2
+ # This file is part of the aGrUM/pyAgrum library. #
3
+ # #
4
+ # Copyright (c) 2005-2025 by #
5
+ # - Pierre-Henri WUILLEMIN(_at_LIP6) #
6
+ # - Christophe GONZALES(_at_AMU) #
7
+ # #
8
+ # The aGrUM/pyAgrum library is free software; you can redistribute it #
9
+ # and/or modify it under the terms of either : #
10
+ # #
11
+ # - the GNU Lesser General Public License as published by #
12
+ # the Free Software Foundation, either version 3 of the License, #
13
+ # or (at your option) any later version, #
14
+ # - the MIT license (MIT), #
15
+ # - or both in dual license, as here. #
16
+ # #
17
+ # (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) #
18
+ # #
19
+ # This aGrUM/pyAgrum library is distributed in the hope that it will be #
20
+ # useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #
21
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS #
22
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
23
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
24
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, #
25
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
26
+ # OTHER DEALINGS IN THE SOFTWARE. #
27
+ # #
28
+ # See LICENCES for more details. #
29
+ # #
30
+ # SPDX-FileCopyrightText: Copyright 2005-2025 #
31
+ # - Pierre-Henri WUILLEMIN(_at_LIP6) #
32
+ # - Christophe GONZALES(_at_AMU) #
33
+ # SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
34
+ # #
35
+ # Contact : info_at_agrum_dot_org #
36
+ # homepage : http://agrum.gitlab.io #
37
+ # gitlab : https://gitlab.com/agrumery/agrum #
38
+ # #
39
+ ############################################################################
40
+
41
+ """
42
+ tools for BN qualitative analysis and explainability
43
+ """
44
+
45
+ import warnings
46
+
47
+ warnings.warn(
48
+ "The module 'pyagrum.lib.explain' has been deprecated since version 2.2.2. "
49
+ "Please use the 'pyagrum.explain' module instead.",
50
+ DeprecationWarning,
51
+ stacklevel=2,
52
+ )
53
+
54
+ from pyagrum.explain.shapley import ShapValues # noqa: E402
55
+ from pyagrum.explain.notebook import showShapValues # noqa: E402
56
+ from pyagrum.explain import independenceListForPairs # noqa: E402
57
+ from pyagrum.explain import showInformation, getInformation, getInformationGraph # noqa: E402
pyagrum/lib/export.py ADDED
@@ -0,0 +1,84 @@
1
+ ############################################################################
2
+ # This file is part of the aGrUM/pyAgrum library. #
3
+ # #
4
+ # Copyright (c) 2005-2025 by #
5
+ # - Pierre-Henri WUILLEMIN(_at_LIP6) #
6
+ # - Christophe GONZALES(_at_AMU) #
7
+ # #
8
+ # The aGrUM/pyAgrum library is free software; you can redistribute it #
9
+ # and/or modify it under the terms of either : #
10
+ # #
11
+ # - the GNU Lesser General Public License as published by #
12
+ # the Free Software Foundation, either version 3 of the License, #
13
+ # or (at your option) any later version, #
14
+ # - the MIT license (MIT), #
15
+ # - or both in dual license, as here. #
16
+ # #
17
+ # (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) #
18
+ # #
19
+ # This aGrUM/pyAgrum library is distributed in the hope that it will be #
20
+ # useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #
21
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS #
22
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
23
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
24
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, #
25
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
26
+ # OTHER DEALINGS IN THE SOFTWARE. #
27
+ # #
28
+ # See LICENCES for more details. #
29
+ # #
30
+ # SPDX-FileCopyrightText: Copyright 2005-2025 #
31
+ # - Pierre-Henri WUILLEMIN(_at_LIP6) #
32
+ # - Christophe GONZALES(_at_AMU) #
33
+ # SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
34
+ # #
35
+ # Contact : info_at_agrum_dot_org #
36
+ # homepage : http://agrum.gitlab.io #
37
+ # gitlab : https://gitlab.com/agrumery/agrum #
38
+ # #
39
+ ############################################################################
40
+
41
+ """
42
+ Tools for exporting graphical models and inference as other formats.
43
+
44
+ For each function `pyagrum.lib.export.to...(model,filename)`, it is assumed that the filename is complete (including the correct suffix).
45
+ """
46
+
47
+ import sys
48
+
49
+
50
+ def toGML(model, filename: str = None):
51
+ """
52
+ Export directed graphical models as a graph to the graph GML format (https://gephi.org/users/supported-graph-formats/gml-format/)
53
+
54
+ Parameters
55
+ ----------
56
+ model :
57
+ the directed graphical model to export
58
+ filename : Optional[str]
59
+ the name of the file (including the prefix), if None , use sys.stdout
60
+ """
61
+
62
+ def _toGML(model, gmlfile):
63
+ print("graph", file=gmlfile)
64
+ print("[", file=gmlfile)
65
+ for i in model.nodes():
66
+ print(" node", file=gmlfile)
67
+ print(" [", file=gmlfile)
68
+ print(f" id X{i}", file=gmlfile)
69
+ print(f' label "{model.variable(i).name()}"', file=gmlfile)
70
+ print(" ]", file=gmlfile)
71
+ print("", file=gmlfile)
72
+ for i, j in model.arcs():
73
+ print(" edge", file=gmlfile)
74
+ print(" [", file=gmlfile)
75
+ print(f" source X{i}", file=gmlfile)
76
+ print(f" target X{j}", file=gmlfile)
77
+ print(" ]", file=gmlfile)
78
+ print("]", file=gmlfile)
79
+
80
+ if filename is None:
81
+ _toGML(model, sys.stdout)
82
+ else:
83
+ with open(filename, "w") as gmlfile:
84
+ _toGML(model, gmlfile)