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
pyagrum/clg/CLG.py ADDED
@@ -0,0 +1,658 @@
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 store a Conditional Linear Gaussian (CLG) in a graph structure.
43
+ """
44
+
45
+ import pyagrum as gum
46
+ from typing import Dict, Tuple
47
+ import random
48
+
49
+ from .constants import NodeId
50
+ from .GaussianVariable import GaussianVariable
51
+
52
+ import pyagrum.lib.bn_vs_bn as gcm
53
+
54
+ import numpy as np
55
+ from scipy.stats import norm
56
+ import pandas as pd
57
+
58
+
59
+ class CLG:
60
+ _graph: gum.DAG
61
+ _id2var: Dict[NodeId, GaussianVariable]
62
+ _name2id: Dict[str, NodeId]
63
+ _arc2coef: Dict[Tuple[NodeId, NodeId], float or int]
64
+
65
+ def __init__(self, clg=None):
66
+ self._graph = gum.DAG()
67
+ self._id2var = {}
68
+ self._name2id = {}
69
+ self._arc2coef = {}
70
+
71
+ if clg:
72
+ self.copy(clg)
73
+
74
+ def copy(self, clg):
75
+ for _, variable in clg._id2var.items():
76
+ new_variable = GaussianVariable(name=variable.name(), mu=variable.mu(), sigma=variable.sigma())
77
+ self.add(new_variable)
78
+
79
+ for (parent, child), coef in clg._arc2coef.items():
80
+ self.addArc(parent, child, coef)
81
+
82
+ def __str__(self):
83
+ return (
84
+ f"CLG{{nodes: {len(self.nodes())}, "
85
+ f"arcs: {len(self.arcs())}, "
86
+ f"parameters: {len(self.arcs()) + 2 * len(self.nodes())}}}"
87
+ )
88
+
89
+ def __repr__(self):
90
+ return str(self)
91
+
92
+ def add(self, var):
93
+ """
94
+ Add a new variable to the CLG.
95
+
96
+ Parameters
97
+ ----------
98
+ var : GaussianVariable
99
+ The variable to be added to the CLG.
100
+
101
+ Returns
102
+ -------
103
+ NodeId
104
+ The id of the added variable.
105
+
106
+ Raises
107
+ ------
108
+ ValueError
109
+ if the argument is None.
110
+
111
+ NameError
112
+ if the name of the variable is empty.
113
+
114
+ NameError
115
+ if a variable with the same name already exists in the CLG.
116
+ """
117
+ if var is None:
118
+ raise ValueError("The argument cannot be None.")
119
+ if var.name() == "":
120
+ raise NameError(f"The name cannot be '{var.name()}'.")
121
+ if var.name() in self._name2id:
122
+ raise NameError(f"A variable with the same name ({var.name()}) already exists in this CLG.")
123
+
124
+ n = NodeId(self._graph.addNode())
125
+ self._id2var[n] = var
126
+ self._name2id[var.name()] = n
127
+
128
+ return n
129
+
130
+ def setMu(self, node, mu):
131
+ """
132
+ Set the mean of a variable.
133
+
134
+ Parameters
135
+ ----------
136
+ node : NodeId
137
+ The id of the variable.
138
+ mu : float
139
+ The new mean of the variable.
140
+
141
+ Raises
142
+ ------
143
+ gum.NotFound
144
+ if the node is not found in the CLG.
145
+ """
146
+ self._id2var[node].setMu(mu)
147
+
148
+ def setSigma(self, node, sigma):
149
+ """
150
+ Set the standard deviation of a variable.
151
+
152
+ Parameters
153
+ ----------
154
+ node : NodeId
155
+ The id of the variable.
156
+ sigma : float
157
+ The new standard deviation of the variable.
158
+
159
+ Raises
160
+ ------
161
+ gum.NotFound
162
+ if the node is not found in the CLG.
163
+ """
164
+ self._id2var[node].setSigma(sigma)
165
+
166
+ def nameOrId(self, val):
167
+ """
168
+ Return the NodeId from the name or the NodeId.
169
+
170
+ Parameters
171
+ ----------
172
+ val : NameOrId
173
+ The name or the NodeId of the variable.
174
+
175
+ Returns
176
+ -------
177
+ NodeId
178
+ The NodeId of the variable.
179
+ """
180
+ return val if isinstance(val, int) else self._name2id[val]
181
+
182
+ def addArc(self, val1, val2, coef=1):
183
+ """
184
+ Add an arc val->val2 with a coefficient coef to the CLG.
185
+
186
+ Parameters
187
+ ----------
188
+ val1 : NameOrId
189
+ The name or the NodeId of the parent variable.
190
+ val2 : NameOrId
191
+ The name or the NodeId of the child variable.
192
+ coef : float or int
193
+ The coefficient of the arc.
194
+
195
+ Returns
196
+ -------
197
+ Tuple[NodeId, NodeId]
198
+ The tuple of the NodeIds of the parent and the child variables.
199
+
200
+ Raises
201
+ ------
202
+ gum.NotFound
203
+ if one of the names is not found in the CLG.
204
+ ValueError
205
+ if the coefficient is 0.
206
+ """
207
+ if coef == 0:
208
+ raise ValueError("The coefficient of an arc cannot be 0.")
209
+
210
+ n1 = self.nameOrId(val1)
211
+ n2 = self.nameOrId(val2)
212
+
213
+ self._graph.addArc(n1, n2)
214
+ self._arc2coef[(n1, n2)] = coef
215
+
216
+ return (n1, n2)
217
+
218
+ def existsArc(self, val1, val2):
219
+ """
220
+ Check if an arc val->val2 exists.
221
+
222
+ Parameters
223
+ ----------
224
+ val1 : NameOrId
225
+ The name or the NodeId of the parent variable.
226
+ val2 : NameOrId
227
+ The name or the NodeId of the child variable.
228
+
229
+ Returns
230
+ -------
231
+ bool
232
+ True if the arc exists.
233
+
234
+ Raises
235
+ ------
236
+ gum.NotFound
237
+ if one of the names is not found in the CLG.
238
+ """
239
+ n1 = self.nameOrId(val1)
240
+ n2 = self.nameOrId(val2)
241
+
242
+ return self._graph.existsArc(n1, n2)
243
+
244
+ def setCoef(self, val1, val2, coef):
245
+ """
246
+ Set the coefficient of an arc val1->val2.
247
+
248
+ Parameters
249
+ ----------
250
+ val1 : NameOrId
251
+ The name or the NodeId of the parent variable.
252
+ val2 : NameOrId
253
+ The name or the NodeId of the child variable.
254
+ coef : float or int
255
+ The new coefficient of the arc.
256
+
257
+ Raises
258
+ ------
259
+ gum.NotFound
260
+ if one of the names is not found in the CLG.
261
+ ValueError
262
+ if the coefficient is 0.
263
+ ValueError
264
+ if the arc does not exist.
265
+ """
266
+ if coef == 0:
267
+ raise ValueError("The coefficient of an arc cannot be 0.")
268
+
269
+ if not self.existsArc(val1, val2):
270
+ raise ValueError("The arc does not exist.")
271
+
272
+ n1 = self.nameOrId(val1)
273
+ n2 = self.nameOrId(val2)
274
+
275
+ self._arc2coef[(n1, n2)] = coef
276
+
277
+ def dag(self):
278
+ """
279
+ Return the graph of the CLG (which is a DAG).
280
+
281
+ Returns
282
+ -------
283
+ gum.DAG
284
+ The graph of the CLG.
285
+ """
286
+ return self._graph
287
+
288
+ def eraseArc(self, val1, val2):
289
+ """
290
+ Erase the arc val->val2.
291
+ """
292
+ self._graph.eraseArc(val1, val2)
293
+
294
+ def name(self, node):
295
+ """
296
+ Return the associated name of the variable.
297
+
298
+ Parameters
299
+ ----------
300
+ node : NodeId
301
+ The id of the variable.
302
+
303
+ Returns
304
+ -------
305
+ str
306
+ The associated name of the variable.
307
+
308
+ Raises
309
+ ------
310
+ gum.NotFound
311
+ if the node is not found in the CLG.
312
+ """
313
+ return self._id2var[node].name()
314
+
315
+ def idFromName(self, name):
316
+ """
317
+ Return the NodeId from the name.
318
+
319
+ Parameters
320
+ ----------
321
+ name : str
322
+ The name of the variable.
323
+
324
+ Returns
325
+ -------
326
+ NodeId
327
+ The NodeId of the variable.
328
+
329
+ Raises
330
+ ------
331
+ gum.NotFound
332
+ if the name is not found in the CLG.
333
+ """
334
+ return self._name2id[name]
335
+
336
+ def variable(self, val):
337
+ """
338
+ Return the variable from the NodeId or from the name.
339
+
340
+ Parameters
341
+ ----------
342
+ val : NameOrId
343
+ The name or the NodeId of the variable.
344
+
345
+ Returns
346
+ -------
347
+ GaussianVariable
348
+ The variable.
349
+
350
+ Raises
351
+ ------
352
+ gum.NotFound
353
+ if val is not Found in the CLG.
354
+ """
355
+ return self._id2var[self.nameOrId(val)]
356
+
357
+ def variables(self):
358
+ """
359
+ Return the list of the variables in the CLG.
360
+
361
+ Returns
362
+ -------
363
+ List[GaussianVariable]
364
+ The list of the variables in the CLG.
365
+ """
366
+ return [self.variable(i) for i in self.nodes()]
367
+
368
+ def nodes(self):
369
+ """
370
+ Return the list of NodeIds in the CLG.
371
+
372
+ Returns
373
+ -------
374
+ List[NodeId]
375
+ The list of NodeIds in the CLG.
376
+ """
377
+ return list(self._id2var.keys())
378
+
379
+ def names(self):
380
+ """
381
+ Return the list of names in the CLG.
382
+
383
+ Returns
384
+ -------
385
+ List[str]
386
+ The list of names in the CLG.
387
+ """
388
+ return list(self._name2id.keys())
389
+
390
+ def arcs(self):
391
+ """
392
+ Return the list of arcs in the CLG.
393
+
394
+ Returns
395
+ -------
396
+ List[Tuple[NodeId, NodeId]]
397
+ The list of arcs in the CLG.
398
+ """
399
+ return self._graph.arcs()
400
+
401
+ def coefArc(self, val1, val2):
402
+ """
403
+ Return the coefficient of the arc val1->val2.
404
+
405
+ Parameters
406
+ ----------
407
+ val1 : NameOrId
408
+ The name or the NodeId of the parent variable.
409
+ val2 : NameOrId
410
+ The name or the NodeId of the child variable.
411
+
412
+ Returns
413
+ -------
414
+ float
415
+ The coefficient of the arc.
416
+
417
+ Raises
418
+ ------
419
+ pyagrum.NotFound
420
+ if one of the names is not found in the CLG.
421
+ pyagrum.NotFound
422
+ if the arc does not exist.
423
+ """
424
+ if not self.existsArc(val1, val2):
425
+ raise gum.NotFound("The arc does not exist.")
426
+
427
+ n1 = self.nameOrId(val1)
428
+ n2 = self.nameOrId(val2)
429
+
430
+ return self._arc2coef[(n1, n2)]
431
+
432
+ def parents(self, val):
433
+ """
434
+ Return the list of parent ids from the name or the id of a node.
435
+
436
+ Parameters
437
+ ----------
438
+ val : NameOrId
439
+ The name or the NodeId of the variable.
440
+
441
+ Returns
442
+ -------
443
+ Set[NodeId]
444
+ The set of parent nodes' ids.
445
+ """
446
+ return self._graph.parents(self.nameOrId(val))
447
+
448
+ def parent_names(self, val):
449
+ """
450
+ Return the list of parents names from the name or the id of a node.
451
+
452
+ Parameters
453
+ ----------
454
+ val : NameOrId
455
+ The name or the NodeId of the variable.
456
+
457
+ Returns
458
+ -------
459
+ List[str]
460
+ The list of val's parents' names.
461
+ """
462
+ return [self.name(n) for n in self.parents(val)]
463
+
464
+ def children(self, val):
465
+ """
466
+ Return the list of children ids from the name or the id of a node.
467
+
468
+ Parameters
469
+ ----------
470
+ val : NameOrId
471
+ The name or the NodeId of the variable.
472
+
473
+ Returns
474
+ -------
475
+ Set[NodeId]
476
+ The set of children nodes' ids.
477
+ """
478
+ return self._graph.children(self.nameOrId(val))
479
+
480
+ def children_names(self, val):
481
+ """
482
+ Return the list of children names from the name or the id of a node.
483
+
484
+ Parameters
485
+ ----------
486
+ val : NameOrId
487
+ The name or the NodeId of the variable.
488
+
489
+ Returns
490
+ -------
491
+ List[str]
492
+ The list of val's children's names.
493
+ """
494
+ return [self.name(n) for n in self.children(val)]
495
+
496
+ def topologicalOrder(self):
497
+ """
498
+ Return the topological order of the CLG.
499
+
500
+ Returns
501
+ -------
502
+ List[NodeId]
503
+ The list of NodeIds in the topological order.
504
+ """
505
+ return self._graph.topologicalOrder()
506
+
507
+ def dag2dict(self):
508
+ """
509
+ Return a dictionary representing the DAG of the CLG.
510
+
511
+ Returns
512
+ -------
513
+ C : Dict[NodeId, Set[NodeId]]
514
+ A directed graph DAG representing the causal structure.
515
+ """
516
+ V = self.nodes()
517
+ C = {v: set() for v in V} # C is shown by a Adjacency List
518
+
519
+ for node in V:
520
+ for child in self.children(node):
521
+ C[node].add(child)
522
+
523
+ return C
524
+
525
+ def logLikelihood(self, data):
526
+ """
527
+ Return the log-likelihood of the data.
528
+
529
+ Parameters
530
+ ----------
531
+ data : csv file
532
+ The data.
533
+
534
+ Returns
535
+ -------
536
+ float
537
+ The log-likelihood of the data for the CLG.
538
+ """
539
+ id2samples = {}
540
+ log_likelihood = 0
541
+
542
+ # collect the samples to a dict whose keys are NodeID
543
+ df = pd.read_csv(data)
544
+ for node in self.nodes():
545
+ id2samples[node] = df[self.name(node)].tolist()
546
+
547
+ # for each sample, compute the pdf of each node
548
+ for i in range(len(id2samples[0])):
549
+ joint_pdf = 1
550
+ for node in self.nodes():
551
+ # compute the real mu of node considering its parents
552
+ loc_mu = self._id2var[node].mu()
553
+ for parent in self.parents(node):
554
+ loc_mu += id2samples[parent][i] * self._arc2coef[(parent, node)]
555
+
556
+ # use norm.pdf to compute the pdf of each node
557
+ joint_pdf *= norm(loc_mu, self._id2var[node].sigma()).pdf(id2samples[node][i])
558
+
559
+ log_likelihood += np.log(joint_pdf)
560
+
561
+ return log_likelihood
562
+
563
+ def CompareStructure(self, clg_to_compare):
564
+ """
565
+ We use the f-score to compare the causal structure of the two CLGs.
566
+ We create two BNs with the same structure as the two CLGs and then compare the two BNs.
567
+
568
+ Parameters
569
+ ----------
570
+ clg_to_compare : CLG
571
+ The CLG to compare with.
572
+
573
+ Returns
574
+ -------
575
+ float
576
+ The f-score of the comparison.
577
+ """
578
+ # Create a BN with the same structure as the CLG
579
+ bn = gum.BayesNet()
580
+ # add variables
581
+ for name in self.names():
582
+ new_variable = gum.LabelizedVariable(name, "a labelized variable", 2)
583
+ bn.add(new_variable)
584
+ # add arcs
585
+ for arc in self.arcs():
586
+ bn.addArc(arc[0], arc[1])
587
+
588
+ # Create a BN with the same structure as the clg_to_compare
589
+ bn_to_compare = gum.BayesNet()
590
+ # add variables
591
+ for name in clg_to_compare.names():
592
+ new_variable = gum.LabelizedVariable(name, "a labelized variable", 2)
593
+ bn_to_compare.add(new_variable)
594
+ # add arcs and edges
595
+ for arc in clg_to_compare.arcs():
596
+ bn_to_compare.addArc(arc[0], arc[1])
597
+
598
+ # We use the f-score to compare graphs of the two created BNs
599
+ cmp = gcm.GraphicalBNComparator(bn, bn_to_compare)
600
+
601
+ return cmp.scores()["fscore"]
602
+
603
+
604
+ def randomCLG(nb_variables, names, MuMax=5, MuMin=-5, SigmaMax=10, SigmaMin=1, ArcCoefMax=10, ArcCoefMin=5):
605
+ """
606
+ This function generates a random CLG with nb_variables variables.
607
+
608
+ Parameters
609
+ ----------
610
+ nb_variables : int
611
+ The number of variables in the CLG.
612
+ names : str
613
+ The list of names of the variables.
614
+ MuMax : float
615
+ The maximum value of mu.
616
+ MuMin : float
617
+ The minimum value of mu.
618
+ SigmaMax : float
619
+ The maximum value of sigma.
620
+ SigmaMin : float
621
+ The minimum value of sigma.
622
+ ArcCoefMax : float
623
+ The maximum value of the coefficient of the arc.
624
+ ArcCoefMin : float
625
+ The minimum value of the coefficient of the arc.
626
+
627
+ Returns
628
+ -------
629
+ CLG
630
+ The random CLG.
631
+ """
632
+ # Create a random BN with nb_variables variables
633
+ bn = gum.randomBN(names=names, n=nb_variables)
634
+
635
+ # Order names by their NodeIds
636
+ ordered_names = [""] * nb_variables
637
+ for name in bn.names():
638
+ ordered_names[bn.idFromName(name)] = name
639
+
640
+ # Create a random CLG with nb_variables variables(The CLG is created with the same structure as the BN)
641
+ clg = CLG()
642
+ # Add variables
643
+ for name in ordered_names:
644
+ new_variable = GaussianVariable(
645
+ name=name, mu=random.uniform(MuMin, MuMax), sigma=random.uniform(SigmaMin, SigmaMax)
646
+ )
647
+ clg.add(new_variable)
648
+ # Add arcs
649
+ for arc in bn.arcs():
650
+ clg.addArc(
651
+ val1=arc[0],
652
+ val2=arc[1],
653
+ coef=random.uniform(-1 * ArcCoefMax, -1 * ArcCoefMin)
654
+ if random.random() < 0.5
655
+ else random.uniform(ArcCoefMin, ArcCoefMax),
656
+ )
657
+
658
+ return clg