CUQIpy 1.1.0.post0.dev39__py3-none-any.whl → 1.1.1.post0.dev5__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.1.0.post0.dev39
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
  cuqi/__init__.py,sha256=LsGilhl-hBLEn6Glt8S_l0OJzAA1sKit_rui8h-D-p0,488
2
2
  cuqi/_messages.py,sha256=fzEBrZT2kbmfecBBPm7spVu7yHdxGARQB4QzXhJbCJ0,415
3
- cuqi/_version.py,sha256=SFVwuROZ7PjMxlopbxtd_O7tlfLQi9nwgd9r4SLXD7o,509
3
+ cuqi/_version.py,sha256=GBlEQB0vnqLdJQ4FNiN2Ih7mYmB2x4_rO95Eva1C9oI,508
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
@@ -24,7 +24,7 @@ cuqi/distribution/_gamma.py,sha256=9vljt5iaBDCHRhrVCMLc2RWDuBchZRQcv9buJMDYPlM,3
24
24
  cuqi/distribution/_gaussian.py,sha256=DmmgVxKp4iEiEYWDdDcRoh35y14Oepn-zDHex0WVaYo,33316
25
25
  cuqi/distribution/_gmrf.py,sha256=OwId8qQWEtmC2fxVhL4iBHZnc8ZCrZzfV6yGXDE3k30,9522
26
26
  cuqi/distribution/_inverse_gamma.py,sha256=XRcNGW_jzORL08V7VvtsuMUoQioBAGbN12qe8hCXJvg,3309
27
- cuqi/distribution/_joint_distribution.py,sha256=jRsV1Dt-pW6sG_xNqF0TugeVKDJY4Kh5aBLsIWfv394,15043
27
+ cuqi/distribution/_joint_distribution.py,sha256=7TxDaZ7y362LfxEpD4I5Z0icdtsBmOBJGnpIkz_bYXA,15900
28
28
  cuqi/distribution/_laplace.py,sha256=5exLvlzJm2AgfvZ3KUSkjfwlGwwbsktBxP8z0iLMik8,1401
29
29
  cuqi/distribution/_lmrf.py,sha256=rdGoQ-fPe1oW6Z29P-l3woq0NX3_RxUQ2rzm1VzemNM,3290
30
30
  cuqi/distribution/_lognormal.py,sha256=st1Uhf67qy2Seo65hA88JQ7lkEjQkW6KxznXahF_0SU,2844
@@ -57,7 +57,7 @@ cuqi/implicitprior/_regularizedUnboundedUniform.py,sha256=H2fTOSqYTlDiLxQ7Ya6wnp
57
57
  cuqi/likelihood/__init__.py,sha256=QXif382iwZ5bT3ZUqmMs_n70JVbbjxbqMrlQYbMn4Zo,1776
58
58
  cuqi/likelihood/_likelihood.py,sha256=z3AXAbIrv_DjOYh4jy3iDHemuIFUUJu6wdvJ5e2dgW0,6913
59
59
  cuqi/model/__init__.py,sha256=IcN4aZCnyp9o-8TNIoZ8vew99QQgi0EmZvnsIuR6qYI,49
60
- cuqi/model/_model.py,sha256=bmS5X-FxhY1n5I0ahBlIPbUFynw-2Vw2s9N-exMX-BU,26627
60
+ cuqi/model/_model.py,sha256=2MtQaahSGOVm45tvxh_xbke9vo_Aq0tpyNvLg9TK9dA,27791
61
61
  cuqi/operator/__init__.py,sha256=0pc9p-KPyl7KtPV0noB0ddI0CP2iYEHw5rbw49D8Njk,136
62
62
  cuqi/operator/_operator.py,sha256=yNwPTh7jR07AiKMbMQQ5_54EgirlKFsbq9JN1EODaQI,8856
63
63
  cuqi/pde/__init__.py,sha256=NyS_ZYruCvy-Yg24qKlwm3ZIX058kLNQX9bqs-xg4ZM,99
@@ -85,8 +85,8 @@ cuqi/testproblem/_testproblem.py,sha256=x769LwwRdJdzIiZkcQUGb_5-vynNTNALXWKato7s
85
85
  cuqi/utilities/__init__.py,sha256=H7xpJe2UinjZftKvE2JuXtTi4DqtkR6uIezStAXwfGg,428
86
86
  cuqi/utilities/_get_python_variable_name.py,sha256=QwlBVj2koJRA8s8pWd554p7-ElcI7HUwY32HknaR92E,1827
87
87
  cuqi/utilities/_utilities.py,sha256=Jc4knn80vLoA7kgw9FzXwKVFGaNBOXiA9kgvltZU3Ao,11777
88
- CUQIpy-1.1.0.post0.dev39.dist-info/LICENSE,sha256=kJWRPrtRoQoZGXyyvu50Uc91X6_0XRaVfT0YZssicys,10799
89
- CUQIpy-1.1.0.post0.dev39.dist-info/METADATA,sha256=tPkKE5LGWKpgvgM1zkAfKPq4tV0kLGVpbdZSz5ZCn3E,18390
90
- CUQIpy-1.1.0.post0.dev39.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
91
- CUQIpy-1.1.0.post0.dev39.dist-info/top_level.txt,sha256=AgmgMc6TKfPPqbjV0kvAoCBN334i_Lwwojc7HE3ZwD0,5
92
- CUQIpy-1.1.0.post0.dev39.dist-info/RECORD,,
88
+ CUQIpy-1.1.1.post0.dev5.dist-info/LICENSE,sha256=kJWRPrtRoQoZGXyyvu50Uc91X6_0XRaVfT0YZssicys,10799
89
+ CUQIpy-1.1.1.post0.dev5.dist-info/METADATA,sha256=PV1PVHglGQb4105G0vt1Px1jAmsP4PBQ91IvzVMiCFk,18389
90
+ CUQIpy-1.1.1.post0.dev5.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
91
+ CUQIpy-1.1.1.post0.dev5.dist-info/top_level.txt,sha256=AgmgMc6TKfPPqbjV0kvAoCBN334i_Lwwojc7HE3ZwD0,5
92
+ CUQIpy-1.1.1.post0.dev5.dist-info/RECORD,,
cuqi/_version.py CHANGED
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-08-29T10:46:43+0300",
11
+ "date": "2024-08-31T21:02:04+0200",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "9d8920342c73b1bd8e7a47a216eb34056ea2f5d6",
15
- "version": "1.1.0.post0.dev39"
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)
cuqi/model/_model.py CHANGED
@@ -19,10 +19,10 @@ class Model(object):
19
19
  Forward operator.
20
20
 
21
21
  range_geometry : integer or cuqi.geometry.Geometry
22
- If integer is given a _DefaultGeometry is created with dimension of the integer.
22
+ If integer is given, a cuqi.geometry._DefaultGeometry is created with dimension of the integer.
23
23
 
24
24
  domain_geometry : integer or cuqi.geometry.Geometry
25
- If integer is given a _DefaultGeometry is created with dimension of the integer.
25
+ If integer is given, a cuqi.geometry._DefaultGeometry is created with dimension of the integer.
26
26
 
27
27
  gradient : callable function, optional
28
28
  The direction-Jacobian product of the forward operator Jacobian with
@@ -35,14 +35,20 @@ class Model(object):
35
35
  The Jacobian of the forward operator with respect to the forward operator input,
36
36
  evaluated at a point (`wrt`). The signature of the Jacobian function should be (`wrt`).
37
37
  The Jacobian function should return a 2D ndarray of shape (range_dim, domain_dim).
38
- The Jacobian function is used to specify the gradient function (vector-Jacobian product)
38
+ The Jacobian function is used to specify the gradient function by computing the vector-Jacobian
39
+ product (VJP), here we refer to the vector in the VJP as the `direction` since it is the direction at
40
+ which the gradient is computed.
39
41
  automatically and thus the gradient function should not be specified when the Jacobian
40
42
  function is specified.
41
43
 
44
+
45
+ :ivar range_geometry: The geometry representing the range.
46
+ :ivar domain_geometry: The geometry representing the domain.
47
+
42
48
  Example
43
49
  -------
44
50
 
45
- Consider a forward model :math:`F: \mathbb{R}^2 \rightarrow \mathbb{R}` defined by the following forward operator:
51
+ Consider a forward model :math:`F: \mathbb{R}^2 \\rightarrow \mathbb{R}` defined by the following forward operator:
46
52
 
47
53
  .. math::
48
54
 
@@ -141,11 +147,17 @@ class Model(object):
141
147
  self._non_default_args = cuqi.utilities.get_non_default_args(self._forward_func)
142
148
 
143
149
  @property
144
- def domain_dim(self):
150
+ def domain_dim(self):
151
+ """
152
+ The dimension of the domain
153
+ """
145
154
  return self.domain_geometry.par_dim
146
155
 
147
156
  @property
148
157
  def range_dim(self):
158
+ """
159
+ The dimension of the range
160
+ """
149
161
  return self.range_geometry.par_dim
150
162
 
151
163
  def _2fun(self, x, geometry, is_par):
@@ -466,28 +478,61 @@ class LinearModel(Model):
466
478
  forward : 2D ndarray or callable function.
467
479
  Forward operator.
468
480
 
469
- adjoint : 2d ndarray or callable function. (optional if matrix is passed as forward)
481
+ adjoint : 2D ndarray or callable function. (optional if matrix is passed as forward)
470
482
 
471
483
  range_geometry : integer or cuqi.geometry.Geometry (optional)
472
- If integer is given a _DefaultGeometry is created with dimension of the integer.
484
+ If integer is given, a cuqi.geometry._DefaultGeometry is created with dimension of the integer.
473
485
 
474
486
  domain_geometry : integer or cuqi.geometry.Geometry (optional)
475
- If integer is given a _DefaultGeometry is created with dimension of the integer.
487
+ If integer is given, a cuqi.geometry._DefaultGeometry is created with dimension of the integer.
476
488
 
477
- Attributes
478
- -----------
479
- range_geometry : cuqi.geometry.Geometry
480
- The geometry representing the range.
481
489
 
482
- domain_geometry : cuqi.geometry.Geometry
483
- The geometry representing the domain.
490
+ :ivar range_geometry: The geometry representing the range.
491
+ :ivar domain_geometry: The geometry representing the domain.
484
492
 
485
- Methods
486
- -----------
487
- :meth:`forward` the forward operator.
488
- :meth:`range_dim` the dimension of the range.
489
- :meth:`domain_dim` the dimension of the domain.
490
- :meth:`get_matrix` returns an ndarray with the matrix representing the forward operator.
493
+ Example
494
+ -------
495
+
496
+ Consider a linear model represented by a matrix, i.e., :math:`y=Ax` where
497
+ :math:`A` is a matrix.
498
+
499
+ We can define such a linear model by passing the matrix :math:`A`:
500
+
501
+ .. code-block:: python
502
+
503
+ import numpy as np
504
+ from cuqi.model import LinearModel
505
+
506
+ A = np.random.randn(2,3)
507
+
508
+ model = LinearModel(A)
509
+
510
+ The dimension of the range and domain geometries will be automatically
511
+ inferred from the matrix :math:`A`.
512
+
513
+ Meanwhile, such a linear model can also be defined by a forward function
514
+ and an adjoint function:
515
+
516
+ .. code-block:: python
517
+
518
+ import numpy as np
519
+ from cuqi.model import LinearModel
520
+
521
+ A = np.random.randn(2,3)
522
+
523
+ def forward(x):
524
+ return A@x
525
+
526
+ def adjoint(y):
527
+ return A.T@y
528
+
529
+ model = LinearModel(forward,
530
+ adjoint=adjoint,
531
+ range_geometry=2,
532
+ domain_geometry=3)
533
+
534
+ Note that you would need to specify the range and domain geometries in this
535
+ case as they cannot be inferred from the forward and adjoint functions.
491
536
  """
492
537
  # Linear forward model with forward and adjoint (transpose).
493
538
 
@@ -552,6 +597,9 @@ class LinearModel(Model):
552
597
 
553
598
 
554
599
  def get_matrix(self):
600
+ """
601
+ Returns an ndarray with the matrix representing the forward operator.
602
+ """
555
603
  if self._matrix is not None: #Matrix exists so return it
556
604
  return self._matrix
557
605
  else:
@@ -594,24 +642,14 @@ class PDEModel(Model):
594
642
  Forward operator assembling, solving and observing the pde.
595
643
 
596
644
  range_geometry : integer or cuqi.geometry.Geometry (optional)
597
- If integer is given a _DefaultGeometry is created with dimension of the integer.
645
+ If integer is given, a cuqi.geometry._DefaultGeometry is created with dimension of the integer.
598
646
 
599
647
  domain_geometry : integer or cuqi.geometry.Geometry (optional)
600
- If integer is given a _DefaultGeometry is created with dimension of the integer.
601
-
602
- Attributes
603
- -----------
604
- range_geometry : cuqi.geometry.Geometry
605
- The geometry representing the range.
648
+ If integer is given, a cuqi.geometry._DefaultGeometry is created with dimension of the integer.
606
649
 
607
- domain_geometry : cuqi.geometry.Geometry
608
- The geometry representing the domain.
609
650
 
610
- Methods
611
- -----------
612
- :meth:`forward` the forward operator.
613
- :meth:`range_dim` the dimension of the range.
614
- :meth:`domain_dim` the dimension of the domain.
651
+ :ivar range_geometry: The geometry representing the range.
652
+ :ivar domain_geometry: The geometry representing the domain.
615
653
  """
616
654
  def __init__(self, PDE: cuqi.pde.PDE, range_geometry, domain_geometry):
617
655