CUQIpy 1.1.1.post0.dev36__py3-none-any.whl → 1.4.1.post0.dev124__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.
- cuqi/__init__.py +2 -0
- cuqi/_version.py +3 -3
- cuqi/algebra/__init__.py +2 -0
- cuqi/algebra/_abstract_syntax_tree.py +358 -0
- cuqi/algebra/_ordered_set.py +82 -0
- cuqi/algebra/_random_variable.py +457 -0
- cuqi/array/_array.py +4 -13
- cuqi/config.py +7 -0
- cuqi/density/_density.py +9 -1
- cuqi/distribution/__init__.py +3 -2
- cuqi/distribution/_beta.py +7 -11
- cuqi/distribution/_cauchy.py +2 -2
- cuqi/distribution/_custom.py +0 -6
- cuqi/distribution/_distribution.py +31 -45
- cuqi/distribution/_gamma.py +7 -3
- cuqi/distribution/_gaussian.py +2 -12
- cuqi/distribution/_inverse_gamma.py +4 -10
- cuqi/distribution/_joint_distribution.py +112 -15
- cuqi/distribution/_lognormal.py +0 -7
- cuqi/distribution/{_modifiedhalfnormal.py → _modified_half_normal.py} +23 -23
- cuqi/distribution/_normal.py +34 -7
- cuqi/distribution/_posterior.py +9 -0
- cuqi/distribution/_truncated_normal.py +129 -0
- cuqi/distribution/_uniform.py +47 -1
- cuqi/experimental/__init__.py +2 -2
- cuqi/experimental/_recommender.py +216 -0
- cuqi/geometry/__init__.py +2 -0
- cuqi/geometry/_geometry.py +15 -1
- cuqi/geometry/_product_geometry.py +181 -0
- cuqi/implicitprior/__init__.py +5 -3
- cuqi/implicitprior/_regularized_gaussian.py +483 -0
- cuqi/implicitprior/{_regularizedGMRF.py → _regularized_gmrf.py} +4 -2
- cuqi/implicitprior/{_regularizedUnboundedUniform.py → _regularized_unbounded_uniform.py} +3 -2
- cuqi/implicitprior/_restorator.py +269 -0
- cuqi/legacy/__init__.py +2 -0
- cuqi/{experimental/mcmc → legacy/sampler}/__init__.py +7 -11
- cuqi/legacy/sampler/_conjugate.py +55 -0
- cuqi/legacy/sampler/_conjugate_approx.py +52 -0
- cuqi/legacy/sampler/_cwmh.py +196 -0
- cuqi/legacy/sampler/_gibbs.py +231 -0
- cuqi/legacy/sampler/_hmc.py +335 -0
- cuqi/{experimental/mcmc → legacy/sampler}/_langevin_algorithm.py +82 -111
- cuqi/legacy/sampler/_laplace_approximation.py +184 -0
- cuqi/legacy/sampler/_mh.py +190 -0
- cuqi/legacy/sampler/_pcn.py +244 -0
- cuqi/{experimental/mcmc → legacy/sampler}/_rto.py +132 -90
- cuqi/legacy/sampler/_sampler.py +182 -0
- cuqi/likelihood/_likelihood.py +9 -1
- cuqi/model/__init__.py +1 -1
- cuqi/model/_model.py +1361 -359
- cuqi/pde/__init__.py +4 -0
- cuqi/pde/_observation_map.py +36 -0
- cuqi/pde/_pde.py +134 -33
- cuqi/problem/_problem.py +93 -87
- cuqi/sampler/__init__.py +120 -8
- cuqi/sampler/_conjugate.py +376 -35
- cuqi/sampler/_conjugate_approx.py +40 -16
- cuqi/sampler/_cwmh.py +132 -138
- cuqi/{experimental/mcmc → sampler}/_direct.py +1 -1
- cuqi/sampler/_gibbs.py +288 -130
- cuqi/sampler/_hmc.py +328 -201
- cuqi/sampler/_langevin_algorithm.py +284 -100
- cuqi/sampler/_laplace_approximation.py +87 -117
- cuqi/sampler/_mh.py +47 -157
- cuqi/sampler/_pcn.py +65 -213
- cuqi/sampler/_rto.py +211 -142
- cuqi/sampler/_sampler.py +553 -136
- cuqi/samples/__init__.py +1 -1
- cuqi/samples/_samples.py +24 -18
- cuqi/solver/__init__.py +6 -4
- cuqi/solver/_solver.py +230 -26
- cuqi/testproblem/_testproblem.py +2 -3
- cuqi/utilities/__init__.py +6 -1
- cuqi/utilities/_get_python_variable_name.py +2 -2
- cuqi/utilities/_utilities.py +182 -2
- {CUQIpy-1.1.1.post0.dev36.dist-info → cuqipy-1.4.1.post0.dev124.dist-info}/METADATA +10 -6
- cuqipy-1.4.1.post0.dev124.dist-info/RECORD +101 -0
- {CUQIpy-1.1.1.post0.dev36.dist-info → cuqipy-1.4.1.post0.dev124.dist-info}/WHEEL +1 -1
- CUQIpy-1.1.1.post0.dev36.dist-info/RECORD +0 -92
- cuqi/experimental/mcmc/_conjugate.py +0 -197
- cuqi/experimental/mcmc/_conjugate_approx.py +0 -81
- cuqi/experimental/mcmc/_cwmh.py +0 -191
- cuqi/experimental/mcmc/_gibbs.py +0 -268
- cuqi/experimental/mcmc/_hmc.py +0 -470
- cuqi/experimental/mcmc/_laplace_approximation.py +0 -156
- cuqi/experimental/mcmc/_mh.py +0 -78
- cuqi/experimental/mcmc/_pcn.py +0 -89
- cuqi/experimental/mcmc/_sampler.py +0 -561
- cuqi/experimental/mcmc/_utilities.py +0 -17
- cuqi/implicitprior/_regularizedGaussian.py +0 -323
- {CUQIpy-1.1.1.post0.dev36.dist-info → cuqipy-1.4.1.post0.dev124.dist-info/licenses}/LICENSE +0 -0
- {CUQIpy-1.1.1.post0.dev36.dist-info → cuqipy-1.4.1.post0.dev124.dist-info}/top_level.txt +0 -0
cuqi/experimental/mcmc/_mh.py
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import cuqi
|
|
3
|
-
from cuqi.experimental.mcmc import ProposalBasedSampler
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class MH(ProposalBasedSampler):
|
|
7
|
-
""" Metropolis-Hastings (MH) sampler.
|
|
8
|
-
|
|
9
|
-
Parameters
|
|
10
|
-
----------
|
|
11
|
-
target : cuqi.density.Density
|
|
12
|
-
Target density or distribution.
|
|
13
|
-
|
|
14
|
-
proposal : cuqi.distribution.Distribution or callable
|
|
15
|
-
Proposal distribution. If None, a random walk MH is used (i.e., Gaussian proposal with identity covariance).
|
|
16
|
-
|
|
17
|
-
scale : float
|
|
18
|
-
Scaling parameter for the proposal distribution.
|
|
19
|
-
|
|
20
|
-
kwargs : dict
|
|
21
|
-
Additional keyword arguments to be passed to the base class :class:`ProposalBasedSampler`.
|
|
22
|
-
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
_STATE_KEYS = ProposalBasedSampler._STATE_KEYS.union({'scale', '_scale_temp'})
|
|
26
|
-
|
|
27
|
-
def __init__(self, target=None, proposal=None, scale=1, **kwargs):
|
|
28
|
-
super().__init__(target, proposal=proposal, scale=scale, **kwargs)
|
|
29
|
-
|
|
30
|
-
def _initialize(self):
|
|
31
|
-
# Due to a bug? in old MH, we must keep track of this extra variable to match behavior.
|
|
32
|
-
self._scale_temp = self.scale
|
|
33
|
-
|
|
34
|
-
def validate_target(self):
|
|
35
|
-
# Fail only when there is no log density, which is currently assumed to be the case in case NaN is returned.
|
|
36
|
-
if np.isnan(self.target.logd(self._get_default_initial_point(self.dim))):
|
|
37
|
-
raise ValueError("Target does not have valid logd")
|
|
38
|
-
|
|
39
|
-
def validate_proposal(self):
|
|
40
|
-
if not isinstance(self.proposal, cuqi.distribution.Distribution):
|
|
41
|
-
raise ValueError("Proposal must be a cuqi.distribution.Distribution object")
|
|
42
|
-
if not self.proposal.is_symmetric:
|
|
43
|
-
raise ValueError("Proposal must be symmetric")
|
|
44
|
-
|
|
45
|
-
def step(self):
|
|
46
|
-
# propose state
|
|
47
|
-
xi = self.proposal.sample(1) # sample from the proposal
|
|
48
|
-
x_star = self.current_point + self.scale*xi.flatten() # MH proposal
|
|
49
|
-
|
|
50
|
-
# evaluate target
|
|
51
|
-
target_eval_star = self.target.logd(x_star)
|
|
52
|
-
|
|
53
|
-
# ratio and acceptance probability
|
|
54
|
-
ratio = target_eval_star - self.current_target_logd # proposal is symmetric
|
|
55
|
-
alpha = min(0, ratio)
|
|
56
|
-
|
|
57
|
-
# accept/reject
|
|
58
|
-
u_theta = np.log(np.random.rand())
|
|
59
|
-
acc = 0
|
|
60
|
-
if (u_theta <= alpha):
|
|
61
|
-
self.current_point = x_star
|
|
62
|
-
self.current_target_logd = target_eval_star
|
|
63
|
-
acc = 1
|
|
64
|
-
|
|
65
|
-
return acc
|
|
66
|
-
|
|
67
|
-
def tune(self, skip_len, update_count):
|
|
68
|
-
hat_acc = np.mean(self._acc[-skip_len:])
|
|
69
|
-
|
|
70
|
-
# d. compute new scaling parameter
|
|
71
|
-
zeta = 1/np.sqrt(update_count+1) # ensures that the variation of lambda(i) vanishes
|
|
72
|
-
|
|
73
|
-
# We use self._scale_temp here instead of self.scale in update. This might be a bug,
|
|
74
|
-
# but is equivalent to old MH
|
|
75
|
-
self._scale_temp = np.exp(np.log(self._scale_temp) + zeta*(hat_acc-0.234))
|
|
76
|
-
|
|
77
|
-
# update parameters
|
|
78
|
-
self.scale = min(self._scale_temp, 1)
|
cuqi/experimental/mcmc/_pcn.py
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import cuqi
|
|
3
|
-
from cuqi.experimental.mcmc import Sampler
|
|
4
|
-
from cuqi.array import CUQIarray
|
|
5
|
-
|
|
6
|
-
class PCN(Sampler): # Refactor to Proposal-based sampler?
|
|
7
|
-
|
|
8
|
-
_STATE_KEYS = Sampler._STATE_KEYS.union({'scale', 'current_likelihood_logd', 'lambd'})
|
|
9
|
-
|
|
10
|
-
def __init__(self, target=None, scale=1.0, **kwargs):
|
|
11
|
-
|
|
12
|
-
super().__init__(target, **kwargs)
|
|
13
|
-
self.initial_scale = scale
|
|
14
|
-
|
|
15
|
-
def _initialize(self):
|
|
16
|
-
self.scale = self.initial_scale
|
|
17
|
-
self.current_likelihood_logd = self._loglikelihood(self.current_point)
|
|
18
|
-
|
|
19
|
-
# parameters used in the Robbins-Monro recursion for tuning the scale parameter
|
|
20
|
-
# see details and reference in the tune method
|
|
21
|
-
self.lambd = self.scale
|
|
22
|
-
self.star_acc = 0.44 #TODO: 0.234 # target acceptance rate
|
|
23
|
-
|
|
24
|
-
def validate_target(self):
|
|
25
|
-
if not isinstance(self.target, cuqi.distribution.Posterior):
|
|
26
|
-
raise ValueError(f"To initialize an object of type {self.__class__}, 'target' need to be of type 'cuqi.distribution.Posterior'.")
|
|
27
|
-
if not isinstance(self.prior, (cuqi.distribution.Gaussian, cuqi.distribution.Normal)):
|
|
28
|
-
raise ValueError("The prior distribution of the target need to be Gaussian")
|
|
29
|
-
|
|
30
|
-
def step(self):
|
|
31
|
-
# propose state
|
|
32
|
-
xi = self.prior.sample(1).flatten() # sample from the prior
|
|
33
|
-
x_star = np.sqrt(1-self.scale**2)*self.current_point + self.scale*xi # PCN proposal
|
|
34
|
-
|
|
35
|
-
# evaluate target
|
|
36
|
-
loglike_eval_star = self._loglikelihood(x_star)
|
|
37
|
-
|
|
38
|
-
# ratio and acceptance probability
|
|
39
|
-
ratio = loglike_eval_star - self.current_likelihood_logd # proposal is symmetric
|
|
40
|
-
alpha = min(0, ratio)
|
|
41
|
-
|
|
42
|
-
# accept/reject
|
|
43
|
-
acc = 0
|
|
44
|
-
u_theta = np.log(np.random.rand())
|
|
45
|
-
if (u_theta <= alpha):
|
|
46
|
-
self.current_point = x_star
|
|
47
|
-
self.current_likelihood_logd = loglike_eval_star
|
|
48
|
-
acc = 1
|
|
49
|
-
|
|
50
|
-
return acc
|
|
51
|
-
|
|
52
|
-
@property
|
|
53
|
-
def prior(self):
|
|
54
|
-
return self.target.prior
|
|
55
|
-
|
|
56
|
-
@property
|
|
57
|
-
def likelihood(self):
|
|
58
|
-
return self.target.likelihood
|
|
59
|
-
|
|
60
|
-
def _loglikelihood(self, x):
|
|
61
|
-
return self.likelihood.logd(x)
|
|
62
|
-
|
|
63
|
-
@property
|
|
64
|
-
def dim(self): # TODO. Check if we need this. Implemented in base class
|
|
65
|
-
if hasattr(self,'target') and hasattr(self.target,'dim'):
|
|
66
|
-
self._dim = self.target.dim
|
|
67
|
-
elif hasattr(self,'target') and isinstance(self.target,tuple) and len(self.target)==2:
|
|
68
|
-
self._dim = self.target[0].dim
|
|
69
|
-
return self._dim
|
|
70
|
-
|
|
71
|
-
def tune(self, skip_len, update_count):
|
|
72
|
-
"""
|
|
73
|
-
Tune the scale parameter of the PCN sampler.
|
|
74
|
-
The tuning is based on algorithm 4 in Andrieu, Christophe, and Johannes Thoms.
|
|
75
|
-
"A tutorial on adaptive MCMC." Statistics and computing 18 (2008): 343-373.
|
|
76
|
-
Note: the tuning algorithm here is the same as the one used in MH sampler.
|
|
77
|
-
"""
|
|
78
|
-
|
|
79
|
-
# average acceptance rate in the past skip_len iterations
|
|
80
|
-
hat_acc = np.mean(self._acc[-skip_len:])
|
|
81
|
-
|
|
82
|
-
# new scaling parameter zeta to be used in the Robbins-Monro recursion
|
|
83
|
-
zeta = 1/np.sqrt(update_count+1)
|
|
84
|
-
|
|
85
|
-
# Robbins-Monro recursion to ensure that the variation of lambd vanishes
|
|
86
|
-
self.lambd = np.exp(np.log(self.lambd) + zeta*(hat_acc-self.star_acc))
|
|
87
|
-
|
|
88
|
-
# update scale parameter
|
|
89
|
-
self.scale = min(self.lambd, 1)
|