pyAgrum-nightly 2.3.1.9.dev202512261765915415__cp310-abi3-macosx_10_15_x86_64.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 +172 -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.1.9.dev202512261765915415.dist-info/LICENSE.md +12 -0
  103. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/LICENSES/LGPL-3.0-or-later.txt +304 -0
  104. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/LICENSES/MIT.txt +18 -0
  105. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/METADATA +145 -0
  106. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/RECORD +107 -0
  107. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/WHEEL +4 -0
@@ -0,0 +1,598 @@
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 file defines functions for dSeparation crtieria
43
+ """
44
+
45
+ from typing import Set
46
+
47
+ import pyagrum
48
+
49
+ from pyagrum.causal._types import NodeId, DirectedModel, NodeSet
50
+
51
+ # pylint: disable=unused-import
52
+ import pyagrum.causal # for annotations
53
+
54
+
55
+ def isParent(a: NodeId, b: NodeId, g: "pyagrum.BayesNet") -> bool:
56
+ """
57
+ Predicate on whether ``a`` is parent of ``b`` in the graph ``g``, the graph must be a DAG
58
+ """
59
+ return g.existsArc(a, b)
60
+
61
+
62
+ def ancester(x: NodeId, dm: DirectedModel, anc: NodeSet):
63
+ """
64
+ Adds the ancestors of ``x`` in the Bayesian network ``bn`` to the set ``P``
65
+ """
66
+ for parent in dm.parents(x):
67
+ if parent not in anc:
68
+ anc.add(parent)
69
+ ancester(parent, dm, anc)
70
+
71
+
72
+ def _reduce_moralize(bn: "pyagrum.BayesNet", x: NodeSet, y: NodeSet, zset: NodeSet) -> "pyagrum.UndiGraph":
73
+ """
74
+ Returns the undirected graph obtained by reducing (ancestor graph) and moralizing the Bayesian network ``bn``
75
+
76
+ Parameters
77
+ ----------
78
+ bn: pyagrum.BayesNet
79
+ the BayesNet
80
+ x: Set[int|str]
81
+ NodeSet generating the ancestor graph
82
+ y: Set[int|str]
83
+ Second NodeSet generating the ancestor graph
84
+ zset: Set[int|str]
85
+ Third NodeSet generating the ancestor graph
86
+
87
+ Returns
88
+ -------
89
+ pyagrum.UndiGraph
90
+ The reduced moralized graph
91
+ """
92
+ G = pyagrum.UndiGraph()
93
+
94
+ Ancetre = x | y
95
+ anc = frozenset(Ancetre)
96
+ for i in anc:
97
+ ancester(i, bn, Ancetre)
98
+
99
+ for i in zset:
100
+ Ancetre.add(i)
101
+ ancester(i, bn, Ancetre)
102
+ for i in Ancetre:
103
+ G.addNodeWithId(i)
104
+
105
+ for b in G.nodes():
106
+ for a in bn.parents(b):
107
+ G.addEdge(a, b)
108
+
109
+ for nod in G.nodes():
110
+ parents_nod = bn.parents(nod)
111
+ for par in parents_nod:
112
+ for par2 in parents_nod:
113
+ if par2 != par:
114
+ G.addEdge(par, par2)
115
+
116
+ return G
117
+
118
+
119
+ def _removeZ(g_undi: "pyagrum.UndiGraph", zset: NodeSet):
120
+ for node in g_undi.nodes():
121
+ if node in zset:
122
+ g_undi.eraseNode(node)
123
+
124
+
125
+ def _is_path_x_y(g_undi: "pyagrum.UndiGraph", sx: NodeSet, sy: NodeSet, marked: NodeSet = None) -> bool:
126
+ """
127
+ Predicate asserting the existence of a path between ``x`` and ``y`` in the non-oriented graph
128
+ ``g_undi``, without going through the optional marking set ``mark``
129
+
130
+ Parameters
131
+ ----------
132
+ g_undi: PyAgrum.UndiGraph
133
+ The graph
134
+ x: int
135
+ first node
136
+ y: int
137
+ second node
138
+
139
+ marked: Set[int]
140
+ forbidden nodes
141
+
142
+ :return:
143
+ bool
144
+ True if a path has been found
145
+ """
146
+
147
+ def inner_ec(g_und: "pyagrum.UndiGraph", a: NodeId, b: NodeSet, m: NodeSet) -> bool:
148
+ if a in b:
149
+ return True
150
+
151
+ m.add(a)
152
+
153
+ for n in g_und.neighbours(a):
154
+ if n not in m:
155
+ if inner_ec(g_und, n, b, m):
156
+ return True
157
+
158
+ return False
159
+
160
+ if len(sx) > len(sy):
161
+ ssx, ssy = sy, sx
162
+ else:
163
+ ssx, ssy = sx, sy
164
+
165
+ if marked is None:
166
+ marked = set()
167
+
168
+ ma = set(marked)
169
+ for i in ssx:
170
+ ma.add(i)
171
+ if inner_ec(g_undi, i, ssy, ma):
172
+ return True
173
+
174
+ return False
175
+
176
+
177
+ def isDSep_tech2(bn: "pyagrum.BayesNet", sx: NodeSet, sy: NodeSet, zset: NodeSet) -> bool:
178
+ """
179
+ Test of d-separation for ``x`` and ``y``, given ``zset`` using the graph-moralization method
180
+
181
+ Parameters
182
+ ----------
183
+ bn: pyagrum.BayesNet
184
+ the bayesian network
185
+ sx: Set[int]
186
+ source nodes
187
+ sy: Set[int]
188
+ destinantion nodes
189
+ zset: Set[int]
190
+ blocking set
191
+
192
+ Returns
193
+ -------
194
+ bool
195
+ True if ``Z`` d-separates ``x`` and ``y``
196
+ """
197
+ g_undi = _reduce_moralize(bn, sx, sy, zset)
198
+
199
+ _removeZ(g_undi, zset)
200
+
201
+ if _is_path_x_y(g_undi, sx, sy):
202
+ return False
203
+
204
+ return True
205
+
206
+
207
+ def isDSep_parents(bn: "pyagrum.BayesNet", sx: NodeSet, sy: NodeSet, zset: NodeSet) -> bool:
208
+ """Test of d-separation of ``sx`` and ``sy`` given ``Z``, considering only the paths with an arc coming into ``x``
209
+ using the graph-moralization method
210
+
211
+
212
+ Parameters
213
+ ----------
214
+ bn: pyagrum.BayesNet
215
+ the bayesian network
216
+ sx: Set[int]
217
+ source nodes
218
+ sy: Set[int]
219
+ destinantion nodes
220
+ zset: Set[int]
221
+ blocking set
222
+
223
+ Returns
224
+ -------
225
+ bool
226
+ True if ``Z`` d-separates ``x`` and ``y``
227
+ """
228
+ return _isDSep_tech2_parents(bn, sx, sy, zset)
229
+
230
+
231
+ def _isDSep_tech2_parents(bn: "pyagrum.BayesNet", sx: NodeSet, sy: NodeSet, zset: NodeSet) -> bool:
232
+ """Test of d-separation of ``sx`` and ``sy`` given ``Z``, considering only the paths with an arc coming into ``x``
233
+ using the graph-moralization method
234
+
235
+ Parameters
236
+ ----------
237
+ bn: pyagrum.BayesNet
238
+ the bayesian network
239
+ sx: Set[int]
240
+ source nodes
241
+ sy: Set[int]
242
+ destinantion nodes
243
+ zset: Set[int]
244
+ blocking set
245
+
246
+ Returns
247
+ -------
248
+ bool
249
+ """
250
+ G = pyagrum.UndiGraph()
251
+ ancesters = sx | sy
252
+ anc = frozenset(ancesters)
253
+ for i in anc:
254
+ ancester(i, bn, ancesters)
255
+
256
+ for i in zset:
257
+ ancesters.add(i)
258
+ ancester(i, bn, ancesters)
259
+ for i in ancesters:
260
+ G.addNodeWithId(i)
261
+
262
+ for b in G.nodes():
263
+ for a in set(bn.parents(b)) - sx:
264
+ G.addEdge(a, b)
265
+
266
+ for nod in G.nodes():
267
+ parents_nod = set(bn.parents(nod)) - sx
268
+ for par in parents_nod:
269
+ for par2 in parents_nod:
270
+ if par2 != par:
271
+ G.addEdge(par, par2)
272
+
273
+ _removeZ(G, zset)
274
+
275
+ if _is_path_x_y(G, sx, sy):
276
+ return False
277
+
278
+ return True
279
+
280
+
281
+ def _isDSep_tech2_children(bn: "pyagrum.BayesNet", sx: NodeSet, sy: NodeSet, zset: NodeSet) -> bool:
282
+ """Test of d-separation of ``x`` and ``y`` given ``zset``, considering only the paths with an arc coming from ``x``
283
+ using the graph-moralization method
284
+
285
+ Parameters
286
+ ----------
287
+ bn: pyagrum.BayesNet
288
+ the bayesian network
289
+ sx: Set[int]
290
+ source nodes
291
+ sy: Set[int]
292
+ destinantion nodes
293
+ zset: Set[int]
294
+ blocking set
295
+
296
+ Returns
297
+ -------
298
+ bool
299
+ """
300
+ G = pyagrum.UndiGraph()
301
+ ancesters = sx | sy
302
+ for i in sy:
303
+ ancester(i, bn, ancesters)
304
+ # sx's ancesters will not be added since sx already is in ancesters
305
+ for i in zset:
306
+ ancesters.add(i)
307
+ ancester(i, bn, ancesters)
308
+ for i in ancesters:
309
+ G.addNodeWithId(i)
310
+ se = set(G.nodes()) - sx
311
+ for b in se:
312
+ for a in bn.parents(b):
313
+ G.addEdge(a, b)
314
+
315
+ for nod in se:
316
+ parents_nod = bn.parents(nod)
317
+ for par in parents_nod:
318
+ for par2 in parents_nod:
319
+ if par2 != par:
320
+ G.addEdge(par, par2)
321
+ _removeZ(G, zset)
322
+
323
+ if _is_path_x_y(G, sx, sy):
324
+ return False
325
+
326
+ return True
327
+
328
+
329
+ def _is_descendant(bn: "pyagrum.BayesNet", x: NodeId, y: NodeId, marked: NodeSet = None) -> bool:
330
+ """Asserts whether or not ``x`` is a descendant of ``y`` in ``bn``"""
331
+
332
+ if marked is None:
333
+ marked = set()
334
+
335
+ if isParent(y, x, bn):
336
+ return True
337
+
338
+ for c in bn.children(y):
339
+ if c not in marked:
340
+ marked.add(c)
341
+ if _is_descendant(bn, x, c, marked):
342
+ return True
343
+
344
+ return False
345
+
346
+
347
+ def _is_ascendant(bn: "pyagrum.BayesNet", x: NodeId, y: NodeId, marquage: Set[int] = None) -> bool:
348
+ """Predicate on whether ``x`` is an ancestor of ``y`` in the Bayesian network ``bn``"""
349
+
350
+ if isParent(x, y, bn):
351
+ return True
352
+
353
+ if marquage is None:
354
+ marquage = set()
355
+
356
+ for p in bn.parents(y):
357
+ if p not in marquage:
358
+ marquage.add(p)
359
+ if _is_ascendant(bn, x, p, marquage):
360
+ return True
361
+
362
+ return False
363
+
364
+
365
+ def descendants(bn: "pyagrum.BayesNet", x: NodeId, marked: NodeSet = None, ensdesc: NodeSet = None) -> NodeSet:
366
+ """Returns a set composed by all the descendents of ``x`` in ``bn``"""
367
+ if marked is None:
368
+ marked = set()
369
+ if ensdesc is None:
370
+ ensdesc = set()
371
+
372
+ ensdesc = ensdesc | set(bn.children(x))
373
+
374
+ for c in bn.children(x):
375
+ if c not in marked:
376
+ marked.add(c)
377
+ ensdesc = ensdesc | descendants(bn, c, marked)
378
+
379
+ return ensdesc
380
+
381
+
382
+ def _filaires(bn: DirectedModel, interest: NodeSet = None, inf: bool = True) -> NodeSet:
383
+ s = set()
384
+
385
+ if interest is None:
386
+ interest = set()
387
+
388
+ for x in bn.nodes():
389
+ if len(set(bn.parents(x)) - s) == 0 and len(bn.children(x)) == 1 and x not in interest:
390
+ a = x
391
+ while True:
392
+ s.add(a)
393
+ for a in bn.children(a):
394
+ break # take the first elt
395
+ if len(bn.children(a)) != 1 or len(set(bn.parents(a)) - s) != 0 or a in interest:
396
+ break
397
+
398
+ if inf and len(bn.children(x)) == 0 and len(bn.parents(x)) == 1 and x not in interest:
399
+ a = x
400
+ while True:
401
+ s.add(a)
402
+ for a in bn.parents(a):
403
+ break # take the first elt
404
+ if len(bn.children(a)) != 1 or a in interest:
405
+ break
406
+ if len(bn.parents(a)) != 1:
407
+ s.add(a)
408
+ break
409
+ return s
410
+
411
+
412
+ def _barren_nodes(bn: "pyagrum.BayesNet", interest: NodeSet = None) -> NodeSet:
413
+ """Returns the set of recursively determined barren nodes in ``bn`` relatively to the set of nodes ``interest`` (if
414
+ ``interest`` is void, then the whole set of nodes in the graph will be returned)"""
415
+ s = set()
416
+
417
+ if interest is None:
418
+ interest = set()
419
+
420
+ def inner_rec(a):
421
+ if a in interest | s:
422
+ return
423
+ s.add(a)
424
+ for b in bn.parents(a):
425
+ if len(set(bn.children(b)) - s) == 0 and (b not in s):
426
+ inner_rec(b)
427
+
428
+ for x in bn.nodes():
429
+ if len(bn.children(x)) == 0:
430
+ inner_rec(x)
431
+
432
+ return s
433
+
434
+
435
+ def partialDAGFromBN(bn: "pyagrum.BayesNet", Nexcl: NodeSet = None) -> "pyagrum.DAG":
436
+ """
437
+ Creates and returns a duplicate DAG of the given Bayesian network
438
+
439
+ Parameters
440
+ ----------
441
+ bn : pyagrum.BayesNet
442
+ the source
443
+ Nexcl : NodeSet
444
+ the nodes
445
+
446
+ Returns
447
+ -------
448
+ pyagrum.DAG
449
+ """
450
+ if Nexcl is None:
451
+ Nexcl = set()
452
+ d = pyagrum.DAG()
453
+
454
+ nodes = set(bn.nodes()) - (Nexcl)
455
+ for n in nodes:
456
+ d.addNodeWithId(n)
457
+
458
+ for x, y in bn.arcs():
459
+ if x in nodes and y in nodes:
460
+ d.addArc(x, y)
461
+
462
+ return d
463
+
464
+
465
+ def dSep_reduce(g: "pyagrum.BayesNet", interest: NodeSet = None) -> "pyagrum.DAG":
466
+ """
467
+ Reduce a BN by removing barren nodes w.r.t a set of nodes.
468
+
469
+ Parameters
470
+ ----------
471
+ g : pyagrum.BayesNet
472
+ the source
473
+ interest: NodeSet
474
+ the nodes of interest
475
+
476
+ Returns
477
+ -------
478
+ pyagrum.DAG
479
+ the reduced DAG
480
+ """
481
+ if interest is None:
482
+ interest = set()
483
+
484
+ barren = _barren_nodes(g, interest)
485
+
486
+ reduced_g = partialDAGFromBN(g, barren)
487
+
488
+ for f in _filaires(reduced_g, interest, False):
489
+ reduced_g.eraseNode(f)
490
+
491
+ return reduced_g
492
+
493
+
494
+ def _blocked(
495
+ bn: "pyagrum.BayesNet", pht: bool, x: NodeSet, y: NodeSet, setz: NodeSet, marquage0: Set[int], marquage1: Set[int]
496
+ ) -> bool:
497
+ """
498
+ internal method to check if a path is blocked
499
+ """
500
+ if x in y:
501
+ return False
502
+
503
+ isInxZ = x in setz
504
+ wasIn = x in marquage0 or x in marquage1
505
+
506
+ if pht:
507
+ marquage1.add(x)
508
+ else:
509
+ marquage0.add(x)
510
+
511
+ if not isInxZ and not wasIn:
512
+ for c in bn.children(x):
513
+ if c not in marquage1 and not _blocked(bn, True, c, y, setz, marquage0, marquage1):
514
+ return False
515
+
516
+ if pht:
517
+ if isInxZ or len(setz & descendants(bn, x)) != 0:
518
+ for p in bn.parents(x):
519
+ if p not in marquage0 and not _blocked(bn, False, p, y, setz, marquage0, marquage1):
520
+ return False
521
+
522
+ else:
523
+ if not isInxZ:
524
+ for p in bn.parents(x):
525
+ if p not in marquage0 and not _blocked(bn, False, p, y, setz, marquage0, marquage1):
526
+ return False
527
+
528
+ return True
529
+
530
+
531
+ def _isDSep_tech1_parents(bn: "pyagrum.BayesNet", x: NodeId, sy: NodeSet, zset: NodeSet, reduced: bool = False) -> bool:
532
+ """Test of d-separation of ``x`` and ``y`` given ``Z``, considering only the paths with an arc coming into ``x``
533
+ using the usual paths method"""
534
+
535
+ if not reduced and len(bn.nodes()) > 170:
536
+ g = dSep_reduce(bn, sy | zset | {x})
537
+ else:
538
+ g = bn
539
+
540
+ for p in g.parents(x):
541
+ if not _blocked(g, False, p, sy, zset, {x}, {x}):
542
+ return False
543
+ return True
544
+
545
+
546
+ def _isDSep_tech1_children(bn: "pyagrum.BayesNet", x: NodeId, sy: NodeSet, setz: NodeSet, reduced=False) -> bool:
547
+ """Test of d-separation of ``x`` and ``y`` given ``Z``, considering only the paths with an arc coming from ``x``
548
+ using the usual paths method"""
549
+
550
+ if not reduced and len(bn.nodes()) > 170:
551
+ g = dSep_reduce(bn, sy | setz | {x})
552
+ else:
553
+ g = bn
554
+
555
+ for c in g.children(x):
556
+ if not _blocked(g, True, c, sy, setz, {x}, {x}):
557
+ return False
558
+ return True
559
+
560
+
561
+ def isDSep_tech1(bn: "pyagrum.BayesNet", sx: NodeSet, sy: NodeSet, setz: NodeSet, reduced=False) -> bool:
562
+ """Test of d-separation for ``x`` and ``y``, given ``Z`` using the usual paths method"""
563
+
564
+ if len(sx) > len(sy):
565
+ sx, sy = sy, sx
566
+
567
+ if not reduced and len(bn.nodes()) > 170:
568
+ g = dSep_reduce(bn, sx | sy | setz)
569
+ else:
570
+ g = bn
571
+ for i in sx:
572
+ if not _isDSep_tech1_parents(g, i, sy, setz, True):
573
+ return False
574
+ if not _isDSep_tech1_children(g, i, sy, setz, True):
575
+ return False
576
+ return True
577
+
578
+
579
+ def isDSep(bn: "pyagrum.BayesNet", x: NodeSet, y: NodeSet, z: NodeSet) -> bool:
580
+ """
581
+ Check if x and y are d-separated by z in the BN
582
+
583
+ Parameters
584
+ ----------
585
+ bn: pyagrum.BayesNet
586
+
587
+ x : NodeSet
588
+
589
+ y : NodeSet
590
+
591
+ z : NodeSet
592
+
593
+ Returns
594
+ -------
595
+ bool
596
+ whether x and y are d-separated by z
597
+ """
598
+ return isDSep_tech2(bn, x, y, z)