CUQIpy 1.1.0.post0.dev47__tar.gz → 1.1.1.post0.dev5__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.

Files changed (118) hide show
  1. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/CUQIpy.egg-info/PKG-INFO +1 -1
  2. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/PKG-INFO +1 -1
  3. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/_version.py +3 -3
  4. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_joint_distribution.py +21 -5
  5. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_joint_distribution.py +83 -0
  6. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/CUQIpy.egg-info/SOURCES.txt +0 -0
  7. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/CUQIpy.egg-info/dependency_links.txt +0 -0
  8. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/CUQIpy.egg-info/requires.txt +0 -0
  9. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/CUQIpy.egg-info/top_level.txt +0 -0
  10. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/LICENSE +0 -0
  11. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/README.md +0 -0
  12. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/__init__.py +0 -0
  13. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/_messages.py +0 -0
  14. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/array/__init__.py +0 -0
  15. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/array/_array.py +0 -0
  16. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/config.py +0 -0
  17. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/data/__init__.py +0 -0
  18. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/data/_data.py +0 -0
  19. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/data/astronaut.npz +0 -0
  20. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/data/camera.npz +0 -0
  21. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/data/cat.npz +0 -0
  22. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/data/cookie.png +0 -0
  23. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/data/satellite.mat +0 -0
  24. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/density/__init__.py +0 -0
  25. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/density/_density.py +0 -0
  26. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/diagnostics.py +0 -0
  27. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/__init__.py +0 -0
  28. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_beta.py +0 -0
  29. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_cauchy.py +0 -0
  30. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_cmrf.py +0 -0
  31. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_custom.py +0 -0
  32. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_distribution.py +0 -0
  33. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_gamma.py +0 -0
  34. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_gaussian.py +0 -0
  35. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_gmrf.py +0 -0
  36. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_inverse_gamma.py +0 -0
  37. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_laplace.py +0 -0
  38. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_lmrf.py +0 -0
  39. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_lognormal.py +0 -0
  40. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_modifiedhalfnormal.py +0 -0
  41. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_normal.py +0 -0
  42. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_posterior.py +0 -0
  43. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_smoothed_laplace.py +0 -0
  44. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/distribution/_uniform.py +0 -0
  45. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/__init__.py +0 -0
  46. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/__init__.py +0 -0
  47. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_conjugate.py +0 -0
  48. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_conjugate_approx.py +0 -0
  49. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_cwmh.py +0 -0
  50. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_direct.py +0 -0
  51. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_gibbs.py +0 -0
  52. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_hmc.py +0 -0
  53. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_langevin_algorithm.py +0 -0
  54. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_laplace_approximation.py +0 -0
  55. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_mh.py +0 -0
  56. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_pcn.py +0 -0
  57. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_rto.py +0 -0
  58. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_sampler.py +0 -0
  59. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/experimental/mcmc/_utilities.py +0 -0
  60. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/geometry/__init__.py +0 -0
  61. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/geometry/_geometry.py +0 -0
  62. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/implicitprior/__init__.py +0 -0
  63. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/implicitprior/_regularizedGMRF.py +0 -0
  64. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/implicitprior/_regularizedGaussian.py +0 -0
  65. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/implicitprior/_regularizedUnboundedUniform.py +0 -0
  66. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/likelihood/__init__.py +0 -0
  67. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/likelihood/_likelihood.py +0 -0
  68. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/model/__init__.py +0 -0
  69. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/model/_model.py +0 -0
  70. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/operator/__init__.py +0 -0
  71. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/operator/_operator.py +0 -0
  72. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/pde/__init__.py +0 -0
  73. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/pde/_pde.py +0 -0
  74. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/problem/__init__.py +0 -0
  75. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/problem/_problem.py +0 -0
  76. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/__init__.py +0 -0
  77. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_conjugate.py +0 -0
  78. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_conjugate_approx.py +0 -0
  79. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_cwmh.py +0 -0
  80. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_gibbs.py +0 -0
  81. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_hmc.py +0 -0
  82. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_langevin_algorithm.py +0 -0
  83. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_laplace_approximation.py +0 -0
  84. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_mh.py +0 -0
  85. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_pcn.py +0 -0
  86. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_rto.py +0 -0
  87. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/sampler/_sampler.py +0 -0
  88. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/samples/__init__.py +0 -0
  89. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/samples/_samples.py +0 -0
  90. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/solver/__init__.py +0 -0
  91. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/solver/_solver.py +0 -0
  92. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/testproblem/__init__.py +0 -0
  93. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/testproblem/_testproblem.py +0 -0
  94. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/utilities/__init__.py +0 -0
  95. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/utilities/_get_python_variable_name.py +0 -0
  96. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/cuqi/utilities/_utilities.py +0 -0
  97. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/pyproject.toml +0 -0
  98. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/requirements.txt +0 -0
  99. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/setup.cfg +0 -0
  100. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/setup.py +0 -0
  101. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_MRFs.py +0 -0
  102. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_abstract_distribution_density.py +0 -0
  103. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_bayesian_inversion.py +0 -0
  104. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_density.py +0 -0
  105. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_distribution.py +0 -0
  106. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_distributions_shape.py +0 -0
  107. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_geometry.py +0 -0
  108. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_implicit_priors.py +0 -0
  109. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_likelihood.py +0 -0
  110. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_model.py +0 -0
  111. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_pde.py +0 -0
  112. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_posterior.py +0 -0
  113. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_problem.py +0 -0
  114. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_sampler.py +0 -0
  115. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_samples.py +0 -0
  116. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_solver.py +0 -0
  117. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_testproblem.py +0 -0
  118. {cuqipy-1.1.0.post0.dev47 → cuqipy-1.1.1.post0.dev5}/tests/test_utilities.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: CUQIpy
3
- Version: 1.1.0.post0.dev47
3
+ Version: 1.1.1.post0.dev5
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: CUQIpy
3
- Version: 1.1.0.post0.dev47
3
+ Version: 1.1.1.post0.dev5
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": "2024-08-29T13:49:05+0200",
11
+ "date": "2024-08-31T21:02:04+0200",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "67dba338b95cc7c16357687a686de0a3c3e5b512",
15
- "version": "1.1.0.post0.dev47"
14
+ "full-revisionid": "b38281138379969a9a8c4683ba3ecf8a88031939",
15
+ "version": "1.1.1.post0.dev5"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -175,6 +175,10 @@ class JointDistribution:
175
175
  kwargs[ordered_keys[index]] = arg
176
176
  return kwargs
177
177
 
178
+ def _sum_evaluated_densities(self):
179
+ """ Return the sum of the evaluated densities in the joint distribution """
180
+ return sum([density.logd() for density in self._evaluated_densities])
181
+
178
182
  def _reduce_to_single_density(self):
179
183
  """ Reduce the joint distribution to a single density if possible.
180
184
 
@@ -183,7 +187,6 @@ class JointDistribution:
183
187
  This method is a hack to allow our current samplers to work with
184
188
  the joint distribution. It should be removed in the future.
185
189
  """
186
-
187
190
  # Count number of distributions and likelihoods
188
191
  n_dist = len(self._distributions)
189
192
  n_likelihood = len(self._likelihoods)
@@ -201,16 +204,29 @@ class JointDistribution:
201
204
  # Ensure parameter names match, otherwise return the joint distribution
202
205
  if set(self._likelihoods[0].get_parameter_names()) != set(self._distributions[0].get_parameter_names()):
203
206
  return self
204
- return Posterior(self._likelihoods[0], self._distributions[0])
205
-
207
+ return self._add_constants_to_density(Posterior(self._likelihoods[0], self._distributions[0]))
208
+
206
209
  # If exactly one distribution and no likelihoods its a Distribution
207
210
  if n_dist == 1 and n_likelihood == 0:
208
- return self._distributions[0]
209
-
211
+ return self._add_constants_to_density(self._distributions[0])
212
+
210
213
  # If no distributions and exactly one likelihood its a Likelihood
211
214
  if n_likelihood == 1 and n_dist == 0:
212
215
  return self._likelihoods[0]
213
216
 
217
+ # If only evaluated densities left return joint to ensure logd method is available
218
+ if n_dist == 0 and n_likelihood == 0:
219
+ return self
220
+
221
+ def _add_constants_to_density(self, density: Density):
222
+ """ Add the constants (evaluated densities) to a single density. Used when reducing to single density. """
223
+
224
+ if isinstance(density, EvaluatedDensity):
225
+ raise ValueError("Cannot add the sum of all evaluated densities to an EvaluatedDensity.")
226
+
227
+ density._constant += self._sum_evaluated_densities()
228
+ return density
229
+
214
230
  def _as_stacked(self) -> _StackedJointDistribution:
215
231
  """ Return a stacked JointDistribution with the same densities. """
216
232
  return _StackedJointDistribution(*self._densities)
@@ -310,3 +310,86 @@ def test_MultipleLikelihoodPosterior_should_raise_if_names_do_not_match():
310
310
  with pytest.raises(ValueError, match=r"the same parameter name"):
311
311
  cuqi.distribution.MultipleLikelihoodPosterior(y.to_likelihood(1), x, z)
312
312
 
313
+ @pytest.mark.parametrize("joint, variables", [
314
+ (
315
+ cuqi.distribution.JointDistribution(
316
+ cuqi.distribution.Normal(0, 1, name="x"),
317
+ cuqi.distribution.Normal(0, 1, name="y")
318
+ ),
319
+ {
320
+ "x": 0,
321
+ "y": 0
322
+ }
323
+ ),
324
+ (
325
+ cuqi.distribution.JointDistribution(
326
+ cuqi.distribution.Uniform(0, 10, name="d"),
327
+ cuqi.distribution.Uniform(0, 5, name="s"),
328
+ cuqi.distribution.Gaussian(np.zeros(8), lambda d: d, name="x"),
329
+ cuqi.distribution.Gaussian(
330
+ mean=cuqi.testproblem.Deconvolution1D(dim=8).model,
331
+ cov=lambda s: s,
332
+ name="y"
333
+ )
334
+ ),
335
+ {
336
+ "d": 5,
337
+ "s": 2,
338
+ "x": np.zeros(8),
339
+ "y": cuqi.testproblem.Deconvolution1D(dim=8).data
340
+ }
341
+ ),
342
+ (
343
+ cuqi.distribution.JointDistribution(
344
+ cuqi.distribution.Uniform(0, 10, name="d"),
345
+ cuqi.distribution.Uniform(0, 5, name="s"),
346
+ cuqi.distribution.Gaussian(np.zeros(8), lambda d: d, name="x"),
347
+ cuqi.distribution.Gaussian(
348
+ mean=cuqi.testproblem.Deconvolution1D(dim=8).model,
349
+ cov=lambda s: s,
350
+ name="y"
351
+ )
352
+ ),
353
+ {
354
+ "d": 11, # Out of bounds (all should return -Inf)
355
+ "s": 2,
356
+ "x": np.zeros(8),
357
+ "y": cuqi.testproblem.Deconvolution1D(dim=8).data
358
+ }
359
+ )
360
+ ]
361
+ )
362
+ def test_logd_consistency_when_conditioning(joint, variables):
363
+ """ Test consistency of logd value when conditioning the joint distribution.
364
+
365
+ This ensures we always return the correct value for logd even when reducing to single density.
366
+
367
+ """
368
+
369
+ # True value of logd by fully evaluating the joint distribution
370
+ true_value = joint.logd(**variables)
371
+
372
+ # Loop over all variables and evaluate the logd value
373
+ # where all previously seen variables are conditioned
374
+ # and not seen variables are given to logd.
375
+ cond_vars = {}
376
+ for key, value in variables.items():
377
+ # Remaining variables are those that are not used for conditioning
378
+ remaining_vars = {k: v for k, v in variables.items() if k not in cond_vars}
379
+
380
+ # Condition the joint distribution
381
+ cond_joint = joint(**cond_vars)
382
+
383
+ # Evaluate the logd value of conditioned joint distribution
384
+ # This may be a single density or a joint distribution since
385
+ # joint can reduce to single density (such as Posterior)
386
+ logd_value = cond_joint.logd(**remaining_vars)
387
+
388
+ # Potential error message if this assert fails:
389
+ msg = f"Evaluated: \n {joint} \n with variables {variables}.\nFailed at {key}={value} for \n {cond_joint} \n with variables {remaining_vars}."
390
+
391
+ # Assert the logd value matches
392
+ assert logd_value == pytest.approx(true_value, rel=1e-6), msg
393
+
394
+ # Add current variable to the variables that need to be conditioned
395
+ cond_vars[key] = value