CUQIpy 1.3.0.post0.dev401__py3-none-any.whl → 1.4.0.post0.dev41__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.

Files changed (50) hide show
  1. cuqi/__init__.py +1 -0
  2. cuqi/_version.py +3 -3
  3. cuqi/density/_density.py +9 -1
  4. cuqi/distribution/_joint_distribution.py +96 -11
  5. cuqi/experimental/__init__.py +1 -2
  6. cuqi/experimental/_recommender.py +4 -4
  7. cuqi/legacy/__init__.py +2 -0
  8. cuqi/legacy/sampler/__init__.py +11 -0
  9. cuqi/legacy/sampler/_conjugate.py +55 -0
  10. cuqi/legacy/sampler/_conjugate_approx.py +52 -0
  11. cuqi/legacy/sampler/_cwmh.py +196 -0
  12. cuqi/legacy/sampler/_gibbs.py +231 -0
  13. cuqi/legacy/sampler/_hmc.py +335 -0
  14. cuqi/legacy/sampler/_langevin_algorithm.py +198 -0
  15. cuqi/legacy/sampler/_laplace_approximation.py +184 -0
  16. cuqi/legacy/sampler/_mh.py +190 -0
  17. cuqi/legacy/sampler/_pcn.py +244 -0
  18. cuqi/legacy/sampler/_rto.py +284 -0
  19. cuqi/legacy/sampler/_sampler.py +182 -0
  20. cuqi/problem/_problem.py +87 -80
  21. cuqi/sampler/__init__.py +120 -8
  22. cuqi/sampler/_conjugate.py +376 -35
  23. cuqi/sampler/_conjugate_approx.py +40 -16
  24. cuqi/sampler/_cwmh.py +132 -138
  25. cuqi/{experimental/mcmc → sampler}/_direct.py +1 -1
  26. cuqi/sampler/_gibbs.py +269 -130
  27. cuqi/sampler/_hmc.py +328 -201
  28. cuqi/sampler/_langevin_algorithm.py +282 -98
  29. cuqi/sampler/_laplace_approximation.py +87 -117
  30. cuqi/sampler/_mh.py +47 -157
  31. cuqi/sampler/_pcn.py +56 -211
  32. cuqi/sampler/_rto.py +206 -140
  33. cuqi/sampler/_sampler.py +540 -135
  34. {cuqipy-1.3.0.post0.dev401.dist-info → cuqipy-1.4.0.post0.dev41.dist-info}/METADATA +1 -1
  35. {cuqipy-1.3.0.post0.dev401.dist-info → cuqipy-1.4.0.post0.dev41.dist-info}/RECORD +38 -37
  36. cuqi/experimental/mcmc/__init__.py +0 -122
  37. cuqi/experimental/mcmc/_conjugate.py +0 -396
  38. cuqi/experimental/mcmc/_conjugate_approx.py +0 -76
  39. cuqi/experimental/mcmc/_cwmh.py +0 -190
  40. cuqi/experimental/mcmc/_gibbs.py +0 -366
  41. cuqi/experimental/mcmc/_hmc.py +0 -462
  42. cuqi/experimental/mcmc/_langevin_algorithm.py +0 -382
  43. cuqi/experimental/mcmc/_laplace_approximation.py +0 -154
  44. cuqi/experimental/mcmc/_mh.py +0 -80
  45. cuqi/experimental/mcmc/_pcn.py +0 -89
  46. cuqi/experimental/mcmc/_rto.py +0 -350
  47. cuqi/experimental/mcmc/_sampler.py +0 -582
  48. {cuqipy-1.3.0.post0.dev401.dist-info → cuqipy-1.4.0.post0.dev41.dist-info}/WHEEL +0 -0
  49. {cuqipy-1.3.0.post0.dev401.dist-info → cuqipy-1.4.0.post0.dev41.dist-info}/licenses/LICENSE +0 -0
  50. {cuqipy-1.3.0.post0.dev401.dist-info → cuqipy-1.4.0.post0.dev41.dist-info}/top_level.txt +0 -0
@@ -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)
@@ -1,350 +0,0 @@
1
- import scipy as sp
2
- from scipy.linalg.interpolative import estimate_spectral_norm
3
- from scipy.sparse.linalg import LinearOperator as scipyLinearOperator
4
- import numpy as np
5
- import cuqi
6
- from cuqi.solver import CGLS, FISTA, ADMM, ScipyLinearLSQ, ScipyMinimizer
7
- from cuqi.experimental.mcmc import Sampler
8
-
9
-
10
- class LinearRTO(Sampler):
11
- """
12
- Linear RTO (Randomize-Then-Optimize) sampler.
13
-
14
- Samples posterior related to the inverse problem with Gaussian likelihood and prior, and where the forward model is linear or more generally affine.
15
-
16
- Parameters
17
- ------------
18
- target : `cuqi.distribution.Posterior`, `cuqi.distribution.MultipleLikelihoodPosterior` or 5-dimensional tuple.
19
- If target is of type cuqi.distribution.Posterior or cuqi.distribution.MultipleLikelihoodPosterior, it represents the posterior distribution.
20
- If target is a 5-dimensional tuple, it assumes the following structure:
21
- (data, model, L_sqrtprec, P_mean, P_sqrtrec)
22
-
23
- Here:
24
- data: is a m-dimensional numpy array containing the measured data.
25
- model: is a m by n dimensional matrix, AffineModel or LinearModel representing the forward model.
26
- L_sqrtprec: is the squareroot of the precision matrix of the Gaussian likelihood.
27
- P_mean: is the prior mean.
28
- P_sqrtprec: is the squareroot of the precision matrix of the Gaussian mean.
29
-
30
- initial_point : `np.ndarray`
31
- Initial point for the sampler. *Optional*.
32
-
33
- maxit : int
34
- Maximum number of iterations of the inner CGLS solver. *Optional*.
35
-
36
- tol : float
37
- Tolerance of the inner CGLS solver. *Optional*.
38
-
39
- inner_initial_point : string or np.ndarray or cuqi.array.CUQIArray
40
- Initial point for the inner optimization problem. Can be "previous_sample" (default), "MAP", or a specific numpy or cuqi array. *Optional*.
41
-
42
- callback : callable, optional
43
- A function that will be called after each sampling step. It can be useful for monitoring the sampler during sampling.
44
- The function should take three arguments: the sampler object, the index of the current sampling step, the total number of requested samples. The last two arguments are integers. An example of the callback function signature is: `callback(sampler, sample_index, num_of_samples)`.
45
-
46
- """
47
- def __init__(self, target=None, initial_point=None, maxit=10, tol=1e-6, inner_initial_point="previous_sample", **kwargs):
48
-
49
- super().__init__(target=target, initial_point=initial_point, **kwargs)
50
-
51
- # Other parameters
52
- self.maxit = maxit
53
- self.tol = tol
54
- self.inner_initial_point = inner_initial_point
55
-
56
- def _initialize(self):
57
- self._precompute()
58
- self._compute_map()
59
-
60
- @property
61
- def inner_initial_point(self):
62
- if isinstance(self._inner_initial_point, str):
63
- if self._inner_initial_point == "previous_sample":
64
- return self.current_point
65
- elif self._inner_initial_point == "map":
66
- return self._map
67
- else:
68
- return self._inner_initial_point
69
-
70
- @inner_initial_point.setter
71
- def inner_initial_point(self, value):
72
- is_correct_string = (isinstance(value, str) and
73
- (value.lower() == "previous_sample" or
74
- value.lower() == "map"))
75
- if is_correct_string:
76
- self._inner_initial_point = value.lower()
77
- elif isinstance(value, (np.ndarray, cuqi.array.CUQIarray)):
78
- self._inner_initial_point = value
79
- else:
80
- raise ValueError("Invalid value for inner_initial_point. Choose either 'previous_sample', 'MAP', or provide a numpy array/cuqi array.")
81
-
82
- @property
83
- def prior(self):
84
- return self.target.prior
85
-
86
- @property
87
- def likelihood(self):
88
- return self.target.likelihood
89
-
90
- @property
91
- def likelihoods(self):
92
- if isinstance(self.target, cuqi.distribution.Posterior):
93
- return [self.target.likelihood]
94
- elif isinstance(self.target, cuqi.distribution.MultipleLikelihoodPosterior):
95
- return self.target.likelihoods
96
-
97
- @property
98
- def model(self):
99
- return self.target.model
100
-
101
- @property
102
- def models(self):
103
- if isinstance(self.target, cuqi.distribution.Posterior):
104
- return [self.target.model]
105
- elif isinstance(self.target, cuqi.distribution.MultipleLikelihoodPosterior):
106
- return self.target.models
107
-
108
- def _compute_map(self):
109
- sim = CGLS(self.M, self.b_tild, self.current_point, self.maxit, self.tol)
110
- self._map, _ = sim.solve()
111
-
112
- def _precompute(self):
113
- L1 = [likelihood.distribution.sqrtprec for likelihood in self.likelihoods]
114
- L2 = self.prior.sqrtprec
115
- L2mu = self.prior.sqrtprecTimesMean
116
-
117
- # pre-computations
118
- self.n = self.prior.dim
119
- self.b_tild = np.hstack([L@(likelihood.data - model._shift) for (L, likelihood, model) in zip(L1, self.likelihoods, self.models)]+ [L2mu]) # With shift from AffineModel
120
- callability = [callable(likelihood.model) for likelihood in self.likelihoods]
121
- notcallability = [not c for c in callability]
122
- if all(notcallability):
123
- self.M = sp.sparse.vstack([L@likelihood.model for (L, likelihood) in zip(L1, self.likelihoods)] + [L2])
124
- elif all(callability):
125
- # in this case, model is a function doing forward and backward operations
126
- def M(x, flag):
127
- if flag == 1:
128
- out1 = [L @ likelihood.model._forward_func_no_shift(x) for (L, likelihood) in zip(L1, self.likelihoods)] # Use forward function which excludes shift
129
- out2 = L2 @ x
130
- out = np.hstack(out1 + [out2])
131
- elif flag == 2:
132
- idx_start = 0
133
- idx_end = 0
134
- out1 = np.zeros(self.n)
135
- for likelihood in self.likelihoods:
136
- idx_end += len(likelihood.data)
137
- out1 += likelihood.model._adjoint_func_no_shift(likelihood.distribution.sqrtprec.T@x[idx_start:idx_end])
138
- idx_start = idx_end
139
- out2 = L2.T @ x[idx_end:]
140
- out = out1 + out2
141
- return out
142
- self.M = M
143
- else:
144
- raise TypeError("All likelihoods need to be callable or none need to be callable.")
145
-
146
- def step(self):
147
- y = self.b_tild + np.random.randn(len(self.b_tild))
148
- sim = CGLS(self.M, y, self.inner_initial_point, self.maxit, self.tol)
149
- self.current_point, _ = sim.solve()
150
- acc = 1
151
- return acc
152
-
153
- def tune(self, skip_len, update_count):
154
- pass
155
-
156
- def validate_target(self):
157
- # Check target type
158
- if not isinstance(self.target, (cuqi.distribution.Posterior, cuqi.distribution.MultipleLikelihoodPosterior)):
159
- raise ValueError(f"To initialize an object of type {self.__class__}, 'target' need to be of type 'cuqi.distribution.Posterior' or 'cuqi.distribution.MultipleLikelihoodPosterior'.")
160
-
161
- # Check Linear model and Gaussian likelihood(s)
162
- if isinstance(self.target, cuqi.distribution.Posterior):
163
- if not isinstance(self.model, cuqi.model.AffineModel):
164
- raise TypeError("Model needs to be linear or more generally affine")
165
-
166
- if not hasattr(self.likelihood.distribution, "sqrtprec"):
167
- raise TypeError("Distribution in Likelihood must contain a sqrtprec attribute")
168
-
169
- elif isinstance(self.target, cuqi.distribution.MultipleLikelihoodPosterior): # Elif used for further alternatives, e.g., stacked posterior
170
- for likelihood in self.likelihoods:
171
- if not isinstance(likelihood.model, cuqi.model.AffineModel):
172
- raise TypeError("Model needs to be linear or more generally affine")
173
-
174
- if not hasattr(likelihood.distribution, "sqrtprec"):
175
- raise TypeError("Distribution in Likelihood must contain a sqrtprec attribute")
176
-
177
- # Check Gaussian prior
178
- if not hasattr(self.prior, "sqrtprec"):
179
- raise TypeError("prior must contain a sqrtprec attribute")
180
-
181
- if not hasattr(self.prior, "sqrtprecTimesMean"):
182
- raise TypeError("Prior must contain a sqrtprecTimesMean attribute")
183
-
184
- def _get_default_initial_point(self, dim):
185
- """ Get the default initial point for the sampler. Defaults to an array of zeros. """
186
- return np.zeros(dim)
187
-
188
- class RegularizedLinearRTO(LinearRTO):
189
- """
190
- Regularized Linear RTO (Randomize-Then-Optimize) sampler.
191
-
192
- Samples posterior related to the inverse problem with Gaussian likelihood and implicit Gaussian prior, and where the forward model is Linear.
193
- The sampler works by repeatedly solving regularized linear least squares problems for perturbed data.
194
- The solver for these optimization problems is chosen based on how the regularized is provided in the implicit Gaussian prior.
195
- Currently we use the following solvers:
196
- FISTA: [1] Beck, Amir, and Marc Teboulle. "A fast iterative shrinkage-thresholding algorithm for linear inverse problems." SIAM journal on imaging sciences 2.1 (2009): 183-202.
197
- Used when prior.proximal is callable.
198
- ADMM: [2] Boyd et al. "Distributed optimization and statistical learning via the alternating direction method of multipliers."Foundations and Trends® in Machine learning, 2011.
199
- Used when prior.proximal is a list of penalty terms.
200
- ScipyLinearLSQ: Wrapper for Scipy's lsq_linear for the Trust Region Reflective algorithm. Optionally used when the constraint is either "nonnegativity" or "box".
201
- ScipyMinimizer: Wrapper for Scipy's minimize. Optionally used when the constraint is either "nonnegativity" or "box".
202
-
203
- Parameters
204
- ------------
205
- target : `cuqi.distribution.Posterior`
206
- See `cuqi.sampler.LinearRTO`
207
-
208
- initial_point : `np.ndarray`
209
- Initial point for the sampler. *Optional*.
210
-
211
- maxit : int
212
- Maximum number of iterations of the FISTA/ADMM/ScipyLinearLSQ/ScipyMinimizer solver. *Optional*.
213
-
214
- inner_max_it : int
215
- Maximum number of iterations of the CGLS solver used within the ADMM solver. *Optional*.
216
-
217
- stepsize : string or float
218
- If stepsize is a string and equals either "automatic", then the stepsize is automatically estimated based on the spectral norm.
219
- If stepsize is a float, then this stepsize is used.
220
-
221
- penalty_parameter : int
222
- Penalty parameter of the ADMM solver. *Optional*.
223
- See [2] or `cuqi.solver.ADMM`
224
-
225
- abstol : float
226
- Absolute tolerance of the FISTA/ScipyLinearLSQ/ScipyMinimizer solver. *Optional*.
227
-
228
- inner_abstol : float
229
- Tolerance parameter for ScipyLinearLSQ's inner solve of the unbounded least-squares problem. *Optional*.
230
-
231
- adaptive : bool
232
- If True, FISTA is used as solver, otherwise ISTA is used. *Optional*.
233
-
234
- solver : string
235
- Options are "FISTA" (default for a single constraint or regularization), "ADMM" (default and the only option for multiple constraints or regularizations), "ScipyLinearLSQ" and "ScipyMinimizer". Note "ScipyLinearLSQ" and "ScipyMinimizer" can only be used with `RegularizedGaussian` of a single `box` or `nonnegativity` constraint. *Optional*.
236
-
237
- inner_initial_point : string or np.ndarray or cuqi.array.CUQIArray
238
- Initial point for the inner optimization problem. Can be "previous_sample" (default), "MAP", or a specific numpy or cuqi array. *Optional*.
239
-
240
- callback : callable, optional
241
- A function that will be called after each sampling step. It can be useful for monitoring the sampler during sampling.
242
- The function should take three arguments: the sampler object, the index of the current sampling step, the total number of requested samples. The last two arguments are integers. An example of the callback function signature is: `callback(sampler, sample_index, num_of_samples)`.
243
-
244
- """
245
- def __init__(self, target=None, initial_point=None, maxit=100, inner_max_it=10, stepsize="automatic", penalty_parameter=10, abstol=1e-10, adaptive=True, solver=None, inner_abstol=None, inner_initial_point="previous_sample", **kwargs):
246
-
247
- super().__init__(target=target, initial_point=initial_point, **kwargs)
248
-
249
- # Other parameters
250
- self.stepsize = stepsize
251
- self.abstol = abstol
252
- self.inner_abstol = inner_abstol
253
- self.adaptive = adaptive
254
- self.maxit = maxit
255
- self.inner_max_it = inner_max_it
256
- self.penalty_parameter = penalty_parameter
257
- self.solver = solver
258
- self.inner_initial_point = inner_initial_point
259
-
260
- def _initialize(self):
261
- super()._initialize()
262
- if self.solver is None:
263
- self.solver = "FISTA" if callable(self.proximal) else "ADMM"
264
- if self.solver == "FISTA":
265
- self._stepsize = self._choose_stepsize()
266
- self._compute_map_regularized()
267
-
268
- @property
269
- def solver(self):
270
- return self._solver
271
-
272
- @solver.setter
273
- def solver(self, value):
274
- if value == "ScipyLinearLSQ" or value == "ScipyMinimizer":
275
- if (self.target.prior.preset["constraint"] == "nonnegativity" or self.target.prior.preset["constraint"] == "box"):
276
- self._solver = value
277
- else:
278
- raise ValueError("ScipyLinearLSQ and ScipyMinimizer only support RegularizedGaussian with box or nonnegativity constraint.")
279
- else:
280
- self._solver = value
281
-
282
- @property
283
- def proximal(self):
284
- return self.target.prior.proximal
285
-
286
- def validate_target(self):
287
- super().validate_target()
288
- if not isinstance(self.target.prior, (cuqi.implicitprior.RegularizedGaussian, cuqi.implicitprior.RegularizedGMRF)):
289
- raise TypeError("Prior needs to be RegularizedGaussian or RegularizedGMRF")
290
-
291
- def _choose_stepsize(self):
292
- if isinstance(self.stepsize, str):
293
- if self.stepsize in ["automatic"]:
294
- if not callable(self.M):
295
- M_op = scipyLinearOperator(self.M.shape, matvec = lambda v: self.M@v, rmatvec = lambda w: self.M.T@w)
296
- else:
297
- M_op = scipyLinearOperator((len(self.b_tild), self.n), matvec = lambda v: self.M(v,1), rmatvec = lambda w: self.M(w,2))
298
-
299
- _stepsize = 0.99/(estimate_spectral_norm(M_op)**2)
300
- # print(f"Estimated stepsize for regularized Linear RTO: {_stepsize}")
301
- else:
302
- raise ValueError("Stepsize choice not supported")
303
- else:
304
- _stepsize = self.stepsize
305
- return _stepsize
306
-
307
- @property
308
- def prior(self):
309
- return self.target.prior.gaussian
310
-
311
- def _compute_map_regularized(self):
312
- self._map = self._customized_step(self.b_tild, self.initial_point)
313
-
314
- def _customized_step(self, y, x0):
315
- if self.solver == "FISTA":
316
- sim = FISTA(self.M, y, self.proximal,
317
- x0, maxit = self.maxit, stepsize = self._stepsize, abstol = self.abstol, adaptive = self.adaptive)
318
- elif self.solver == "ADMM":
319
- sim = ADMM(self.M, y, self.proximal,
320
- x0, self.penalty_parameter, maxit = self.maxit, inner_max_it = self.inner_max_it, adaptive = self.adaptive)
321
- elif self.solver == "ScipyLinearLSQ":
322
- A_op = sp.sparse.linalg.LinearOperator((sum([llh.distribution.dim for llh in self.likelihoods])+self.target.prior.dim, self.target.prior.dim),
323
- matvec=lambda x: self.M(x, 1),
324
- rmatvec=lambda x: self.M(x, 2)
325
- )
326
- sim = ScipyLinearLSQ(A_op, y, self.target.prior._box_bounds,
327
- max_iter = self.maxit,
328
- lsmr_maxiter = self.inner_max_it,
329
- tol = self.abstol,
330
- lsmr_tol = self.inner_abstol)
331
- elif self.solver == "ScipyMinimizer":
332
- # Adapt bounds format, as scipy.minimize requires a bounds format
333
- # different than that in scipy.lsq_linear.
334
- bounds = [(self.target.prior._box_bounds[0][i], self.target.prior._box_bounds[1][i]) for i in range(self.target.prior.dim)]
335
- # Note that the objective function is defined as 0.5*||Mx-y||^2,
336
- # and the corresponding gradient (gradfunc) is given by M^T(Mx-y).
337
- sim = ScipyMinimizer(lambda x: 0.5*np.sum((self.M(x, 1)-y)**2), x0, gradfunc=lambda x: self.M(self.M(x, 1) - y, 2), bounds=bounds, tol=self.abstol, options={"maxiter": self.maxit})
338
- else:
339
- raise ValueError("Choice of solver not supported.")
340
-
341
- sol, _ = sim.solve()
342
- return sol
343
-
344
- def step(self):
345
- y = self.b_tild + np.random.randn(len(self.b_tild))
346
-
347
- self.current_point = self._customized_step(y, self.inner_initial_point)
348
-
349
- acc = 1
350
- return acc