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.
- pyagrum/__init__.py +165 -0
- pyagrum/_pyagrum.so +0 -0
- pyagrum/bnmixture/BNMInference.py +268 -0
- pyagrum/bnmixture/BNMLearning.py +376 -0
- pyagrum/bnmixture/BNMixture.py +464 -0
- pyagrum/bnmixture/__init__.py +60 -0
- pyagrum/bnmixture/notebook.py +1058 -0
- pyagrum/causal/_CausalFormula.py +280 -0
- pyagrum/causal/_CausalModel.py +436 -0
- pyagrum/causal/__init__.py +81 -0
- pyagrum/causal/_causalImpact.py +356 -0
- pyagrum/causal/_dSeparation.py +598 -0
- pyagrum/causal/_doAST.py +761 -0
- pyagrum/causal/_doCalculus.py +361 -0
- pyagrum/causal/_doorCriteria.py +374 -0
- pyagrum/causal/_exceptions.py +95 -0
- pyagrum/causal/_types.py +61 -0
- pyagrum/causal/causalEffectEstimation/_CausalEffectEstimation.py +1175 -0
- pyagrum/causal/causalEffectEstimation/_IVEstimators.py +718 -0
- pyagrum/causal/causalEffectEstimation/_RCTEstimators.py +132 -0
- pyagrum/causal/causalEffectEstimation/__init__.py +46 -0
- pyagrum/causal/causalEffectEstimation/_backdoorEstimators.py +774 -0
- pyagrum/causal/causalEffectEstimation/_causalBNEstimator.py +324 -0
- pyagrum/causal/causalEffectEstimation/_frontdoorEstimators.py +396 -0
- pyagrum/causal/causalEffectEstimation/_learners.py +118 -0
- pyagrum/causal/causalEffectEstimation/_utils.py +466 -0
- pyagrum/causal/notebook.py +171 -0
- pyagrum/clg/CLG.py +658 -0
- pyagrum/clg/GaussianVariable.py +111 -0
- pyagrum/clg/SEM.py +312 -0
- pyagrum/clg/__init__.py +63 -0
- pyagrum/clg/canonicalForm.py +408 -0
- pyagrum/clg/constants.py +54 -0
- pyagrum/clg/forwardSampling.py +202 -0
- pyagrum/clg/learning.py +776 -0
- pyagrum/clg/notebook.py +480 -0
- pyagrum/clg/variableElimination.py +271 -0
- pyagrum/common.py +60 -0
- pyagrum/config.py +319 -0
- pyagrum/ctbn/CIM.py +513 -0
- pyagrum/ctbn/CTBN.py +573 -0
- pyagrum/ctbn/CTBNGenerator.py +216 -0
- pyagrum/ctbn/CTBNInference.py +459 -0
- pyagrum/ctbn/CTBNLearner.py +161 -0
- pyagrum/ctbn/SamplesStats.py +671 -0
- pyagrum/ctbn/StatsIndepTest.py +355 -0
- pyagrum/ctbn/__init__.py +79 -0
- pyagrum/ctbn/constants.py +54 -0
- pyagrum/ctbn/notebook.py +264 -0
- pyagrum/defaults.ini +199 -0
- pyagrum/deprecated.py +95 -0
- pyagrum/explain/_ComputationCausal.py +75 -0
- pyagrum/explain/_ComputationConditional.py +48 -0
- pyagrum/explain/_ComputationMarginal.py +48 -0
- pyagrum/explain/_CustomShapleyCache.py +110 -0
- pyagrum/explain/_Explainer.py +176 -0
- pyagrum/explain/_Explanation.py +70 -0
- pyagrum/explain/_FIFOCache.py +54 -0
- pyagrum/explain/_ShallCausalValues.py +204 -0
- pyagrum/explain/_ShallConditionalValues.py +155 -0
- pyagrum/explain/_ShallMarginalValues.py +155 -0
- pyagrum/explain/_ShallValues.py +296 -0
- pyagrum/explain/_ShapCausalValues.py +208 -0
- pyagrum/explain/_ShapConditionalValues.py +126 -0
- pyagrum/explain/_ShapMarginalValues.py +191 -0
- pyagrum/explain/_ShapleyValues.py +298 -0
- pyagrum/explain/__init__.py +81 -0
- pyagrum/explain/_explGeneralizedMarkovBlanket.py +152 -0
- pyagrum/explain/_explIndependenceListForPairs.py +146 -0
- pyagrum/explain/_explInformationGraph.py +264 -0
- pyagrum/explain/notebook/__init__.py +54 -0
- pyagrum/explain/notebook/_bar.py +142 -0
- pyagrum/explain/notebook/_beeswarm.py +174 -0
- pyagrum/explain/notebook/_showShapValues.py +97 -0
- pyagrum/explain/notebook/_waterfall.py +220 -0
- pyagrum/explain/shapley.py +225 -0
- pyagrum/lib/__init__.py +46 -0
- pyagrum/lib/_colors.py +390 -0
- pyagrum/lib/bn2graph.py +299 -0
- pyagrum/lib/bn2roc.py +1026 -0
- pyagrum/lib/bn2scores.py +217 -0
- pyagrum/lib/bn_vs_bn.py +605 -0
- pyagrum/lib/cn2graph.py +305 -0
- pyagrum/lib/discreteTypeProcessor.py +1102 -0
- pyagrum/lib/discretizer.py +58 -0
- pyagrum/lib/dynamicBN.py +390 -0
- pyagrum/lib/explain.py +57 -0
- pyagrum/lib/export.py +84 -0
- pyagrum/lib/id2graph.py +258 -0
- pyagrum/lib/image.py +387 -0
- pyagrum/lib/ipython.py +307 -0
- pyagrum/lib/mrf2graph.py +471 -0
- pyagrum/lib/notebook.py +1821 -0
- pyagrum/lib/proba_histogram.py +552 -0
- pyagrum/lib/utils.py +138 -0
- pyagrum/pyagrum.py +31495 -0
- pyagrum/skbn/_MBCalcul.py +242 -0
- pyagrum/skbn/__init__.py +49 -0
- pyagrum/skbn/_learningMethods.py +282 -0
- pyagrum/skbn/_utils.py +297 -0
- pyagrum/skbn/bnclassifier.py +1014 -0
- pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/LICENSE.md +12 -0
- pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/LICENSES/LGPL-3.0-or-later.txt +304 -0
- pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/LICENSES/MIT.txt +18 -0
- pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/METADATA +145 -0
- pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/RECORD +107 -0
- pyagrum_nightly-2.3.0.9.dev202512061764412981.dist-info/WHEEL +4 -0
pyagrum/ctbn/CIM.py
ADDED
|
@@ -0,0 +1,513 @@
|
|
|
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
|
+
from typing import Dict, Optional, Union, List
|
|
42
|
+
|
|
43
|
+
import numpy
|
|
44
|
+
import pyagrum
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
This file contains the CIM class (Conditional Intensity Matrix).
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class CIM:
|
|
52
|
+
"""
|
|
53
|
+
This class is used to represent a CIM (random variables and parameters of transition time).
|
|
54
|
+
A CIM is mainly a pyagrum.Tensor that contains the parameters of an exponential distribution.
|
|
55
|
+
This class contains also contains the ``amalgamation`` operator, used for merging CIMs into one.
|
|
56
|
+
|
|
57
|
+
Notes
|
|
58
|
+
-----
|
|
59
|
+
A static string ``DELIMITER`` is used to differentiate between the current state of the variable and its next state.
|
|
60
|
+
<V_name><DELIMITER>i : starting node
|
|
61
|
+
<V_name><DELIMITER>j : ending node
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
pot : pyagrum.Tensor | None
|
|
66
|
+
Defines the new CIM using existing tensor.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
DELIMITER = "#"
|
|
70
|
+
_pot: pyagrum.Tensor
|
|
71
|
+
|
|
72
|
+
def __init__(self, pot=None):
|
|
73
|
+
if pot is None:
|
|
74
|
+
self._pot = pyagrum.Tensor()
|
|
75
|
+
else:
|
|
76
|
+
self._pot = pyagrum.Tensor(pot)
|
|
77
|
+
self._recordVars()
|
|
78
|
+
|
|
79
|
+
def __getitem__(self, i):
|
|
80
|
+
return self._pot[i]
|
|
81
|
+
|
|
82
|
+
def __setitem__(self, i, v):
|
|
83
|
+
self._pot[i] = v
|
|
84
|
+
|
|
85
|
+
def __mul__(self: "CIM", cimY: "CIM") -> "CIM":
|
|
86
|
+
return self.amalgamate(cimY)
|
|
87
|
+
|
|
88
|
+
def __repr__(self):
|
|
89
|
+
return self._pot.__repr__()
|
|
90
|
+
|
|
91
|
+
def __str__(self):
|
|
92
|
+
return self.__repr__()
|
|
93
|
+
|
|
94
|
+
def add(self, v: pyagrum.DiscreteVariable) -> "CIM":
|
|
95
|
+
"""
|
|
96
|
+
Add a new variable to the CIM.
|
|
97
|
+
|
|
98
|
+
Parameters
|
|
99
|
+
----------
|
|
100
|
+
v : pyagrum.DiscreteVariable
|
|
101
|
+
Variable to add.
|
|
102
|
+
|
|
103
|
+
Returns
|
|
104
|
+
-------
|
|
105
|
+
CIM
|
|
106
|
+
A reference to the CIM.
|
|
107
|
+
"""
|
|
108
|
+
if not self._pot.contains(v):
|
|
109
|
+
self._pot.add(v)
|
|
110
|
+
self._recordVars()
|
|
111
|
+
return self
|
|
112
|
+
|
|
113
|
+
def remove(self, v: pyagrum.DiscreteVariable) -> "CIM":
|
|
114
|
+
"""
|
|
115
|
+
Removes a variable from the CIM. Only for parent variables.
|
|
116
|
+
|
|
117
|
+
Parameters
|
|
118
|
+
----------
|
|
119
|
+
v : pyagrum.DiscreteVariable
|
|
120
|
+
Variable to remove.
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
CIM
|
|
125
|
+
A reference to the CIM.
|
|
126
|
+
|
|
127
|
+
Raises
|
|
128
|
+
------
|
|
129
|
+
pyagrum.NotFound
|
|
130
|
+
If the variable isn't in the CIM.
|
|
131
|
+
pyagrum.InvalidArgument
|
|
132
|
+
If the variable isn't a parent in the CIM.
|
|
133
|
+
"""
|
|
134
|
+
if v not in self.variablesSequence():
|
|
135
|
+
raise pyagrum.NotFound("the variable is not in the CIM")
|
|
136
|
+
elif not self.isParent(v):
|
|
137
|
+
raise pyagrum.InvalidArgument("the variable is not a parent in the CIM")
|
|
138
|
+
else:
|
|
139
|
+
self._pot.remove(v)
|
|
140
|
+
self._recordVars()
|
|
141
|
+
return self
|
|
142
|
+
|
|
143
|
+
def nbrDim(self) -> int:
|
|
144
|
+
"""
|
|
145
|
+
Returns
|
|
146
|
+
-------
|
|
147
|
+
int
|
|
148
|
+
The number of variables in the CIM (including v_i and v_j variables).
|
|
149
|
+
|
|
150
|
+
"""
|
|
151
|
+
return self._pot.nbrDim()
|
|
152
|
+
|
|
153
|
+
def extract(self, ctxt: Optional[Dict[str, str]]) -> "CIM":
|
|
154
|
+
"""
|
|
155
|
+
Creates a new CIM extracted from the current CIM using the instantiation ``ctxt``.
|
|
156
|
+
|
|
157
|
+
Parameters
|
|
158
|
+
----------
|
|
159
|
+
ctxt : Optional[Dict[str, str]]
|
|
160
|
+
Instantiation of variables.
|
|
161
|
+
|
|
162
|
+
Returns
|
|
163
|
+
-------
|
|
164
|
+
CIM
|
|
165
|
+
The extracted CIM.
|
|
166
|
+
"""
|
|
167
|
+
return CIM(self._pot.extract(ctxt))
|
|
168
|
+
|
|
169
|
+
def asTensor(self):
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
Returns
|
|
173
|
+
-------
|
|
174
|
+
pyagrum.Tensor
|
|
175
|
+
a copy of the internal tensor
|
|
176
|
+
"""
|
|
177
|
+
return pyagrum.Tensor(self._pot)
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def varNames(self):
|
|
181
|
+
"""
|
|
182
|
+
Returns
|
|
183
|
+
-------
|
|
184
|
+
List[str]
|
|
185
|
+
A list containing the name of each variable in the CIM.
|
|
186
|
+
"""
|
|
187
|
+
# return self._pot.varNames
|
|
188
|
+
return self._pot.names
|
|
189
|
+
|
|
190
|
+
def variablesSequence(self) -> List[pyagrum.DiscreteVariable]:
|
|
191
|
+
"""
|
|
192
|
+
Returns
|
|
193
|
+
-------
|
|
194
|
+
List[pyagrum.DiscreteVariable]
|
|
195
|
+
A list containing the sequence of variables of the CIM.
|
|
196
|
+
"""
|
|
197
|
+
return self._pot.variablesSequence()
|
|
198
|
+
|
|
199
|
+
def variable(self, arg: int) -> "pyagrum.DiscreteVariable":
|
|
200
|
+
"""
|
|
201
|
+
Parameters
|
|
202
|
+
----------
|
|
203
|
+
arg : int
|
|
204
|
+
Index of the variable in the CIM (i.e its node id).
|
|
205
|
+
|
|
206
|
+
Returns
|
|
207
|
+
-------
|
|
208
|
+
pyagrum.DiscreteVariable
|
|
209
|
+
The variable at index ``arg``.
|
|
210
|
+
"""
|
|
211
|
+
return self._pot.variable(arg)
|
|
212
|
+
|
|
213
|
+
def findVar(self, name: str) -> Union[None, pyagrum.DiscreteVariable]:
|
|
214
|
+
"""
|
|
215
|
+
Finds a variable in the CIM using its name.
|
|
216
|
+
|
|
217
|
+
Parameters
|
|
218
|
+
----------
|
|
219
|
+
name : str
|
|
220
|
+
Name of the variable to find.
|
|
221
|
+
|
|
222
|
+
Returns
|
|
223
|
+
-------
|
|
224
|
+
pyagrum.DiscreteVariable | None
|
|
225
|
+
The variable if it is in the CIM.
|
|
226
|
+
"""
|
|
227
|
+
v: pyagrum.DiscreteVariable
|
|
228
|
+
for v in self._pot.variablesSequence():
|
|
229
|
+
if v.name() == name:
|
|
230
|
+
return v
|
|
231
|
+
return None
|
|
232
|
+
|
|
233
|
+
def instantiation(self):
|
|
234
|
+
"""
|
|
235
|
+
Returns
|
|
236
|
+
-------
|
|
237
|
+
pyagrum.Instantiation
|
|
238
|
+
An Instantiation object using the CIM's tensor.
|
|
239
|
+
"""
|
|
240
|
+
return pyagrum.Instantiation(self._pot)
|
|
241
|
+
|
|
242
|
+
def _recordVars(self):
|
|
243
|
+
self._parents = set()
|
|
244
|
+
self._bases = set()
|
|
245
|
+
for v in self.variablesSequence():
|
|
246
|
+
if self.isParent(v):
|
|
247
|
+
self._parents.add(v)
|
|
248
|
+
else:
|
|
249
|
+
self._bases.add(v)
|
|
250
|
+
|
|
251
|
+
@staticmethod
|
|
252
|
+
def varI(name: str) -> str:
|
|
253
|
+
"""
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
name : str
|
|
257
|
+
Name of the variable to format.
|
|
258
|
+
|
|
259
|
+
Returns
|
|
260
|
+
-------
|
|
261
|
+
str
|
|
262
|
+
The name of the variable using {name}{DELIMITER}i format.
|
|
263
|
+
"""
|
|
264
|
+
return f"{name}{CIM.DELIMITER}i"
|
|
265
|
+
|
|
266
|
+
@staticmethod
|
|
267
|
+
def varJ(name: str) -> str:
|
|
268
|
+
"""
|
|
269
|
+
Parameters
|
|
270
|
+
----------
|
|
271
|
+
name : str
|
|
272
|
+
Name of the variable to format.
|
|
273
|
+
|
|
274
|
+
Returns
|
|
275
|
+
-------
|
|
276
|
+
str
|
|
277
|
+
The name of the variable using {name}{DELIMITER}j format.
|
|
278
|
+
"""
|
|
279
|
+
return f"{name}{CIM.DELIMITER}j"
|
|
280
|
+
|
|
281
|
+
@staticmethod
|
|
282
|
+
def varRadical(v: pyagrum.DiscreteVariable) -> str:
|
|
283
|
+
"""
|
|
284
|
+
Parameters
|
|
285
|
+
----------
|
|
286
|
+
v : pyagrum.DiscreteVariable
|
|
287
|
+
Variable to get name from.
|
|
288
|
+
|
|
289
|
+
Returns
|
|
290
|
+
-------
|
|
291
|
+
str
|
|
292
|
+
The name of the variable (without ``DELIMITER`` formatting).
|
|
293
|
+
"""
|
|
294
|
+
if CIM.isParent(v):
|
|
295
|
+
return v.name()
|
|
296
|
+
return v.name()[:-2]
|
|
297
|
+
|
|
298
|
+
@staticmethod
|
|
299
|
+
def isParent(v: pyagrum.DiscreteVariable) -> bool:
|
|
300
|
+
"""
|
|
301
|
+
Uses the syntax convention to check if a variable's name is the name of a parent in the CIM.
|
|
302
|
+
|
|
303
|
+
Parameters
|
|
304
|
+
----------
|
|
305
|
+
v : pyagrum.DiscreteVariable
|
|
306
|
+
Variable to check.
|
|
307
|
+
|
|
308
|
+
Returns
|
|
309
|
+
-------
|
|
310
|
+
bool
|
|
311
|
+
True if ``v``'s name corresponds to the name of a parent in the CIM.
|
|
312
|
+
"""
|
|
313
|
+
name = v.name()
|
|
314
|
+
if len(name) < 2:
|
|
315
|
+
return True
|
|
316
|
+
if name[-2] != CIM.DELIMITER:
|
|
317
|
+
return True
|
|
318
|
+
return False
|
|
319
|
+
|
|
320
|
+
def isIM(self) -> bool:
|
|
321
|
+
"""
|
|
322
|
+
Returns
|
|
323
|
+
-------
|
|
324
|
+
bool
|
|
325
|
+
True if there is no conditioning variable (parent) in the CIM.
|
|
326
|
+
"""
|
|
327
|
+
for v in self.variablesSequence():
|
|
328
|
+
if self.isParent(v):
|
|
329
|
+
return False
|
|
330
|
+
return True
|
|
331
|
+
|
|
332
|
+
def toMatrix(self, ctxt: Optional[Dict[str, str]] = None) -> numpy.array:
|
|
333
|
+
"""
|
|
334
|
+
Converts a CIM to a numpy.array matrix.
|
|
335
|
+
|
|
336
|
+
Notes
|
|
337
|
+
-----
|
|
338
|
+
Only works for CIMs with no conditioning variable, or CIMs obtained through amalgamation.
|
|
339
|
+
|
|
340
|
+
Parameters
|
|
341
|
+
----------
|
|
342
|
+
ctxt : Optional[Dict[str, str]] | None
|
|
343
|
+
Instantiation of variables to use if given.
|
|
344
|
+
|
|
345
|
+
Returns
|
|
346
|
+
------
|
|
347
|
+
numpy.array
|
|
348
|
+
The CIM as a numpy.array.
|
|
349
|
+
"""
|
|
350
|
+
if ctxt is not None:
|
|
351
|
+
q = self.extract(ctxt)
|
|
352
|
+
else:
|
|
353
|
+
q = self
|
|
354
|
+
if not q.isIM():
|
|
355
|
+
raise ValueError("The cim is conditionnal.")
|
|
356
|
+
i = q.instantiation()
|
|
357
|
+
iI = pyagrum.Instantiation()
|
|
358
|
+
iJ = pyagrum.Instantiation()
|
|
359
|
+
for n in sorted(q.varNames): # to be sure of a deterministic order
|
|
360
|
+
v = i.variable(n)
|
|
361
|
+
if n[-1] == "i":
|
|
362
|
+
iI.add(v)
|
|
363
|
+
else:
|
|
364
|
+
iJ.add(v)
|
|
365
|
+
|
|
366
|
+
res = []
|
|
367
|
+
iI.setFirst()
|
|
368
|
+
while not iI.end():
|
|
369
|
+
iJ.setFirst()
|
|
370
|
+
line = []
|
|
371
|
+
while not iJ.end():
|
|
372
|
+
i.setVals(iI)
|
|
373
|
+
i.setVals(iJ)
|
|
374
|
+
line.append(q[i])
|
|
375
|
+
iJ.inc()
|
|
376
|
+
res.append(list(line))
|
|
377
|
+
iI.inc()
|
|
378
|
+
|
|
379
|
+
return numpy.array(res)
|
|
380
|
+
|
|
381
|
+
def fromMatrix(self, mat):
|
|
382
|
+
"""
|
|
383
|
+
Fills the CIM with matrix ``mat``.
|
|
384
|
+
|
|
385
|
+
Notes
|
|
386
|
+
-----
|
|
387
|
+
Only works for square-shaped matrixes, if the CIM is not conditional.
|
|
388
|
+
|
|
389
|
+
Parameters
|
|
390
|
+
----------
|
|
391
|
+
mat : numpy.array
|
|
392
|
+
Matrix to convert into a CIM.
|
|
393
|
+
"""
|
|
394
|
+
if not self.isIM():
|
|
395
|
+
raise ValueError("The cim is conditionnal.")
|
|
396
|
+
i = self.instantiation()
|
|
397
|
+
iI = pyagrum.Instantiation()
|
|
398
|
+
iJ = pyagrum.Instantiation()
|
|
399
|
+
siz = 1
|
|
400
|
+
for n in sorted(self.varNames): # to be sure of a deterministic order
|
|
401
|
+
v = i.variable(n)
|
|
402
|
+
if n[-1] == "i":
|
|
403
|
+
iI.add(v)
|
|
404
|
+
siz *= v.domainSize()
|
|
405
|
+
else:
|
|
406
|
+
iJ.add(v)
|
|
407
|
+
if mat.shape != (siz, siz):
|
|
408
|
+
raise AttributeError(f"Shape {mat.shape} should be {(siz, siz)}")
|
|
409
|
+
|
|
410
|
+
iI.setFirst()
|
|
411
|
+
for lin in mat:
|
|
412
|
+
iJ.setFirst()
|
|
413
|
+
for v in lin:
|
|
414
|
+
i.setVals(iI)
|
|
415
|
+
i.setVals(iJ)
|
|
416
|
+
self[i] = v
|
|
417
|
+
iJ.inc()
|
|
418
|
+
iI.inc()
|
|
419
|
+
|
|
420
|
+
def amalgamate(self: "CIM", cimY: "CIM") -> "CIM":
|
|
421
|
+
"""
|
|
422
|
+
Amalgamation of 2 CIMs, i.e combine 2 CIMs into one. When manipulating CIMs ``*`` can be used instead.
|
|
423
|
+
|
|
424
|
+
Parameters
|
|
425
|
+
----------
|
|
426
|
+
cimY : CIM
|
|
427
|
+
CIM to amalgamate self with.
|
|
428
|
+
|
|
429
|
+
Returns
|
|
430
|
+
-------
|
|
431
|
+
CIM
|
|
432
|
+
Amalgamation of the CIMs.
|
|
433
|
+
"""
|
|
434
|
+
cimX = self
|
|
435
|
+
|
|
436
|
+
# Checks if either one of the CIM is empty
|
|
437
|
+
if cimX.nbrDim() == 0:
|
|
438
|
+
return CIM(pyagrum.Tensor(cimY._pot))
|
|
439
|
+
if cimY.nbrDim() == 0:
|
|
440
|
+
return CIM(pyagrum.Tensor(cimX._pot))
|
|
441
|
+
|
|
442
|
+
# Names of the non-parent variables from the CIM
|
|
443
|
+
sX = {self.varRadical(v) for v in cimX.variablesSequence() if not self.isParent(v)}
|
|
444
|
+
sY = {self.varRadical(v) for v in cimY.variablesSequence() if not self.isParent(v)}
|
|
445
|
+
|
|
446
|
+
amal = CIM()
|
|
447
|
+
|
|
448
|
+
for v in cimX._bases.union(cimY._bases):
|
|
449
|
+
amal.add(v)
|
|
450
|
+
|
|
451
|
+
# parents of cimY that are bases from cimX
|
|
452
|
+
pXinY = set()
|
|
453
|
+
# parents of cimX that are bases from cimY
|
|
454
|
+
pYinX = set()
|
|
455
|
+
|
|
456
|
+
for v in cimX._parents:
|
|
457
|
+
if v.name() not in sY:
|
|
458
|
+
amal.add(v)
|
|
459
|
+
else:
|
|
460
|
+
pYinX.add(v)
|
|
461
|
+
|
|
462
|
+
for v in cimY._parents:
|
|
463
|
+
if v.name() not in sX:
|
|
464
|
+
amal.add(v)
|
|
465
|
+
else:
|
|
466
|
+
pXinY.add(v)
|
|
467
|
+
|
|
468
|
+
amal._recordVars()
|
|
469
|
+
|
|
470
|
+
i = amal.instantiation()
|
|
471
|
+
iX = cimX.instantiation()
|
|
472
|
+
iY = cimY.instantiation()
|
|
473
|
+
# goes over all possible combinations of values of variables and their parents
|
|
474
|
+
i.setFirst()
|
|
475
|
+
while not i.end():
|
|
476
|
+
iX.setVals(i)
|
|
477
|
+
iY.setVals(i)
|
|
478
|
+
for v in pXinY:
|
|
479
|
+
iY.chgVal(v, iX[CIM.varI(v.name())])
|
|
480
|
+
for v in pYinX:
|
|
481
|
+
iX.chgVal(v, iY[CIM.varI(v.name())])
|
|
482
|
+
dX = True
|
|
483
|
+
for v in sX:
|
|
484
|
+
# checks if the variable v from sX changes value over the transition
|
|
485
|
+
if iX[CIM.varI(v)] != iX[CIM.varJ(v)]:
|
|
486
|
+
dX = False
|
|
487
|
+
break
|
|
488
|
+
dY = True
|
|
489
|
+
for v in sY:
|
|
490
|
+
if iY[CIM.varI(v)] != iY[CIM.varJ(v)]:
|
|
491
|
+
dY = False
|
|
492
|
+
break
|
|
493
|
+
if dX and dY: # case where both states don't change
|
|
494
|
+
amal[i] = cimX[iX] + cimY[iY]
|
|
495
|
+
elif dY: # case were one of iX variables changes value but none of iY does
|
|
496
|
+
amal[i] = cimX[iX]
|
|
497
|
+
elif dX: # case were one of iY variables changes value but none of iX does
|
|
498
|
+
amal[i] = cimY[iY]
|
|
499
|
+
else: # case were 2 variables from iX and iY change value at the sime time
|
|
500
|
+
amal[i] = 0
|
|
501
|
+
|
|
502
|
+
i.inc() # next combination of variables
|
|
503
|
+
|
|
504
|
+
return amal
|
|
505
|
+
|
|
506
|
+
def getTensor(self) -> "pyagrum.Tensor":
|
|
507
|
+
"""
|
|
508
|
+
Returns
|
|
509
|
+
-------
|
|
510
|
+
pyagrum.Tensor
|
|
511
|
+
A copy of the CIM's tensor
|
|
512
|
+
"""
|
|
513
|
+
return pyagrum.Tensor(self._pot)
|