CUQIpy 0.8.0.post0.dev2__py3-none-any.whl → 0.8.0.post0.dev13__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.
- {CUQIpy-0.8.0.post0.dev2.dist-info → CUQIpy-0.8.0.post0.dev13.dist-info}/METADATA +1 -1
- {CUQIpy-0.8.0.post0.dev2.dist-info → CUQIpy-0.8.0.post0.dev13.dist-info}/RECORD +9 -9
- cuqi/_version.py +3 -3
- cuqi/distribution/_cmrf.py +1 -1
- cuqi/distribution/_gmrf.py +49 -56
- cuqi/distribution/_lmrf.py +1 -1
- {CUQIpy-0.8.0.post0.dev2.dist-info → CUQIpy-0.8.0.post0.dev13.dist-info}/LICENSE +0 -0
- {CUQIpy-0.8.0.post0.dev2.dist-info → CUQIpy-0.8.0.post0.dev13.dist-info}/WHEEL +0 -0
- {CUQIpy-0.8.0.post0.dev2.dist-info → CUQIpy-0.8.0.post0.dev13.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: CUQIpy
|
|
3
|
-
Version: 0.8.0.post0.
|
|
3
|
+
Version: 0.8.0.post0.dev13
|
|
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=K0ss2HNqoLUX7wGpSZdaPKxIaKdRS452fcJm4D0pcEs,433
|
|
2
2
|
cuqi/_messages.py,sha256=fzEBrZT2kbmfecBBPm7spVu7yHdxGARQB4QzXhJbCJ0,415
|
|
3
|
-
cuqi/_version.py,sha256=
|
|
3
|
+
cuqi/_version.py,sha256=8o64V7liXM5C7qTDSlG8846YAX74kBBM_o5Zjl9Zpvw,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
|
|
@@ -16,16 +16,16 @@ cuqi/density/_density.py,sha256=BG7gtP0cbFYLVgjYQGkNAhM95PR5ocBVLKRlOVX2PyM,7253
|
|
|
16
16
|
cuqi/distribution/__init__.py,sha256=f85DzOHPvGec9nr_AIfp_THSuC4WN8ZUJMSLZrKClG8,615
|
|
17
17
|
cuqi/distribution/_beta.py,sha256=xQ6nURJqB20j1A8YNnpKO9BUcb-kKUdq8QCmljlm9l4,2980
|
|
18
18
|
cuqi/distribution/_cauchy.py,sha256=UsVXYz8HhagXN5fIWSAIyELqhsJAX_-wk9kkRGgRmA8,3296
|
|
19
|
-
cuqi/distribution/_cmrf.py,sha256=
|
|
19
|
+
cuqi/distribution/_cmrf.py,sha256=tCbEulM_O7FB3C_W-3IqZp9zGHkTofCdFF0ybHc9UZI,3745
|
|
20
20
|
cuqi/distribution/_custom.py,sha256=1ZFT3yjXsRKQJwNX3WwNDf2a9x13C9nIgxmq2wEOv4M,10657
|
|
21
21
|
cuqi/distribution/_distribution.py,sha256=Qh8Yq-rtKh9xgog-2bo7d4-o0vaW_aAt5LaGbXlgX0U,17951
|
|
22
22
|
cuqi/distribution/_gamma.py,sha256=GGsbIeHQhzUb1eTNeARcLXjJqcZ5iZWvaDaNsfJv9N0,1303
|
|
23
23
|
cuqi/distribution/_gaussian.py,sha256=Ymllxg7ZQE24ss0oVgtPII4Hx4-xy3x1tAb01_-4i_U,33026
|
|
24
|
-
cuqi/distribution/_gmrf.py,sha256=
|
|
24
|
+
cuqi/distribution/_gmrf.py,sha256=OwId8qQWEtmC2fxVhL4iBHZnc8ZCrZzfV6yGXDE3k30,9522
|
|
25
25
|
cuqi/distribution/_inverse_gamma.py,sha256=XRcNGW_jzORL08V7VvtsuMUoQioBAGbN12qe8hCXJvg,3309
|
|
26
26
|
cuqi/distribution/_joint_distribution.py,sha256=jRsV1Dt-pW6sG_xNqF0TugeVKDJY4Kh5aBLsIWfv394,15043
|
|
27
27
|
cuqi/distribution/_laplace.py,sha256=5exLvlzJm2AgfvZ3KUSkjfwlGwwbsktBxP8z0iLMik8,1401
|
|
28
|
-
cuqi/distribution/_lmrf.py,sha256=
|
|
28
|
+
cuqi/distribution/_lmrf.py,sha256=rdGoQ-fPe1oW6Z29P-l3woq0NX3_RxUQ2rzm1VzemNM,3290
|
|
29
29
|
cuqi/distribution/_lognormal.py,sha256=st1Uhf67qy2Seo65hA88JQ7lkEjQkW6KxznXahF_0SU,2844
|
|
30
30
|
cuqi/distribution/_normal.py,sha256=UeoTtGDT7YSf4ZNo2amlVF9K-YQpYbf8q76jcRJTVFw,1914
|
|
31
31
|
cuqi/distribution/_posterior.py,sha256=zAfL0GECxekZ2lBt1W6_LN0U_xskMwK4VNce5xAF7ig,5018
|
|
@@ -63,8 +63,8 @@ cuqi/testproblem/_testproblem.py,sha256=x769LwwRdJdzIiZkcQUGb_5-vynNTNALXWKato7s
|
|
|
63
63
|
cuqi/utilities/__init__.py,sha256=EfxHLdsyDNugbmbzs43nV_AeKcycM9sVBjG9WZydagA,351
|
|
64
64
|
cuqi/utilities/_get_python_variable_name.py,sha256=QwlBVj2koJRA8s8pWd554p7-ElcI7HUwY32HknaR92E,1827
|
|
65
65
|
cuqi/utilities/_utilities.py,sha256=UaC-rWhevEzi6862uZdHNQoBV8fAgsLm4Fobb6ik81I,8025
|
|
66
|
-
CUQIpy-0.8.0.post0.
|
|
67
|
-
CUQIpy-0.8.0.post0.
|
|
68
|
-
CUQIpy-0.8.0.post0.
|
|
69
|
-
CUQIpy-0.8.0.post0.
|
|
70
|
-
CUQIpy-0.8.0.post0.
|
|
66
|
+
CUQIpy-0.8.0.post0.dev13.dist-info/LICENSE,sha256=kJWRPrtRoQoZGXyyvu50Uc91X6_0XRaVfT0YZssicys,10799
|
|
67
|
+
CUQIpy-0.8.0.post0.dev13.dist-info/METADATA,sha256=3pWRkPFBPnXKK3yDk_5rQvVC-tllSZ9GtJwd0YD3Is0,18386
|
|
68
|
+
CUQIpy-0.8.0.post0.dev13.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
69
|
+
CUQIpy-0.8.0.post0.dev13.dist-info/top_level.txt,sha256=AgmgMc6TKfPPqbjV0kvAoCBN334i_Lwwojc7HE3ZwD0,5
|
|
70
|
+
CUQIpy-0.8.0.post0.dev13.dist-info/RECORD,,
|
cuqi/_version.py
CHANGED
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2023-12-
|
|
11
|
+
"date": "2023-12-19T22:07:12+0100",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "0.8.0.post0.
|
|
14
|
+
"full-revisionid": "cdddb1ac7225b019877b440f2c84a5cf34190af5",
|
|
15
|
+
"version": "0.8.0.post0.dev13"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
cuqi/distribution/_cmrf.py
CHANGED
cuqi/distribution/_gmrf.py
CHANGED
|
@@ -2,11 +2,12 @@ import numpy as np
|
|
|
2
2
|
from scipy.sparse import diags, eye
|
|
3
3
|
from scipy.sparse import linalg as splinalg
|
|
4
4
|
from scipy.linalg import dft
|
|
5
|
-
from cuqi.geometry import
|
|
5
|
+
from cuqi.geometry import _get_identity_geometries
|
|
6
6
|
from cuqi.utilities import sparse_cholesky
|
|
7
7
|
from cuqi import config
|
|
8
8
|
from cuqi.operator import PrecisionFiniteDifference
|
|
9
9
|
from cuqi.distribution import Distribution
|
|
10
|
+
from cuqi.utilities import force_ndarray
|
|
10
11
|
|
|
11
12
|
class GMRF(Distribution):
|
|
12
13
|
""" Gaussian Markov random field (GMRF).
|
|
@@ -19,9 +20,6 @@ class GMRF(Distribution):
|
|
|
19
20
|
prec : float
|
|
20
21
|
Precision of the GMRF.
|
|
21
22
|
|
|
22
|
-
physical_dim : int
|
|
23
|
-
The physical dimension of what the distribution represents (can take the values 1 or 2).
|
|
24
|
-
|
|
25
23
|
bc_type : str
|
|
26
24
|
The type of boundary conditions to use. Can be 'zero', 'periodic' or 'neumann'.
|
|
27
25
|
|
|
@@ -94,54 +92,67 @@ class GMRF(Distribution):
|
|
|
94
92
|
For more details see: See Bardsley, J. (2018). Computational Uncertainty Quantification for Inverse Problems, Chapter 4.2.
|
|
95
93
|
|
|
96
94
|
"""
|
|
97
|
-
|
|
98
|
-
def __init__(self, mean, prec, physical_dim=1, bc_type='zero', order=1, is_symmetric=True, **kwargs):
|
|
99
|
-
super().__init__(is_symmetric=is_symmetric, **kwargs) #TODO: This calls Distribution __init__, should be replaced by calling Gaussian.__init__
|
|
100
95
|
|
|
101
|
-
|
|
96
|
+
def __init__(self, mean=None, prec=None, bc_type="zero", order=1, **kwargs):
|
|
97
|
+
# Init from abstract distribution class
|
|
98
|
+
super().__init__(**kwargs)
|
|
99
|
+
|
|
100
|
+
self.mean = mean
|
|
102
101
|
self.prec = prec
|
|
103
|
-
self.
|
|
104
|
-
|
|
102
|
+
self._bc_type = bc_type
|
|
103
|
+
|
|
104
|
+
# Ensure geometry has shape
|
|
105
|
+
if not self.geometry.fun_shape or self.geometry.par_dim == 1:
|
|
106
|
+
raise ValueError(f"Distribution {self.__class__.__name__} must be initialized with supported geometry (geometry of which the fun_shape is not None) and has parameter dimension greater than 1.")
|
|
107
|
+
|
|
108
|
+
# Default physical_dim to geometry's dimension if not provided
|
|
109
|
+
physical_dim = len(self.geometry.fun_shape)
|
|
110
|
+
|
|
111
|
+
# Ensure provided physical dimension is either 1 or 2
|
|
112
|
+
if physical_dim not in [1, 2]:
|
|
113
|
+
raise ValueError("Only physical dimension 1 or 2 supported.")
|
|
114
|
+
|
|
105
115
|
self._physical_dim = physical_dim
|
|
106
|
-
|
|
107
|
-
num_nodes = tuple(self._partition_size for _ in range(physical_dim))
|
|
108
|
-
if physical_dim == 2: #TODO. Remove once _DefaultGeometry is implemented for 2D.
|
|
109
|
-
if isinstance(self.geometry, _DefaultGeometry1D):
|
|
110
|
-
self.geometry = Image2D(num_nodes)
|
|
111
116
|
|
|
112
|
-
self.
|
|
113
|
-
|
|
117
|
+
if self._physical_dim == 2:
|
|
118
|
+
N = int(np.sqrt(self.dim))
|
|
119
|
+
num_nodes = (N, N)
|
|
120
|
+
else:
|
|
121
|
+
num_nodes = self.dim
|
|
122
|
+
|
|
123
|
+
self._prec_op = PrecisionFiniteDifference(num_nodes=num_nodes, bc_type=bc_type, order=order)
|
|
124
|
+
self._diff_op = self._prec_op._diff_op
|
|
114
125
|
|
|
115
126
|
# compute Cholesky and det
|
|
116
127
|
if (bc_type == 'zero'): # only for PSD matrices
|
|
117
128
|
self._rank = self.dim
|
|
118
129
|
self._chol = sparse_cholesky(self._prec_op.get_matrix()).T
|
|
119
130
|
self._logdet = 2*sum(np.log(self._chol.diagonal()))
|
|
120
|
-
# L_cholmod = cholesky(self.L, ordering_method='natural')
|
|
121
|
-
# self.chol = L_cholmod
|
|
122
|
-
# self.logdet = L_cholmod.logdet()
|
|
123
|
-
#
|
|
124
|
-
# np.log(np.linalg.det(self.L.todense()))
|
|
125
131
|
elif (bc_type == 'periodic') or (bc_type == 'neumann'):
|
|
126
|
-
# Print warning that periodic and Neumann boundary conditions are experimental
|
|
127
132
|
print("Warning (GMRF): Periodic and Neumann boundary conditions are experimental. Sampling using LinearRTO may not produce fully accurate results.")
|
|
128
|
-
|
|
129
133
|
eps = np.finfo(float).eps
|
|
130
134
|
self._rank = self.dim - 1 #np.linalg.matrix_rank(self.L.todense())
|
|
131
135
|
self._chol = sparse_cholesky(self._prec_op + np.sqrt(eps)*eye(self.dim, dtype=int)).T
|
|
132
|
-
if (self.dim > config.MAX_DIM_INV): # approximate to avoid '
|
|
136
|
+
if (self.dim > config.MAX_DIM_INV): # approximate to avoid 'excessive' time
|
|
133
137
|
self._logdet = 2*sum(np.log(self._chol.diagonal()))
|
|
134
138
|
else:
|
|
135
|
-
# eigval = eigvalsh(self.L.todense())
|
|
136
139
|
self._L_eigval = splinalg.eigsh(self._prec_op.get_matrix(), self._rank, which='LM', return_eigenvectors=False)
|
|
137
140
|
self._logdet = sum(np.log(self._L_eigval))
|
|
138
141
|
else:
|
|
139
142
|
raise ValueError('bc_type must be "zero", "periodic" or "neumann"')
|
|
140
143
|
|
|
144
|
+
@property
|
|
145
|
+
def mean(self):
|
|
146
|
+
return self._mean
|
|
147
|
+
|
|
148
|
+
@mean.setter
|
|
149
|
+
def mean(self, value):
|
|
150
|
+
self._mean = force_ndarray(value, flatten=True)
|
|
151
|
+
|
|
141
152
|
@property
|
|
142
153
|
def prec(self):
|
|
143
154
|
return self._prec
|
|
144
|
-
|
|
155
|
+
|
|
145
156
|
@prec.setter
|
|
146
157
|
def prec(self, value):
|
|
147
158
|
# We store the precision as a scalar to match existing code in this class,
|
|
@@ -153,33 +164,20 @@ class GMRF(Distribution):
|
|
|
153
164
|
raise ValueError('Precision must be a scalar or a 1D array with a single scalar element.')
|
|
154
165
|
self._prec = value
|
|
155
166
|
|
|
156
|
-
@property
|
|
157
|
-
def dim(self):
|
|
158
|
-
if self._physical_dim == 1:
|
|
159
|
-
return self._partition_size
|
|
160
|
-
elif self._physical_dim==2:
|
|
161
|
-
return self._partition_size**2
|
|
162
|
-
raise ValueError("attribute dom can be either 1 or 2")
|
|
163
|
-
|
|
164
167
|
def logpdf(self, x):
|
|
165
|
-
mean = self.mean
|
|
168
|
+
mean = self.mean
|
|
166
169
|
const = 0.5*(self._rank*(np.log(self.prec)-np.log(2*np.pi)) + self._logdet)
|
|
167
|
-
|
|
168
|
-
# = sps.multivariate_normal.logpdf(x.T, self.mean.flatten(), np.linalg.inv(self.prec*self.L.todense()))
|
|
169
|
-
return y
|
|
170
|
-
|
|
171
|
-
def pdf(self, x):
|
|
172
|
-
# = sps.multivariate_normal.pdf(x.T, self.mean.flatten(), np.linalg.inv(self.prec*self.L.todense()))
|
|
173
|
-
return np.exp(self.logpdf(x))
|
|
170
|
+
return const - 0.5*( self.prec*((x-mean).T @ (self._prec_op @ (x-mean))) )
|
|
174
171
|
|
|
175
172
|
def _gradient(self, x):
|
|
176
173
|
#Avoid complicated geometries that change the gradient.
|
|
177
174
|
if not type(self.geometry) in _get_identity_geometries():
|
|
178
175
|
raise NotImplementedError("Gradient not implemented for distribution {} with geometry {}".format(self,self.geometry))
|
|
179
176
|
|
|
180
|
-
if not callable(self.mean):
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
if not callable(self.mean): # for prior
|
|
178
|
+
return -(self.prec*self._prec_op) @ (x-self.mean)
|
|
179
|
+
else:
|
|
180
|
+
NotImplementedError("Gradient not implemented for mean {}".format(type(self.mean)))
|
|
183
181
|
|
|
184
182
|
def _sample(self, N=1, rng=None):
|
|
185
183
|
if (self._bc_type == 'zero'):
|
|
@@ -190,10 +188,9 @@ class GMRF(Distribution):
|
|
|
190
188
|
xi = np.random.randn(self.dim, N) # standard Gaussian
|
|
191
189
|
|
|
192
190
|
if N == 1:
|
|
193
|
-
s = self.mean.flatten() + (1/np.sqrt(self.prec))*splinalg.spsolve(self._chol.T, xi)
|
|
194
|
-
else:
|
|
195
191
|
s = self.mean + (1/np.sqrt(self.prec))*splinalg.spsolve(self._chol.T, xi)
|
|
196
|
-
|
|
192
|
+
else:
|
|
193
|
+
s = self.mean[:, np.newaxis] + (1/np.sqrt(self.prec))*splinalg.spsolve(self._chol.T, xi)
|
|
197
194
|
|
|
198
195
|
elif (self._bc_type == 'periodic'):
|
|
199
196
|
|
|
@@ -206,12 +203,9 @@ class GMRF(Distribution):
|
|
|
206
203
|
xi = np.random.randn(self.dim, N) + 1j*np.random.randn(self.dim, N)
|
|
207
204
|
|
|
208
205
|
F = dft(self.dim, scale='sqrtn') # unitary DFT matrix
|
|
209
|
-
# eigv = eigvalsh(self.L.todense()) # splinalg.eigsh(self.L, self.rank, return_eigenvectors=False)
|
|
210
206
|
eigv = np.hstack([self._L_eigval, self._L_eigval[-1]]) # repeat last eigval to complete dim
|
|
211
207
|
L_sqrt = diags(np.sqrt(eigv))
|
|
212
|
-
s = self.mean + (1/np.sqrt(self.prec))*np.real(F.conj() @ splinalg.spsolve(L_sqrt, xi))
|
|
213
|
-
# L_sqrt = pinvh(np.diag(np.sqrt(eigv)))
|
|
214
|
-
# s = self.mean + (1/np.sqrt(self.prec))*np.real(F.conj() @ (L_sqrt @ xi))
|
|
208
|
+
s = self.mean[:, np.newaxis] + (1/np.sqrt(self.prec))*np.real(F.conj() @ splinalg.spsolve(L_sqrt, xi))
|
|
215
209
|
|
|
216
210
|
elif (self._bc_type == 'neumann'):
|
|
217
211
|
|
|
@@ -220,7 +214,7 @@ class GMRF(Distribution):
|
|
|
220
214
|
else:
|
|
221
215
|
xi = np.random.randn(self._diff_op.shape[0], N) # standard Gaussian
|
|
222
216
|
|
|
223
|
-
s = self.mean + (1/np.sqrt(self.prec))* \
|
|
217
|
+
s = self.mean[:, np.newaxis] + (1/np.sqrt(self.prec))* \
|
|
224
218
|
splinalg.spsolve(self._chol.T, (splinalg.spsolve(self._chol, (self._diff_op.T @ xi))))
|
|
225
219
|
else:
|
|
226
220
|
raise TypeError('Unexpected BC type (choose from zero, periodic, neumann or none)')
|
|
@@ -233,5 +227,4 @@ class GMRF(Distribution):
|
|
|
233
227
|
|
|
234
228
|
@property
|
|
235
229
|
def sqrtprecTimesMean(self):
|
|
236
|
-
return (self.sqrtprec@self.mean)
|
|
237
|
-
|
|
230
|
+
return (self.sqrtprec@self.mean)
|
cuqi/distribution/_lmrf.py
CHANGED
|
@@ -40,7 +40,7 @@ class LMRF(Distribution):
|
|
|
40
40
|
prior = cuqi.distribution.LMRF(location=0, scale=0.1, geometry=128)
|
|
41
41
|
|
|
42
42
|
"""
|
|
43
|
-
def __init__(self, location, scale, bc_type="zero", **kwargs):
|
|
43
|
+
def __init__(self, location=None, scale=None, bc_type="zero", **kwargs):
|
|
44
44
|
# Init from abstract distribution class
|
|
45
45
|
super().__init__(**kwargs)
|
|
46
46
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|