CUQIpy 1.2.0.post0.dev380__tar.gz → 1.2.0.post0.dev409__tar.gz
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.
Potentially problematic release.
This version of CUQIpy might be problematic. Click here for more details.
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/CUQIpy.egg-info/PKG-INFO +2 -2
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/CUQIpy.egg-info/SOURCES.txt +2 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/PKG-INFO +2 -2
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/_version.py +3 -3
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/__init__.py +1 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/algebra/_ast.py +19 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/algebra/_orderedset.py +23 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/algebra/_randomvariable.py +78 -7
- cuqipy-1.2.0.post0.dev409/cuqi/experimental/geometry/__init__.py +1 -0
- cuqipy-1.2.0.post0.dev409/cuqi/experimental/geometry/_productgeometry.py +181 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/likelihood/_likelihood.py +8 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/CUQIpy.egg-info/dependency_links.txt +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/CUQIpy.egg-info/requires.txt +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/CUQIpy.egg-info/top_level.txt +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/LICENSE +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/README.md +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/_messages.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/array/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/array/_array.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/config.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/data/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/data/_data.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/data/astronaut.npz +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/data/camera.npz +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/data/cat.npz +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/data/cookie.png +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/data/satellite.mat +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/density/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/density/_density.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/diagnostics.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_beta.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_cauchy.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_cmrf.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_custom.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_distribution.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_gamma.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_gaussian.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_gmrf.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_inverse_gamma.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_joint_distribution.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_laplace.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_lmrf.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_lognormal.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_modifiedhalfnormal.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_normal.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_posterior.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_smoothed_laplace.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_truncated_normal.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_uniform.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/algebra/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_conjugate.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_conjugate_approx.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_cwmh.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_direct.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_gibbs.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_hmc.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_langevin_algorithm.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_laplace_approximation.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_mh.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_pcn.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_rto.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_sampler.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_utilities.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/geometry/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/geometry/_geometry.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/implicitprior/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/implicitprior/_regularizedGMRF.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/implicitprior/_regularizedGaussian.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/implicitprior/_regularizedUnboundedUniform.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/implicitprior/_restorator.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/likelihood/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/model/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/model/_model.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/operator/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/operator/_operator.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/pde/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/pde/_pde.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/problem/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/problem/_problem.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_conjugate.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_conjugate_approx.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_cwmh.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_gibbs.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_hmc.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_langevin_algorithm.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_laplace_approximation.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_mh.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_pcn.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_rto.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_sampler.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/samples/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/samples/_samples.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/solver/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/solver/_solver.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/testproblem/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/testproblem/_testproblem.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/utilities/__init__.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/utilities/_get_python_variable_name.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/utilities/_utilities.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/pyproject.toml +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/requirements.txt +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/setup.cfg +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/setup.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_MRFs.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_abstract_distribution_density.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_bayesian_inversion.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_density.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_distribution.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_distributions_shape.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_geometry.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_implicit_priors.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_joint_distribution.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_likelihood.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_model.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_pde.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_posterior.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_problem.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_sampler.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_samples.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_solver.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_testproblem.py +0 -0
- {cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_utilities.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: CUQIpy
|
|
3
|
-
Version: 1.2.0.post0.
|
|
3
|
+
Version: 1.2.0.post0.dev409
|
|
4
4
|
Summary: Computational Uncertainty Quantification for Inverse problems in Python
|
|
5
5
|
Maintainer-email: "Nicolai A. B. Riis" <nabr@dtu.dk>, "Jakob S. Jørgensen" <jakj@dtu.dk>, "Amal M. Alghamdi" <amaal@dtu.dk>, Chao Zhang <chaz@dtu.dk>
|
|
6
6
|
License: Apache License
|
|
@@ -49,6 +49,8 @@ cuqi/experimental/algebra/__init__.py
|
|
|
49
49
|
cuqi/experimental/algebra/_ast.py
|
|
50
50
|
cuqi/experimental/algebra/_orderedset.py
|
|
51
51
|
cuqi/experimental/algebra/_randomvariable.py
|
|
52
|
+
cuqi/experimental/geometry/__init__.py
|
|
53
|
+
cuqi/experimental/geometry/_productgeometry.py
|
|
52
54
|
cuqi/experimental/mcmc/__init__.py
|
|
53
55
|
cuqi/experimental/mcmc/_conjugate.py
|
|
54
56
|
cuqi/experimental/mcmc/_conjugate_approx.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: CUQIpy
|
|
3
|
-
Version: 1.2.0.post0.
|
|
3
|
+
Version: 1.2.0.post0.dev409
|
|
4
4
|
Summary: Computational Uncertainty Quantification for Inverse problems in Python
|
|
5
5
|
Maintainer-email: "Nicolai A. B. Riis" <nabr@dtu.dk>, "Jakob S. Jørgensen" <jakj@dtu.dk>, "Amal M. Alghamdi" <amaal@dtu.dk>, Chao Zhang <chaz@dtu.dk>
|
|
6
6
|
License: Apache License
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "
|
|
11
|
+
"date": "2025-01-14T23:39:18+0100",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "1.2.0.post0.
|
|
14
|
+
"full-revisionid": "4d0949ea5c777b95d3c216f22c17e267e5cf15ff",
|
|
15
|
+
"version": "1.2.0.post0.dev409"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -51,6 +51,11 @@ class Node(ABC):
|
|
|
51
51
|
"""Evaluate node at a given parameter value. This will traverse the sub-tree originated at this node and evaluate it given the recorded operations."""
|
|
52
52
|
pass
|
|
53
53
|
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def condition(self, **kwargs):
|
|
56
|
+
""" Conditions the tree by replacing any VariableNode with a ValueNode if the variable is in the kwargs dictionary. """
|
|
57
|
+
pass
|
|
58
|
+
|
|
54
59
|
@abstractmethod
|
|
55
60
|
def __repr__(self):
|
|
56
61
|
"""String representation of the node. Used for printing the AST."""
|
|
@@ -129,6 +134,9 @@ class UnaryNode(Node, ABC):
|
|
|
129
134
|
def __init__(self, child: Node):
|
|
130
135
|
self.child = child
|
|
131
136
|
|
|
137
|
+
def condition(self, **kwargs):
|
|
138
|
+
return self.__class__(self.child.condition(**kwargs))
|
|
139
|
+
|
|
132
140
|
|
|
133
141
|
class BinaryNode(Node, ABC):
|
|
134
142
|
"""Base class for all binary nodes in the abstract syntax tree.
|
|
@@ -155,6 +163,9 @@ class BinaryNode(Node, ABC):
|
|
|
155
163
|
self.left = left
|
|
156
164
|
self.right = right
|
|
157
165
|
|
|
166
|
+
def condition(self, **kwargs):
|
|
167
|
+
return self.__class__(self.left.condition(**kwargs), self.right.condition(**kwargs))
|
|
168
|
+
|
|
158
169
|
def __repr__(self):
|
|
159
170
|
return f"{self.left} {self.op_symbol} {self.right}"
|
|
160
171
|
|
|
@@ -205,6 +216,11 @@ class VariableNode(Node):
|
|
|
205
216
|
)
|
|
206
217
|
return kwargs[self.name]
|
|
207
218
|
|
|
219
|
+
def condition(self, **kwargs):
|
|
220
|
+
if self.name in kwargs:
|
|
221
|
+
return ValueNode(kwargs[self.name])
|
|
222
|
+
return self
|
|
223
|
+
|
|
208
224
|
def __repr__(self):
|
|
209
225
|
return self.name
|
|
210
226
|
|
|
@@ -226,6 +242,9 @@ class ValueNode(Node):
|
|
|
226
242
|
"""Returns the value of the node."""
|
|
227
243
|
return self.value
|
|
228
244
|
|
|
245
|
+
def condition(self, **kwargs):
|
|
246
|
+
return self
|
|
247
|
+
|
|
229
248
|
def __repr__(self):
|
|
230
249
|
return str(self.value)
|
|
231
250
|
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/algebra/_orderedset.py
RENAMED
|
@@ -19,6 +19,13 @@ class _OrderedSet:
|
|
|
19
19
|
"""
|
|
20
20
|
self.dict[item] = None
|
|
21
21
|
|
|
22
|
+
def remove(self, item):
|
|
23
|
+
"""Remove an item from the set.
|
|
24
|
+
|
|
25
|
+
If the item is not in the set, it raises a KeyError.
|
|
26
|
+
"""
|
|
27
|
+
del self.dict[item]
|
|
28
|
+
|
|
22
29
|
def __contains__(self, item):
|
|
23
30
|
"""Check if an item is in the set.
|
|
24
31
|
|
|
@@ -47,6 +54,18 @@ class _OrderedSet:
|
|
|
47
54
|
for item in other:
|
|
48
55
|
self.add(item)
|
|
49
56
|
|
|
57
|
+
def replace(self, old_item, new_item):
|
|
58
|
+
"""Replace old_item with new_item at the same position, preserving order."""
|
|
59
|
+
if old_item not in self.dict:
|
|
60
|
+
raise KeyError(f"{old_item} not in set")
|
|
61
|
+
|
|
62
|
+
items = list(self.dict.keys()) # Preserve order
|
|
63
|
+
index = items.index(old_item) # Find position
|
|
64
|
+
items[index] = new_item # Replace at the same position
|
|
65
|
+
|
|
66
|
+
# Reconstruct the ordered set with the new item in place
|
|
67
|
+
self.dict = dict.fromkeys(items)
|
|
68
|
+
|
|
50
69
|
def __or__(self, other):
|
|
51
70
|
"""Return a new set that is the union of this set and another set.
|
|
52
71
|
|
|
@@ -57,3 +76,7 @@ class _OrderedSet:
|
|
|
57
76
|
new_set = _OrderedSet(self.dict.keys())
|
|
58
77
|
new_set.extend(other)
|
|
59
78
|
return new_set
|
|
79
|
+
|
|
80
|
+
def __repr__(self):
|
|
81
|
+
"""Return a string representation of the set."""
|
|
82
|
+
return "_OrderedSet({})".format(list(self.dict.keys()))
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/algebra/_randomvariable.py
RENAMED
|
@@ -5,8 +5,7 @@ from ._orderedset import _OrderedSet
|
|
|
5
5
|
import operator
|
|
6
6
|
import cuqi
|
|
7
7
|
from cuqi.distribution import Distribution
|
|
8
|
-
from copy import copy
|
|
9
|
-
|
|
8
|
+
from copy import copy, deepcopy
|
|
10
9
|
|
|
11
10
|
class RandomVariable:
|
|
12
11
|
""" Random variable defined by a distribution with the option to apply algebraic operations on it.
|
|
@@ -210,7 +209,7 @@ class RandomVariable:
|
|
|
210
209
|
def parameter_names(self) -> str:
|
|
211
210
|
""" Name of the parameter that the random variable can be evaluated at. """
|
|
212
211
|
self._inject_name_into_distribution()
|
|
213
|
-
return [distribution.
|
|
212
|
+
return [distribution._name for distribution in self.distributions] # Consider renaming .name to .par_name for distributions
|
|
214
213
|
|
|
215
214
|
@property
|
|
216
215
|
def dim(self):
|
|
@@ -239,7 +238,57 @@ class RandomVariable:
|
|
|
239
238
|
def is_transformed(self):
|
|
240
239
|
""" Returns True if the random variable is transformed. """
|
|
241
240
|
return not isinstance(self.tree, VariableNode)
|
|
242
|
-
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def is_cond(self):
|
|
244
|
+
""" Returns True if the random variable is a conditional random variable. """
|
|
245
|
+
return any(dist.is_cond for dist in self.distributions)
|
|
246
|
+
|
|
247
|
+
def condition(self, *args, **kwargs):
|
|
248
|
+
"""Condition the random variable on a given value. Only one of either positional or keyword arguments can be passed.
|
|
249
|
+
|
|
250
|
+
Parameters
|
|
251
|
+
----------
|
|
252
|
+
*args : Any
|
|
253
|
+
Positional arguments to condition the random variable on. The order of the arguments must match the order of the parameter names.
|
|
254
|
+
|
|
255
|
+
**kwargs : Any
|
|
256
|
+
Keyword arguments to condition the random variable on. The keys must match the parameter names.
|
|
257
|
+
|
|
258
|
+
"""
|
|
259
|
+
|
|
260
|
+
# Before conditioning, capture repr to ensure all variable names are injected
|
|
261
|
+
self.__repr__()
|
|
262
|
+
|
|
263
|
+
if args and kwargs:
|
|
264
|
+
raise ValueError("Cannot pass both positional and keyword arguments to RandomVariable")
|
|
265
|
+
|
|
266
|
+
if args:
|
|
267
|
+
kwargs = self._parse_args_add_to_kwargs(args, kwargs)
|
|
268
|
+
|
|
269
|
+
# Create a deep copy of the random variable to ensure the original tree is not modified
|
|
270
|
+
new_variable = self._make_copy(deep=True)
|
|
271
|
+
|
|
272
|
+
for kwargs_name in list(kwargs.keys()):
|
|
273
|
+
value = kwargs.pop(kwargs_name)
|
|
274
|
+
|
|
275
|
+
# Condition the tree turning the variable into a constant
|
|
276
|
+
if kwargs_name in self.parameter_names:
|
|
277
|
+
new_variable._tree = new_variable.tree.condition(**{kwargs_name: value})
|
|
278
|
+
|
|
279
|
+
# Condition the random variable on both the distribution parameter name and distribution conditioning variables
|
|
280
|
+
for dist in self.distributions:
|
|
281
|
+
if kwargs_name == dist.name:
|
|
282
|
+
new_variable._remove_distribution(dist.name)
|
|
283
|
+
elif kwargs_name in dist.get_conditioning_variables():
|
|
284
|
+
new_variable._replace_distribution(dist.name, dist(**{kwargs_name: value}))
|
|
285
|
+
|
|
286
|
+
# Check if any kwargs are left unprocessed
|
|
287
|
+
if kwargs:
|
|
288
|
+
raise ValueError(f"Conditioning variables {list(kwargs.keys())} not found in the random variable {self}")
|
|
289
|
+
|
|
290
|
+
return new_variable
|
|
291
|
+
|
|
243
292
|
@property
|
|
244
293
|
def _non_default_args(self) -> List[str]:
|
|
245
294
|
"""List of non-default arguments to distribution. This is used to return the correct
|
|
@@ -247,13 +296,31 @@ class RandomVariable:
|
|
|
247
296
|
"""
|
|
248
297
|
return self.parameter_names
|
|
249
298
|
|
|
299
|
+
def _replace_distribution(self, name, new_distribution):
|
|
300
|
+
""" Replace distribution with a given name with a new distribution in the same position of the ordered set. """
|
|
301
|
+
for dist in self.distributions:
|
|
302
|
+
if dist._name == name:
|
|
303
|
+
self._distributions.replace(dist, new_distribution)
|
|
304
|
+
break
|
|
305
|
+
|
|
306
|
+
def _remove_distribution(self, name):
|
|
307
|
+
""" Remove distribution with a given name from the set of distributions. """
|
|
308
|
+
for dist in self.distributions:
|
|
309
|
+
if dist._name == name:
|
|
310
|
+
self._distributions.remove(dist)
|
|
311
|
+
break
|
|
312
|
+
|
|
250
313
|
def _inject_name_into_distribution(self, name=None):
|
|
251
314
|
if len(self._distributions) == 1:
|
|
252
315
|
dist = next(iter(self._distributions))
|
|
316
|
+
|
|
317
|
+
if dist._is_copy:
|
|
318
|
+
dist = dist._original_density
|
|
319
|
+
|
|
253
320
|
if dist._name is None:
|
|
254
321
|
if name is None:
|
|
255
322
|
name = self.name
|
|
256
|
-
dist.
|
|
323
|
+
dist.name = name # Inject using setter
|
|
257
324
|
|
|
258
325
|
def _parse_args_add_to_kwargs(self, args, kwargs) -> dict:
|
|
259
326
|
""" Parse args and add to kwargs if any. Arguments follow self.parameter_names order. """
|
|
@@ -293,8 +360,12 @@ class RandomVariable:
|
|
|
293
360
|
""" Returns True if this is a copy of another random variable, e.g. by conditioning. """
|
|
294
361
|
return hasattr(self, '_original_variable') and self._original_variable is not None
|
|
295
362
|
|
|
296
|
-
def _make_copy(self):
|
|
297
|
-
""" Returns a
|
|
363
|
+
def _make_copy(self, deep=False) -> 'RandomVariable':
|
|
364
|
+
""" Returns a copy of the density keeping a pointer to the original. """
|
|
365
|
+
if deep:
|
|
366
|
+
new_variable = deepcopy(self)
|
|
367
|
+
new_variable._original_variable = self
|
|
368
|
+
return new_variable
|
|
298
369
|
new_variable = copy(self)
|
|
299
370
|
new_variable._distributions = copy(self.distributions)
|
|
300
371
|
new_variable._tree = copy(self._tree)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from ._productgeometry import _ProductGeometry
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
from cuqi.geometry import Geometry
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
class _ProductGeometry(Geometry):
|
|
5
|
+
""" A class for representing a product geometry. A product geometry
|
|
6
|
+
represents the product space of multiple geometries of type :class:`Geometry`.
|
|
7
|
+
See the example below for a product geometry of two geometries.
|
|
8
|
+
|
|
9
|
+
Parameters
|
|
10
|
+
----------
|
|
11
|
+
\*geometries : cuqi.geometry.Geometry
|
|
12
|
+
The geometries to be combined into a product geometry. Each geometry
|
|
13
|
+
is passed as a comma-separated argument.
|
|
14
|
+
|
|
15
|
+
Example
|
|
16
|
+
-------
|
|
17
|
+
.. code-block:: python
|
|
18
|
+
import numpy as np
|
|
19
|
+
from cuqi.geometry import Continuous1D, Discrete
|
|
20
|
+
from cuqi.experimental.geometry import _ProductGeometry
|
|
21
|
+
geometry1 = Continuous1D(np.linspace(0, 1, 100))
|
|
22
|
+
geometry2 = Discrete(["sound_speed"])
|
|
23
|
+
product_geometry = _ProductGeometry(geometry1, geometry2)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, *geometries):
|
|
27
|
+
self.geometries = geometries
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def geometries(self):
|
|
31
|
+
"""List of geometries that are combined to form the product geometry."""
|
|
32
|
+
return self._geometries
|
|
33
|
+
|
|
34
|
+
@geometries.setter
|
|
35
|
+
def geometries(self, geometries):
|
|
36
|
+
# Check if all geometries are of type Geometry.
|
|
37
|
+
for g in geometries:
|
|
38
|
+
if not isinstance(g, Geometry):
|
|
39
|
+
raise TypeError(
|
|
40
|
+
"All geometries must be of type Geometry. "
|
|
41
|
+
"Received: {}".format(type(g))
|
|
42
|
+
)
|
|
43
|
+
self._geometries = geometries
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def fun_shape(self):
|
|
47
|
+
"""Shape of the function representation. Returns a tuple, where
|
|
48
|
+
each element of the tuple is the shape of the function
|
|
49
|
+
representation of each geometry."""
|
|
50
|
+
return tuple([g.fun_shape for g in self.geometries])
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def fun_dim(self):
|
|
54
|
+
"""Dimension of the function representation which is the sum of
|
|
55
|
+
the function representation dimensions of each geometry."""
|
|
56
|
+
return sum([g.fun_dim for g in self.geometries])
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def par_shape(self):
|
|
60
|
+
"""Shape of the parameter representation. Returns a tuple, where
|
|
61
|
+
each element of the tuple is the shape of the parameter
|
|
62
|
+
representation of each geometry."""
|
|
63
|
+
return tuple([g.par_shape for g in self.geometries])
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def par_dim(self):
|
|
67
|
+
"""Dimension of the parameter representation which is the sum of
|
|
68
|
+
the parameter representation dimensions of each geometry."""
|
|
69
|
+
return sum(self.par_dim_list)
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def par_dim_list(self):
|
|
73
|
+
"""List of the parameter representation dimensions of each
|
|
74
|
+
geometry. This property is useful for indexing a stacked parameter
|
|
75
|
+
vector."""
|
|
76
|
+
return [g.par_dim for g in self.geometries]
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def stacked_par_split_indices(self):
|
|
80
|
+
"""Indices at which the stacked parameter vector should be split
|
|
81
|
+
to obtain the parameter vectors for each geometry. For example, if
|
|
82
|
+
the stacked parameter vector is [1, 2, 3, 4, 5, 6] and the parameter
|
|
83
|
+
vectors for each geometry are [1, 2], [3, 4], and [5, 6], then the
|
|
84
|
+
split indices are [2, 4]"""
|
|
85
|
+
return np.cumsum(self.par_dim_list[:-1])
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def number_of_geometries(self):
|
|
89
|
+
"""Number of geometries in the product geometry."""
|
|
90
|
+
return len(self.geometries)
|
|
91
|
+
|
|
92
|
+
def _split_par(self, par):
|
|
93
|
+
"""Splits a stacked parameter vector into parameter vectors for each
|
|
94
|
+
geometry."""
|
|
95
|
+
return tuple(np.split(par, self.stacked_par_split_indices))
|
|
96
|
+
|
|
97
|
+
def _plot(self, values, **kwargs):
|
|
98
|
+
"""Plotting function for the product geometry."""
|
|
99
|
+
raise NotImplementedError(
|
|
100
|
+
f"Plotting not implemented for {self.__class__.__name__}.")
|
|
101
|
+
|
|
102
|
+
def par2fun(self, *pars):
|
|
103
|
+
"""Converts parameter vector(s) into function values for each
|
|
104
|
+
geometry. The parameter vector can be stacked (all parameters are
|
|
105
|
+
in one vector) or unstacked (one parameter vector corresponds to
|
|
106
|
+
each geometry). In all cases, the order of the parameter vectors
|
|
107
|
+
should follow the order of the geometries in the product, i.e., the
|
|
108
|
+
first parameter vector corresponds to the first geometry and so on."""
|
|
109
|
+
|
|
110
|
+
# If one argument is passed, then it is assumed that the parameter
|
|
111
|
+
# vector is stacked and split it.
|
|
112
|
+
# No effect if the parameter vector is already split and corresponds
|
|
113
|
+
# to one geometry.
|
|
114
|
+
if len(pars) == 1:
|
|
115
|
+
pars = self._split_par(pars[0])
|
|
116
|
+
|
|
117
|
+
# Convert parameter vectors to function values for each geometry.
|
|
118
|
+
funvals = []
|
|
119
|
+
for i, g in enumerate(self.geometries):
|
|
120
|
+
funval_i = g.par2fun(pars[i])
|
|
121
|
+
funvals.append(funval_i)
|
|
122
|
+
return tuple(funvals)
|
|
123
|
+
|
|
124
|
+
def fun2par(self, *funvals, stacked=False):
|
|
125
|
+
"""Converts (multiple) function values into the corresponding
|
|
126
|
+
parameter vectors. If the flag stacked is set to True, then the
|
|
127
|
+
parameter vectors are stacked into one vector. Otherwise, the
|
|
128
|
+
parameter vectors are returned as a tuple. The order of function
|
|
129
|
+
values should follow the order of the geometries in the product,
|
|
130
|
+
i.e., the first function value corresponds to the first geometry
|
|
131
|
+
and so on."""
|
|
132
|
+
|
|
133
|
+
pars = []
|
|
134
|
+
for i, g in enumerate(self.geometries):
|
|
135
|
+
par_i = g.fun2par(funvals[i])
|
|
136
|
+
pars.append(par_i)
|
|
137
|
+
|
|
138
|
+
# stack parameters:
|
|
139
|
+
if stacked:
|
|
140
|
+
# if single sample
|
|
141
|
+
if len(pars[0].shape) == 1:
|
|
142
|
+
stacked_val = np.hstack(pars)
|
|
143
|
+
elif len(pars[0].shape) == 2:
|
|
144
|
+
stacked_val = np.vstack(pars)
|
|
145
|
+
else:
|
|
146
|
+
raise ValueError(
|
|
147
|
+
"Cannot stack parameter vectors with more than 2 dimensions."
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return stacked_val if stacked else tuple(pars)
|
|
151
|
+
|
|
152
|
+
def vec2fun(self, *funvecs):
|
|
153
|
+
"""Maps function vector representation, if available, to function
|
|
154
|
+
values. The order of the function vectors should follow the order of
|
|
155
|
+
the geometries in the product, i.e., the first function vector
|
|
156
|
+
corresponds to the first geometry and so on."""
|
|
157
|
+
funvals = []
|
|
158
|
+
for i, g in enumerate(self.geometries):
|
|
159
|
+
funvals.append(g.vec2fun(funvecs[i]))
|
|
160
|
+
|
|
161
|
+
return tuple(funvals)
|
|
162
|
+
|
|
163
|
+
def fun2vec(self, *funvals):
|
|
164
|
+
"""Maps function values to a vector representation of the function
|
|
165
|
+
values, if available. The order of the function values should follow
|
|
166
|
+
the order of the geometries in the product, i.e., the first function
|
|
167
|
+
value corresponds to the first geometry and so on."""
|
|
168
|
+
funvecs = []
|
|
169
|
+
for i, g in enumerate(self.geometries):
|
|
170
|
+
funvecs.append(g.fun2vec(funvals[i]))
|
|
171
|
+
|
|
172
|
+
return tuple(funvecs)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def __repr__(self) -> str:
|
|
176
|
+
"""Representation of the product geometry."""
|
|
177
|
+
string = "{}(".format(self.__class__.__name__) + "\n"
|
|
178
|
+
for g in self.geometries:
|
|
179
|
+
string += "\t{}\n".format(g.__repr__())
|
|
180
|
+
string += ")"
|
|
181
|
+
return string
|
|
@@ -43,6 +43,14 @@ class Likelihood(Density):
|
|
|
43
43
|
def name(self, value):
|
|
44
44
|
self.distribution.name = value
|
|
45
45
|
|
|
46
|
+
@property
|
|
47
|
+
def _name(self):
|
|
48
|
+
return self.distribution._name
|
|
49
|
+
|
|
50
|
+
@_name.setter
|
|
51
|
+
def _name(self, value):
|
|
52
|
+
self.distribution._name = value
|
|
53
|
+
|
|
46
54
|
@property
|
|
47
55
|
def FD_enabled(self):
|
|
48
56
|
""" Return FD_enabled of the likelihood from the underlying distribution """
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/CUQIpy.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_joint_distribution.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_modifiedhalfnormal.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_smoothed_laplace.py
RENAMED
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/distribution/_truncated_normal.py
RENAMED
|
File without changes
|
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/algebra/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_conjugate.py
RENAMED
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_conjugate_approx.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/experimental/mcmc/_utilities.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/implicitprior/_regularizedGMRF.py
RENAMED
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/implicitprior/_regularizedGaussian.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/sampler/_laplace_approximation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/cuqi/utilities/_get_python_variable_name.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cuqipy-1.2.0.post0.dev380 → cuqipy-1.2.0.post0.dev409}/tests/test_abstract_distribution_density.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|