CUQIpy 1.2.0.post0.dev42__py3-none-any.whl → 1.2.0.post0.dev90__py3-none-any.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.

Potentially problematic release.


This version of CUQIpy might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: CUQIpy
3
- Version: 1.2.0.post0.dev42
3
+ Version: 1.2.0.post0.dev90
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
  cuqi/__init__.py,sha256=LsGilhl-hBLEn6Glt8S_l0OJzAA1sKit_rui8h-D-p0,488
2
2
  cuqi/_messages.py,sha256=fzEBrZT2kbmfecBBPm7spVu7yHdxGARQB4QzXhJbCJ0,415
3
- cuqi/_version.py,sha256=8yG6yaTIxWU2I_4MDAqgTgzlSR5m8uT0oqard7PIDds,509
3
+ cuqi/_version.py,sha256=fadCQ-al0LVIaJsUncww5HgsVEcSF53R-lWs5uar-ow,509
4
4
  cuqi/config.py,sha256=wcYvz19wkeKW2EKCGIKJiTpWt5kdaxyt4imyRkvtTRA,526
5
5
  cuqi/diagnostics.py,sha256=5OrbJeqpynqRXOe5MtOKKhe7EAVdOEpHIqHnlMW9G_c,3029
6
6
  cuqi/array/__init__.py,sha256=-EeiaiWGNsE3twRS4dD814BIlfxEsNkTCZUc5gjOXb0,30
@@ -14,7 +14,7 @@ cuqi/data/cookie.png,sha256=mr6wUeoIUc5VC2qYj8vafOmTbcRwz0fHz4IIPK9_PnE,984680
14
14
  cuqi/data/satellite.mat,sha256=a0Nz_Ak-Y0m360dH74pa_rpk-MhaQ91ftGTKhQX7I8g,16373
15
15
  cuqi/density/__init__.py,sha256=0zfVcPgqdqiPkss5n_WP_PUt-G3ovHXjokhqEKIlLwA,48
16
16
  cuqi/density/_density.py,sha256=BG7gtP0cbFYLVgjYQGkNAhM95PR5ocBVLKRlOVX2PyM,7253
17
- cuqi/distribution/__init__.py,sha256=4vVLArg6NVzBj67vVioK8BY6wISJKb5cOxdoHMuUb_s,714
17
+ cuqi/distribution/__init__.py,sha256=Vvw-ge5HAF1now9n4rcwDicCsEUN9_jbbxlKxyzeUuY,761
18
18
  cuqi/distribution/_beta.py,sha256=lgN6PGoF9RXQtrMGqSaSBV0hw-LEsOfRTD2Q2L3-Ok4,2903
19
19
  cuqi/distribution/_cauchy.py,sha256=UsVXYz8HhagXN5fIWSAIyELqhsJAX_-wk9kkRGgRmA8,3296
20
20
  cuqi/distribution/_cmrf.py,sha256=tCbEulM_O7FB3C_W-3IqZp9zGHkTofCdFF0ybHc9UZI,3745
@@ -29,9 +29,10 @@ cuqi/distribution/_laplace.py,sha256=5exLvlzJm2AgfvZ3KUSkjfwlGwwbsktBxP8z0iLMik8
29
29
  cuqi/distribution/_lmrf.py,sha256=rdGoQ-fPe1oW6Z29P-l3woq0NX3_RxUQ2rzm1VzemNM,3290
30
30
  cuqi/distribution/_lognormal.py,sha256=8_hOFQ3iu88ujX8vxmfVEZ0fdmlhTY98PlG5PasPjEg,2612
31
31
  cuqi/distribution/_modifiedhalfnormal.py,sha256=eCg9YhH-zyX25V5WqdBwQykwG_90lm5Qc2901z7jFUE,7390
32
- cuqi/distribution/_normal.py,sha256=ohBk5bTZbDEkU0JqcNkkSQ4bDhTR2s-PXjA8d91L7Y4,1682
32
+ cuqi/distribution/_normal.py,sha256=vhIiAseW09IKh1uy0KUq7RP1IuY7hH5aNM1W_R8Gd_Q,2912
33
33
  cuqi/distribution/_posterior.py,sha256=zAfL0GECxekZ2lBt1W6_LN0U_xskMwK4VNce5xAF7ig,5018
34
34
  cuqi/distribution/_smoothed_laplace.py,sha256=p-1Y23mYA9omwiHGkEuv3T2mwcPAAoNlCr7T8osNkjE,2925
35
+ cuqi/distribution/_truncated_normal.py,sha256=sZkLYgnkGOyS_3ZxY7iw6L62t-Jh6shzsweRsRepN2k,4240
35
36
  cuqi/distribution/_uniform.py,sha256=KA8yQ6ZS3nQGS4PYJ4hpDg6Eq8EQKQvPsIpYfR8fj2w,1967
36
37
  cuqi/experimental/__init__.py,sha256=vhZvyMX6rl8Y0haqCzGLPz6PSUKyu75XMQbeDHqTTrw,83
37
38
  cuqi/experimental/mcmc/__init__.py,sha256=1sn0U6Ep0x5zv2602og2DkV3Bs8hNFOiq7C3VcMimVw,4472
@@ -85,8 +86,8 @@ cuqi/testproblem/_testproblem.py,sha256=x769LwwRdJdzIiZkcQUGb_5-vynNTNALXWKato7s
85
86
  cuqi/utilities/__init__.py,sha256=H7xpJe2UinjZftKvE2JuXtTi4DqtkR6uIezStAXwfGg,428
86
87
  cuqi/utilities/_get_python_variable_name.py,sha256=QwlBVj2koJRA8s8pWd554p7-ElcI7HUwY32HknaR92E,1827
87
88
  cuqi/utilities/_utilities.py,sha256=Jc4knn80vLoA7kgw9FzXwKVFGaNBOXiA9kgvltZU3Ao,11777
88
- CUQIpy-1.2.0.post0.dev42.dist-info/LICENSE,sha256=kJWRPrtRoQoZGXyyvu50Uc91X6_0XRaVfT0YZssicys,10799
89
- CUQIpy-1.2.0.post0.dev42.dist-info/METADATA,sha256=HICsNy9FiNUfy2rnCMBDZxqvBsM__s0hbLpGAOccHG0,18495
90
- CUQIpy-1.2.0.post0.dev42.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
91
- CUQIpy-1.2.0.post0.dev42.dist-info/top_level.txt,sha256=AgmgMc6TKfPPqbjV0kvAoCBN334i_Lwwojc7HE3ZwD0,5
92
- CUQIpy-1.2.0.post0.dev42.dist-info/RECORD,,
89
+ CUQIpy-1.2.0.post0.dev90.dist-info/LICENSE,sha256=kJWRPrtRoQoZGXyyvu50Uc91X6_0XRaVfT0YZssicys,10799
90
+ CUQIpy-1.2.0.post0.dev90.dist-info/METADATA,sha256=KBSZdCAb8ZYWIzYvHOZ4iqrog8QGiBynjOw0gbo_sis,18495
91
+ CUQIpy-1.2.0.post0.dev90.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
92
+ CUQIpy-1.2.0.post0.dev90.dist-info/top_level.txt,sha256=AgmgMc6TKfPPqbjV0kvAoCBN334i_Lwwojc7HE3ZwD0,5
93
+ CUQIpy-1.2.0.post0.dev90.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
cuqi/_version.py CHANGED
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-10-11T13:31:57+0300",
11
+ "date": "2024-11-03T22:18:33+0100",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "85645ceb5eccff9ab309005d62defa609b9f53b2",
15
- "version": "1.2.0.post0.dev42"
14
+ "full-revisionid": "8f8b00804a857370d46fd7bdf26cb9542a6b8f34",
15
+ "version": "1.2.0.post0.dev90"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -12,6 +12,7 @@ from ._laplace import Laplace
12
12
  from ._smoothed_laplace import SmoothedLaplace
13
13
  from ._lognormal import Lognormal
14
14
  from ._normal import Normal
15
+ from ._truncated_normal import TruncatedNormal
15
16
  from ._posterior import Posterior
16
17
  from ._uniform import Uniform
17
18
  from ._custom import UserDefinedDistribution, DistributionGallery
@@ -1,5 +1,8 @@
1
1
  import numpy as np
2
+ import numbers
2
3
  from scipy.special import erf
4
+ from cuqi.geometry import _get_identity_geometries
5
+ from cuqi.utilities import force_ndarray
3
6
  from cuqi.distribution import Distribution
4
7
 
5
8
  class Normal(Distribution):
@@ -27,6 +30,24 @@ class Normal(Distribution):
27
30
  self.mean = mean
28
31
  self.std = std
29
32
 
33
+ @property
34
+ def mean(self):
35
+ """ Mean of the distribution """
36
+ return self._mean
37
+
38
+ @mean.setter
39
+ def mean(self, value):
40
+ self._mean = force_ndarray(value, flatten=True)
41
+
42
+ @property
43
+ def std(self):
44
+ """ Std of the distribution """
45
+ return self._std
46
+
47
+ @std.setter
48
+ def std(self, value):
49
+ self._std = force_ndarray(value, flatten=True)
50
+
30
51
  def pdf(self, x):
31
52
  return np.prod(1/(self.std*np.sqrt(2*np.pi))*np.exp(-0.5*((x-self.mean)/self.std)**2))
32
53
 
@@ -36,6 +57,19 @@ class Normal(Distribution):
36
57
  def cdf(self, x):
37
58
  return np.prod(0.5*(1 + erf((x-self.mean)/(self.std*np.sqrt(2)))))
38
59
 
60
+ def _gradient(self, val, *args, **kwargs):
61
+ if not type(self.geometry) in _get_identity_geometries():
62
+ raise NotImplementedError("Gradient not implemented for distribution {} with geometry {}".format(self,self.geometry))
63
+ if not callable(self.mean):
64
+ return -(val-self.mean)/(self.std**2)
65
+ elif hasattr(self.mean, "gradient"): # for likelihood
66
+ model = self.mean
67
+ dev = val - model.forward(*args, **kwargs)
68
+ print(dev)
69
+ return model.gradient(1.0/(np.array(self.std)) @ dev, *args, **kwargs)
70
+ else:
71
+ raise NotImplementedError("Gradient not implemented for distribution {} with location {}".format(self,self.mean))
72
+
39
73
  def _sample(self,N=1, rng=None):
40
74
 
41
75
  """
@@ -0,0 +1,129 @@
1
+ import numpy as np
2
+ from scipy.special import erf
3
+ from cuqi.utilities import force_ndarray
4
+ from cuqi.distribution import Distribution
5
+ from cuqi.distribution import Normal
6
+
7
+ class TruncatedNormal(Distribution):
8
+ """
9
+ Truncated Normal probability distribution.
10
+
11
+ Generates instance of cuqi.distribution.TruncatedNormal.
12
+ It allows the user to specify upper and lower bounds on random variables
13
+ represented by a Normal distribution. This distribution is suitable for a
14
+ small dimension setup (e.g. `dim`=3 or 4). Using TruncatedNormal
15
+ Distribution with a larger dimension can lead to a high rejection rate when
16
+ used within MCMC samplers.
17
+
18
+ The variables of this distribution are iid.
19
+
20
+
21
+ Parameters
22
+ ------------
23
+ mean : float or array_like of floats
24
+ mean of distribution
25
+ std : float or array_like of floats
26
+ standard deviation
27
+ low : float or array_like of floats
28
+ lower bound of the distribution
29
+ high : float or array_like of floats
30
+ upper bound of the distribution
31
+
32
+ Example
33
+ -----------
34
+ .. code-block:: python
35
+
36
+ #Generate Normal with mean 0, standard deviation 1 and bounds [-2,2]
37
+ p = cuqi.distribution.TruncatedNormal(mean=0, std=1, low=-2, high=2)
38
+ samples = p.sample(5000)
39
+ """
40
+ def __init__(self, mean=None, std=None, low=-np.Inf, high=np.Inf, is_symmetric=False, **kwargs):
41
+ # Init from abstract distribution class
42
+ super().__init__(is_symmetric=is_symmetric, **kwargs)
43
+
44
+ # Init specific to this distribution
45
+ self.mean = mean
46
+ self.std = std
47
+ self.low = low
48
+ self.high = high
49
+
50
+ # Init underlying normal distribution
51
+ self._normal = Normal(self.mean, self.std, is_symmetric=True, **kwargs)
52
+
53
+ @property
54
+ def mean(self):
55
+ """ Mean of the distribution """
56
+ return self._mean
57
+
58
+ @mean.setter
59
+ def mean(self, value):
60
+ self._mean = force_ndarray(value, flatten=True)
61
+ if hasattr(self, '_normal'):
62
+ self._normal.mean = self._mean
63
+
64
+ @property
65
+ def std(self):
66
+ """ Std of the distribution """
67
+ return self._std
68
+
69
+ @std.setter
70
+ def std(self, value):
71
+ self._std = force_ndarray(value, flatten=True)
72
+ if hasattr(self, '_normal'):
73
+ self._normal.std = self._std
74
+
75
+ @property
76
+ def low(self):
77
+ """ Lower bound of the distribution """
78
+ return self._low
79
+
80
+ @low.setter
81
+ def low(self, value):
82
+ self._low = force_ndarray(value, flatten=True)
83
+
84
+ @property
85
+ def high(self):
86
+ """ Higher bound of the distribution """
87
+ return self._high
88
+
89
+ @high.setter
90
+ def high(self, value):
91
+ self._high = force_ndarray(value, flatten=True)
92
+
93
+ def logpdf(self, x):
94
+ """
95
+ Computes the unnormalized logpdf at the given values of x.
96
+ """
97
+ # the unnormalized logpdf
98
+ # check if x falls in the range between np.array a and b
99
+ if np.any(x < self.low) or np.any(x > self.high):
100
+ return -np.Inf
101
+ else:
102
+ return self._normal.logpdf(x)
103
+
104
+ def _gradient(self, x, *args, **kwargs):
105
+ """
106
+ Computes the gradient of the unnormalized logpdf at the given values of x.
107
+ """
108
+ # check if x falls in the range between np.array a and b
109
+ if np.any(x < self.low) or np.any(x > self.high):
110
+ return np.NaN*np.ones_like(x)
111
+ else:
112
+ return self._normal.gradient(x, *args, **kwargs)
113
+
114
+ def _sample(self, N=1, rng=None):
115
+ """
116
+ Generates random samples from the distribution.
117
+ """
118
+ max_iter = 1e9 # maximum number of trials to avoid infinite loop
119
+ samples = []
120
+ for i in range(int(max_iter)):
121
+ if len(samples) == N:
122
+ break
123
+ sample = self._normal.sample(1,rng)
124
+ if np.all(sample >= self.low) and np.all(sample <= self.high):
125
+ samples.append(sample)
126
+ # raise a error if the number of iterations exceeds max_iter
127
+ if i == max_iter-1:
128
+ raise RuntimeError("Failed to generate {} samples within {} iterations".format(N, max_iter))
129
+ return np.array(samples).T.reshape(-1,N)