eryn 1.2.2__py3-none-any.whl → 1.2.4__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.
eryn/backends/backend.py CHANGED
@@ -703,8 +703,11 @@ class Backend(object):
703
703
  "thermo",
704
704
  "ti",
705
705
  ]:
706
- logls = np.mean(logls_all, axis=(0, -1))
707
- logZ, dlogZ = thermodynamic_integration_log_evidence(betas, logls)
706
+ logls = logls_all.copy()
707
+ logls[~np.isfinite(logls)] = np.nan
708
+ meanlogls = np.nanmean(logls, axis=(0, -1))
709
+ logZ, dlogZ = thermodynamic_integration_log_evidence(betas, meanlogls)
710
+
708
711
  elif method.lower() in [
709
712
  "stepping stone",
710
713
  "ss",
eryn/ensemble.py CHANGED
@@ -1208,6 +1208,9 @@ class EnsembleSampler(object):
1208
1208
  # vectorized because everything is rectangular (no groups to indicate model difference)
1209
1209
  prior_out += prior_out_temp.sum(axis=-1)
1210
1210
 
1211
+ if np.any(np.isnan(prior_out)):
1212
+ raise ValueError("The prior function is returning Nan.")
1213
+
1211
1214
  return prior_out
1212
1215
 
1213
1216
  def compute_log_like(
@@ -1493,8 +1496,9 @@ class EnsembleSampler(object):
1493
1496
  ll[inds_fix_zeros] = self.fill_zero_leaves_val
1494
1497
 
1495
1498
  # deal with blobs
1496
- blobs_out = np.zeros((nwalkers_all, results.shape[1] - 1))
1497
- blobs_out[unique_groups] = results[:, 1:]
1499
+ _blobs_out = np.zeros((nwalkers_all, results.shape[1] - 1))
1500
+ _blobs_out[unique_groups] = results[:, 1:]
1501
+ blobs_out = _blobs_out.reshape(ntemps, nwalkers)
1498
1502
 
1499
1503
  elif results.dtype == "object":
1500
1504
  # TODO: check blobs and add this capability
@@ -1531,6 +1535,9 @@ class EnsembleSampler(object):
1531
1535
  for key in branch_supps_in_2[name_i]
1532
1536
  }
1533
1537
 
1538
+ if np.any(np.isnan(ll)):
1539
+ raise ValueError("The likelihood function is returning Nan.")
1540
+
1534
1541
  # return Likelihood and blobs
1535
1542
  return ll.reshape(ntemps, nwalkers), blobs_out
1536
1543
 
eryn/moves/gaussian.py CHANGED
@@ -137,7 +137,12 @@ class _isotropic_proposal(object):
137
137
  def __init__(self, scale, factor, mode):
138
138
  self.index = 0
139
139
  self.scale = scale
140
- self.invscale = np.linalg.inv(np.linalg.cholesky(scale))
140
+
141
+ if isinstance(scale, float):
142
+ self.invscale = 1. / scale
143
+ else:
144
+ self.invscale = np.linalg.inv(np.linalg.cholesky(scale))
145
+
141
146
  if factor is None:
142
147
  self._log_factor = None
143
148
  else:
eryn/utils/utility.py CHANGED
@@ -237,11 +237,12 @@ def stepping_stone_log_evidence(betas, logls, block_len=50, repeats=100):
237
237
 
238
238
  def calculate_stepping_stone(betas, logls):
239
239
  n = logls.shape[0]
240
- delta_betas = betas[1:] - betas[:-1]
241
240
  n_T = betas.shape[0]
242
- log_ratio = logsumexp(delta_betas * logls[:, :-1], axis=0) - np.log(n)
241
+ delta_betas = betas[1:] - betas[:-1]
242
+ throwaways = np.any(~np.isfinite(logls), axis=1) # a safeguard against non-finite entries
243
+ log_ratio = logsumexp(delta_betas * logls[~throwaways, :-1], axis=0) - (n_T - 1.0)*np.log(n - np.sum(throwaways))
243
244
  return np.sum(log_ratio), log_ratio
244
-
245
+
245
246
  # make sure they are the same length
246
247
  if len(betas) != logls.shape[1]:
247
248
  raise ValueError(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: eryn
3
- Version: 1.2.2
3
+ Version: 1.2.4
4
4
  Summary: Eryn: an omni-MCMC sampling package.
5
5
  Author: Michael Katz
6
6
  Author-email: Michael Katz <mikekatz04@gmail.com>
@@ -1,9 +1,9 @@
1
1
  eryn/CMakeLists.txt,sha256=rs-_qMYpJryM_FyvERto4RgQQ_NV4lkYvFzCNU7vvFc,1736
2
2
  eryn/__init__.py,sha256=eMxCEUQyqtaUM8zTr6kDCxeuFWpxZsfY41TefWUNHXI,821
3
3
  eryn/backends/__init__.py,sha256=yRQszA4WSofDDsSpTsA1V9eNw-pLVO_qalP5wpKjyZQ,380
4
- eryn/backends/backend.py,sha256=Gcl6qk8UI1QKK74C8Kr9QYASWzuKLJhxPOj9OyiDSFI,46906
4
+ eryn/backends/backend.py,sha256=VitOOK3vkzVlpzYj-y-_N0Q5GA6DBdm9ZwIMKvQjBOE,47011
5
5
  eryn/backends/hdfbackend.py,sha256=njW1KA2Anw9zxpLTYLkpNErNRBgNMA4VKidZXidkh-A,29414
6
- eryn/ensemble.py,sha256=SWkOml63_LP2ZMUF38jJTwsmIr1_JUoSFhslWQ7fSco,71701
6
+ eryn/ensemble.py,sha256=TqpTLun3iydLOycEi2Gtlg0enLEL2raVrPyVMIQgn-o,71998
7
7
  eryn/git_version.py.in,sha256=dZ5WklaoF4dDsCVqhgw5jwr3kJCc8zjRX_LR90byZOw,139
8
8
  eryn/model.py,sha256=5TeWTI6V-Xcuy5C2LI6AmtZZU-EkRSSuA7VojXNALk8,284
9
9
  eryn/moves/__init__.py,sha256=9pWsSZSKLt05Ihd46vPASHwotTOHOPk_zEsCm8jWiw8,1081
@@ -11,7 +11,7 @@ eryn/moves/combine.py,sha256=YfIiRqObi11qBbTgqRQ3nMBr6a-ugGGBd1VgPSEosx4,4545
11
11
  eryn/moves/delayedrejection.py,sha256=deaPPwNG2nKz-FAvi5NVTsrcoKONhy-LD15FLN0iLpY,7645
12
12
  eryn/moves/distgen.py,sha256=jNTxL23KSradICJydeTsUcnE7BqMDTPmzuGh4ydQGkQ,3935
13
13
  eryn/moves/distgenrj.py,sha256=szTgY1VYriJ1YYDJEOYT_kkjewk42BoXgQeZc41CO_c,9133
14
- eryn/moves/gaussian.py,sha256=5No4tN3PFzkx5JugLwX8LboSXBt2DOHU8xegtj5zOGo,6853
14
+ eryn/moves/gaussian.py,sha256=Uj1O14ONPReku8SoYLZ00_MIPjbHrxL9LM05bLqHdCk,6957
15
15
  eryn/moves/group.py,sha256=sm1iUvHJwuk_dvtmBTbmhZBbB_Esxl_4f2h0Ofx5p7s,10100
16
16
  eryn/moves/groupstretch.py,sha256=tMXeCauYy_AyAhWM5kpgOcoQRdKLJYx2h85Tdfq6WLk,3920
17
17
  eryn/moves/mh.py,sha256=63xvBRk6iNLn6EZmGb1W_buLmNw3WS7ch4kSK7yGfeE,6517
@@ -26,14 +26,12 @@ eryn/moves/tempering.py,sha256=e2doT8jVWSuaPpVUKIkWQjRe20T0i98w70wi-dz7buo,23977
26
26
  eryn/pbar.py,sha256=uDDn8dMVHLD6EqZyk6vGhkOQwxgFm21Us9dz-nZE4oI,1330
27
27
  eryn/prior.py,sha256=x4E5NS4v7Odag7a30OXQ-kJuoU3a6M6JnJuKlWGO6F4,14393
28
28
  eryn/state.py,sha256=x4HZNrGhxnR6Ia2JrVskJGDS1Uk3AgQHgxJ4384Hpzs,31456
29
- eryn/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- eryn/tests/test_eryn.py,sha256=JTac0NdiBfTa2-l8z0Q6S5oxr-C-UzH0uNTOE61jVFY,39792
31
29
  eryn/utils/__init__.py,sha256=HzlQs1wg3J1xdrZjIMO34QHd0ZT58SQFCKEdclj7vpM,250
32
30
  eryn/utils/periodic.py,sha256=Q07HKMNeUN8V_rauUjT7fKRwlYOd2AFsa9DekuRYUbk,4135
33
31
  eryn/utils/stopping.py,sha256=fX1np10U3B-fpI3dGqEPZfqeYt8dc0x3PQGwrvYbbFU,5095
34
32
  eryn/utils/transform.py,sha256=wzOYow7xHjqVOi8ZQDXBeoFj9y53cCtIeLggrQuo_sc,8895
35
33
  eryn/utils/updates.py,sha256=U3T9UxPLabJzJuuB9s2OuX3vMD_2P7486SkgaFEkbLw,2137
36
- eryn/utils/utility.py,sha256=Mxmx-XoLe5tEdzc2QuprpOd3u4Z2aYmR4aDVWRi6Jsk,11151
37
- eryn-1.2.2.dist-info/WHEEL,sha256=pFCy50wRV2h7SjJ35YOsQUupaV45rMdgpNIvnXbG5bE,79
38
- eryn-1.2.2.dist-info/METADATA,sha256=FYUcecJC6kTsKZdUQpa3zCH-1srOJIRhoe5OKHhd7SM,6240
39
- eryn-1.2.2.dist-info/RECORD,,
34
+ eryn/utils/utility.py,sha256=mgmfoL0BFFb3hho7OAQSJLO7T_erx6f6t38V-5yKSA4,11296
35
+ eryn-1.2.4.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
36
+ eryn-1.2.4.dist-info/METADATA,sha256=IBGDzBc3Esx7RPZ_RKSFQewgaitRnFyVEaacPn3-9MA,6240
37
+ eryn-1.2.4.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.8.19
2
+ Generator: uv 0.8.24
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
eryn/tests/__init__.py DELETED
File without changes
eryn/tests/test_eryn.py DELETED
@@ -1,1246 +0,0 @@
1
- #!/usr/bin/env python
2
- # coding: utf-8
3
-
4
- # In[14]:
5
-
6
-
7
- from eryn.ensemble import EnsembleSampler
8
- from eryn.state import State
9
- from eryn.prior import ProbDistContainer, uniform_dist
10
- from eryn.utils import TransformContainer
11
- from eryn.moves import (
12
- GaussianMove,
13
- StretchMove,
14
- CombineMove,
15
- DistributionGenerateRJ,
16
- GroupStretchMove,
17
- )
18
- from eryn.utils.utility import groups_from_inds
19
- from eryn.backends import HDFBackend
20
-
21
- import os
22
- import unittest
23
- import matplotlib.pyplot as plt
24
- import numpy as np
25
-
26
- # set random seed
27
- np.random.seed(42)
28
-
29
- import corner
30
-
31
-
32
- # Gaussian likelihood
33
- def log_like_fn(x, mu, invcov):
34
- diff = x - mu
35
- return -0.5 * (diff * np.dot(invcov, diff.T).T).sum()
36
-
37
-
38
- def gaussian_pulse(x, a, b, c):
39
- f_x = a * np.exp(-((x - b) ** 2) / (2 * c**2))
40
- return f_x
41
-
42
-
43
- def combine_gaussians(t, params):
44
- template = np.zeros_like(t)
45
- for param in params:
46
- template += gaussian_pulse(t, *param) # *params -> a, b, c
47
- return template
48
-
49
-
50
- def log_like_fn_gauss_pulse(params, t, data, sigma):
51
- template = combine_gaussians(t, params)
52
-
53
- ll = -0.5 * np.sum(((template - data) / sigma) ** 2, axis=-1)
54
- return ll
55
-
56
-
57
- def gaussian_pulse(x, a, b, c):
58
- f_x = a * np.exp(-((x - b) ** 2) / (2 * c**2))
59
- return f_x
60
-
61
-
62
- def combine_gaussians(t, params):
63
- template = np.zeros_like(t)
64
- for param in params:
65
- template += gaussian_pulse(t, *param) # *params -> a, b, c
66
- return template
67
-
68
-
69
- def sine(x, a, b, c):
70
- f_x = a * np.sin(2 * np.pi * b * x + c)
71
- return f_x
72
-
73
-
74
- def combine_sine(t, params):
75
- template = np.zeros_like(t)
76
- for param in params:
77
- template += sine(t, *param) # *params -> a, b, c
78
- return template
79
-
80
-
81
- def log_like_fn_gauss_and_sine(params_both, t, data, sigma):
82
- params_gauss, params_sine = params_both
83
- template = np.zeros_like(t)
84
-
85
- if params_gauss is not None:
86
- template += combine_gaussians(t, params_gauss)
87
-
88
- if params_sine is not None:
89
- template += combine_sine(t, params_sine)
90
-
91
- ll = -0.5 * np.sum(((template - data) / sigma) ** 2, axis=-1)
92
- return ll
93
-
94
-
95
- class ErynTest(unittest.TestCase):
96
- def test_base(self):
97
- ndim = 5
98
- nwalkers = 99
99
-
100
- means = np.zeros(ndim) # np.random.rand(ndim)
101
-
102
- # define covariance matrix
103
- cov = np.diag(np.ones(ndim))
104
- invcov = np.linalg.inv(cov)
105
-
106
- lims = 5.0
107
- priors_in = {
108
- i: uniform_dist(-lims + means[i], lims + means[i]) for i in range(ndim)
109
- }
110
- priors = ProbDistContainer(priors_in)
111
-
112
- ensemble = EnsembleSampler(
113
- nwalkers,
114
- ndim,
115
- log_like_fn,
116
- priors,
117
- args=[means, invcov],
118
- )
119
-
120
- coords = priors.rvs(size=(nwalkers,))
121
-
122
- # check log_like
123
- log_like = np.asarray(
124
- [log_like_fn(coords[i], means, invcov) for i in range(nwalkers)]
125
- )
126
-
127
- # check log_prior
128
- log_prior = np.asarray([priors.logpdf(coords[i]) for i in range(nwalkers)])
129
-
130
- nsteps = 50
131
- # burn for 1000 steps
132
- burn = 10
133
- # thin by 5
134
- thin_by = 1
135
- out = ensemble.run_mcmc(
136
- coords, nsteps, burn=burn, progress=False, thin_by=thin_by
137
- )
138
-
139
- samples = ensemble.get_chain()["model_0"].reshape(-1, ndim)
140
-
141
- ll = ensemble.backend.get_log_like()
142
- lp = ensemble.backend.get_log_prior()
143
-
144
- samples = ensemble.get_chain()
145
-
146
- ensemble.backend.shape
147
-
148
- last_state = ensemble.backend.get_last_sample()
149
-
150
- last_state.branches
151
-
152
- last_state.branches["model_0"].coords
153
-
154
- def test_pt(self):
155
- # set up problem
156
- ndim = 5
157
- nwalkers = 100
158
- ntemps = 10
159
-
160
- means = np.zeros(ndim) # np.random.rand(ndim)
161
-
162
- # define covariance matrix
163
- cov = np.diag(np.ones(ndim))
164
- invcov = np.linalg.inv(cov)
165
-
166
- lims = 5.0
167
- priors_in = {
168
- i: uniform_dist(-lims + means[i], lims + means[i]) for i in range(ndim)
169
- }
170
- priors = ProbDistContainer(priors_in)
171
-
172
- # fill kwargs dictionary
173
- tempering_kwargs = dict(ntemps=ntemps)
174
-
175
- # randomize throughout prior
176
- coords = priors.rvs(
177
- size=(
178
- ntemps,
179
- nwalkers,
180
- )
181
- )
182
-
183
- backend_test_file = "_hdf_backend_test_file.h5"
184
- # initialize sampler
185
- ensemble_pt = EnsembleSampler(
186
- nwalkers,
187
- ndim,
188
- log_like_fn,
189
- priors,
190
- args=[means, cov],
191
- backend=backend_test_file,
192
- tempering_kwargs=tempering_kwargs,
193
- )
194
-
195
- nsteps = 50
196
- # burn for 1000 steps
197
- burn = 10
198
- # thin by 5
199
- thin_by = 1
200
- ensemble_pt.run_mcmc(coords, nsteps, burn=burn, progress=False, thin_by=thin_by)
201
-
202
- for temp in range(ntemps):
203
- samples = ensemble_pt.get_chain()["model_0"][:, temp].reshape(-1, ndim)
204
-
205
- ll = ensemble_pt.backend.get_log_like()
206
-
207
- # check temperature index and branch_names
208
- cold_chain = ensemble_pt.backend.get_chain(discard=10, thin=2, temp_index=0, branch_names=["model_0"])
209
- os.remove(backend_test_file)
210
-
211
- def test_rj(self):
212
- nwalkers = 20
213
- ntemps = 8
214
- ndim = 3
215
- nleaves_max = {"gauss": 1}
216
- nleaves_min = {"gauss": 0}
217
-
218
- branch_names = ["gauss"]
219
-
220
- # define time stream
221
- num = 500
222
- t = np.linspace(-1, 1, num)
223
-
224
- gauss_inj_params = [
225
- # [3.3, -0.2, 0.1],
226
- # [2.6, -0.1, 0.1],
227
- # [3.4, 0.0, 0.1],
228
- # [2.9, 0.3, 0.1],
229
- ]
230
-
231
- # combine gaussians
232
- injection = combine_gaussians(t, np.asarray(gauss_inj_params))
233
-
234
- # set noise level
235
- sigma = 0.00001
236
-
237
- # produce full data
238
- y = injection + sigma * np.random.randn(len(injection))
239
-
240
- coords = {"gauss": np.zeros((ntemps, nwalkers, nleaves_max["gauss"], ndim))}
241
-
242
- # this is the sigma for the multivariate Gaussian that sets starting points
243
- # We need it to be very small to assume we are passed the search phase
244
- # we will verify this is with likelihood calculations
245
- sig1 = 0.0001
246
-
247
- # setup initial walkers to be the correct count (it will spread out)
248
- # for nn in range(nleaves_max["gauss"]):
249
- # if nn >= len(gauss_inj_params):
250
- # # not going to add parameters for these unused leaves
251
- # continue
252
-
253
- # coords["gauss"][:, :, nn] = np.random.multivariate_normal(
254
- # gauss_inj_params[nn],
255
- # np.diag(np.ones(3) * sig1),
256
- # size=(ntemps, nwalkers),
257
- # )
258
-
259
- # make sure to start near the proper setup
260
- inds = {"gauss": np.zeros((ntemps, nwalkers, nleaves_max["gauss"]), dtype=bool)}
261
-
262
- # turn False -> True for any binary in the sampler
263
- # inds["gauss"][:, :, : len(gauss_inj_params)] = True
264
-
265
- # describes priors for all leaves independently
266
- priors = {
267
- "gauss": {
268
- 0: uniform_dist(2.5, 3.5), # amplitude
269
- 1: uniform_dist(t.min(), t.max()), # mean
270
- 2: uniform_dist(0.01, 0.21), # sigma
271
- },
272
- }
273
-
274
- # for the Gaussian Move, will be explained later
275
- factor = 0.00001
276
- cov = {"gauss": np.diag(np.ones(ndim)) * factor}
277
-
278
- priors_gen = {"gauss": ProbDistContainer(priors["gauss"])}
279
- moves = GaussianMove(cov)
280
- rj_moves = [
281
- DistributionGenerateRJ(
282
- priors_gen, nleaves_min=nleaves_min, nleaves_max=nleaves_max
283
- ),
284
- DistributionGenerateRJ(
285
- priors_gen, nleaves_min=nleaves_min, nleaves_max=nleaves_max
286
- ),
287
- ]
288
-
289
- base_like = log_like_fn_gauss_pulse(np.asarray([]), t, y, sigma)
290
-
291
- ensemble = EnsembleSampler(
292
- nwalkers,
293
- ndim,
294
- log_like_fn_gauss_pulse,
295
- priors,
296
- args=[t, y, sigma],
297
- tempering_kwargs=dict(ntemps=ntemps),
298
- nbranches=len(branch_names),
299
- branch_names=branch_names,
300
- nleaves_max=nleaves_max,
301
- nleaves_min=nleaves_min,
302
- moves=moves,
303
- fill_zero_leaves_val=base_like,
304
- rj_moves=rj_moves, # basic generation of new leaves from the prior
305
- )
306
-
307
- log_prior = ensemble.compute_log_prior(coords, inds=inds)
308
- log_like = ensemble.compute_log_like(coords, inds=inds, logp=log_prior)[0]
309
-
310
- # setup starting state
311
- state = State(coords, log_like=log_like, log_prior=log_prior, inds=inds)
312
-
313
- nsteps = 1000
314
- last_sample = ensemble.run_mcmc(
315
- state, nsteps, burn=1000, progress=True, thin_by=1
316
- )
317
-
318
- last_sample.branches["gauss"].nleaves
319
-
320
- nleaves = ensemble.get_nleaves()["gauss"]
321
- bns = (
322
- np.arange(1, nleaves_max["gauss"] + 2) - 0.5
323
- ) # Just to make it pretty and center the bins
324
-
325
- samples = ensemble.get_chain()["gauss"][:, 0].reshape(-1, ndim)
326
-
327
- # same as ensemble.get_chain()['gauss'][ensemble.get_inds()['gauss']]
328
- samples = samples[~np.isnan(samples[:, 0])]
329
-
330
- # check temperature index and branch_names
331
- cold_chain = ensemble.backend.get_chain(discard=10, thin=2, temp_index=1, branch_names=["gauss"])
332
-
333
- #means = np.asarray(gauss_inj_params)[:, 1]
334
- # fig, (ax1, ax2) = plt.subplots(1, 2)
335
- # ax1.hist(nleaves[:, 0].flatten(), np.arange(0, 3) - 0.5)
336
- # ax2.plot(t, y)
337
- # ax2.plot(t, injection)
338
- # plt.show()
339
- # breakpoint()
340
-
341
- def test_rj_multiple_branches(self):
342
- nwalkers = 20
343
- ntemps = 8
344
- ndims = {"gauss": 3, "sine": 3}
345
- nleaves_max = {"gauss": 8, "sine": 4}
346
- nleaves_min = {"gauss": 0, "sine": 0}
347
-
348
- branch_names = ["gauss", "sine"]
349
-
350
- # define time stream
351
- num = 500
352
- t = np.linspace(-1, 1, num)
353
-
354
- gauss_inj_params = [
355
- [3.3, -0.2, 0.1],
356
- [2.6, -0.1, 0.1],
357
- [3.4, 0.0, 0.1],
358
- [2.9, 0.3, 0.1],
359
- ]
360
-
361
- sine_inj_params = [
362
- [1.3, 10.1, 1.0],
363
- [0.8, 4.6, 1.2],
364
- ]
365
-
366
- # combine gaussians
367
- injection = combine_gaussians(t, np.asarray(gauss_inj_params))
368
- injection += combine_sine(t, np.asarray(sine_inj_params))
369
-
370
- # set noise level
371
- sigma = 200.0
372
-
373
- # produce full data
374
- y = injection + sigma * np.random.randn(len(injection))
375
-
376
- coords = {
377
- "gauss": np.zeros((ntemps, nwalkers, nleaves_max["gauss"], ndims["gauss"])),
378
- "sine": np.zeros((ntemps, nwalkers, nleaves_max["sine"], ndims["sine"])),
379
- }
380
-
381
- # make sure to start near the proper setup
382
- inds = {
383
- "gauss": np.zeros((ntemps, nwalkers, nleaves_max["gauss"]), dtype=bool),
384
- "sine": np.zeros((ntemps, nwalkers, nleaves_max["sine"]), dtype=bool),
385
- }
386
-
387
- # this is the sigma for the multivariate Gaussian that sets starting points
388
- # We need it to be very small to assume we are passed the search phase
389
- # we will verify this is with likelihood calculations
390
- sig1 = 0.0001
391
-
392
- # setup initial walkers to be the correct count (it will spread out)
393
- # start with gaussians
394
- for nn in range(nleaves_max["gauss"]):
395
- if nn >= len(gauss_inj_params):
396
- # not going to add parameters for these unused leaves
397
- continue
398
- coords["gauss"][:, :, nn] = np.random.multivariate_normal(
399
- gauss_inj_params[nn],
400
- np.diag(np.ones(3) * sig1),
401
- size=(ntemps, nwalkers),
402
- )
403
- inds["gauss"][:, :, nn] = True
404
-
405
- # next do sine waves
406
- for nn in range(nleaves_max["sine"]):
407
- if nn >= len(sine_inj_params):
408
- # not going to add parameters for these unused leaves
409
- continue
410
- coords["sine"][:, :, nn] = np.random.multivariate_normal(
411
- sine_inj_params[nn], np.diag(np.ones(3) * sig1), size=(ntemps, nwalkers)
412
- )
413
- inds["sine"][:, :, nn] = True
414
-
415
- # describes priors for all leaves independently
416
- priors = {
417
- "gauss": {
418
- 0: uniform_dist(2.5, 3.5), # amplitude
419
- 1: uniform_dist(t.min(), t.max()), # mean
420
- 2: uniform_dist(0.01, 0.21), # sigma
421
- },
422
- "sine": {
423
- 0: uniform_dist(0.5, 1.5), # amplitude
424
- 1: uniform_dist(1.0, 20.0), # mean
425
- 2: uniform_dist(0.0, 2 * np.pi), # sigma
426
- },
427
- }
428
-
429
- # for the Gaussian Move, will be explained later
430
- factor = 0.00001
431
- cov = {
432
- "gauss": np.diag(np.ones(ndims["gauss"])) * factor,
433
- "sine": np.diag(np.ones(ndims["sine"])) * factor,
434
- }
435
-
436
- moves = GaussianMove(cov)
437
-
438
- fp = "_test_backend.h5"
439
-
440
- # just to test iterate_branches
441
- tmp = EnsembleSampler(
442
- nwalkers,
443
- ndims,
444
- log_like_fn_gauss_and_sine,
445
- priors,
446
- args=[t, y, sigma],
447
- tempering_kwargs=dict(ntemps=ntemps),
448
- nbranches=len(branch_names),
449
- branch_names=branch_names,
450
- nleaves_max=nleaves_max,
451
- nleaves_min=nleaves_min,
452
- moves=moves,
453
- rj_moves="iterate_branches", # basic generation of new leaves from the prior
454
- backend=None,
455
- )
456
- del tmp
457
-
458
- ensemble = EnsembleSampler(
459
- nwalkers,
460
- ndims,
461
- log_like_fn_gauss_and_sine,
462
- priors,
463
- args=[t, y, sigma],
464
- tempering_kwargs=dict(ntemps=ntemps),
465
- nbranches=len(branch_names),
466
- branch_names=branch_names,
467
- nleaves_max=nleaves_max,
468
- nleaves_min=nleaves_min,
469
- moves=moves,
470
- rj_moves="separate_branches", # basic generation of new leaves from the prior
471
- backend=fp,
472
- )
473
-
474
- log_prior = ensemble.compute_log_prior(coords, inds=inds)
475
- log_like = ensemble.compute_log_like(coords, inds=inds, logp=log_prior)[0]
476
-
477
- # make sure it is reasonably close to the maximum which this is
478
- # will not be zero due to noise
479
-
480
- # setup starting state
481
- state = State(coords, log_like=log_like, log_prior=log_prior, inds=inds)
482
-
483
- state.branches
484
-
485
- nsteps = 50
486
- last_sample = ensemble.run_mcmc(
487
- state, nsteps, burn=10, progress=False, thin_by=1
488
- )
489
-
490
- np.array(
491
- [
492
- last_sample.branches["gauss"].nleaves[0],
493
- last_sample.branches["sine"].nleaves[0],
494
- ]
495
- ).T
496
-
497
- nleaves_gauss = ensemble.get_nleaves()["gauss"]
498
- nleaves_sine = ensemble.get_nleaves()["sine"]
499
-
500
- samples = ensemble.get_chain()["gauss"][:, 0].reshape(-1, ndims["gauss"])
501
-
502
- # same as ensemble.get_chain()['gauss'][ensemble.get_inds()['gauss']]
503
- samples = samples[~np.isnan(samples[:, 0])]
504
-
505
- means = np.asarray(gauss_inj_params)[:, 1]
506
-
507
- os.remove(fp)
508
-
509
- def test_gibbs_sampling(self):
510
- nwalkers = 20
511
- ntemps = 8
512
- ndims = {"gauss": 3, "sine": 3}
513
- nleaves_max = {"gauss": 8, "sine": 2} # same min and max means no changing
514
- nleaves_min = {"gauss": 0, "sine": 2}
515
-
516
- branch_names = ["gauss", "sine"]
517
-
518
- # define time stream
519
- num = 500
520
- t = np.linspace(-1, 1, num)
521
-
522
- gauss_inj_params = [
523
- [3.3, -0.2, 0.1],
524
- [2.6, -0.1, 0.1],
525
- [3.4, 0.0, 0.1],
526
- [2.9, 0.3, 0.1],
527
- ]
528
-
529
- sine_inj_params = [
530
- [1.3, 10.1, 1.0],
531
- [0.8, 4.6, 1.2],
532
- ]
533
-
534
- # combine gaussians
535
- injection = combine_gaussians(t, np.asarray(gauss_inj_params))
536
- injection += combine_sine(t, np.asarray(sine_inj_params))
537
-
538
- # set noise level
539
- sigma = 2.0
540
-
541
- # produce full data
542
- y = injection + sigma * np.random.randn(len(injection))
543
-
544
- coords = {
545
- "gauss": np.zeros((ntemps, nwalkers, nleaves_max["gauss"], ndims["gauss"])),
546
- "sine": np.zeros((ntemps, nwalkers, nleaves_max["sine"], ndims["sine"])),
547
- }
548
-
549
- # make sure to start near the proper setup
550
- inds = {
551
- "gauss": np.zeros((ntemps, nwalkers, nleaves_max["gauss"]), dtype=bool),
552
- "sine": np.ones((ntemps, nwalkers, nleaves_max["sine"]), dtype=bool),
553
- }
554
-
555
- # this is the sigma for the multivariate Gaussian that sets starting points
556
- # We need it to be very small to assume we are passed the search phase
557
- # we will verify this is with likelihood calculations
558
- sig1 = 0.0001
559
-
560
- # setup initial walkers to be the correct count (it will spread out)
561
- # start with gaussians
562
- for nn in range(nleaves_max["gauss"]):
563
- if nn >= len(gauss_inj_params):
564
- # not going to add parameters for these unused leaves
565
- continue
566
- coords["gauss"][:, :, nn] = np.random.multivariate_normal(
567
- gauss_inj_params[nn],
568
- np.diag(np.ones(3) * sig1),
569
- size=(ntemps, nwalkers),
570
- )
571
- inds["gauss"][:, :, nn] = True
572
-
573
- # next do sine waves
574
- for nn in range(nleaves_max["sine"]):
575
- if nn >= len(sine_inj_params):
576
- # not going to add parameters for these unused leaves
577
- continue
578
- coords["sine"][:, :, nn] = np.random.multivariate_normal(
579
- sine_inj_params[nn], np.diag(np.ones(3) * sig1), size=(ntemps, nwalkers)
580
- )
581
- # inds["sine"][:, :, nn] = True # already True
582
-
583
- # describes priors for all leaves independently
584
- priors = {
585
- "gauss": {
586
- 0: uniform_dist(2.5, 3.5), # amplitude
587
- 1: uniform_dist(t.min(), t.max()), # mean
588
- 2: uniform_dist(0.01, 0.21), # sigma
589
- },
590
- "sine": {
591
- 0: uniform_dist(0.5, 1.5), # amplitude
592
- 1: uniform_dist(1.0, 20.0), # mean
593
- 2: uniform_dist(0.0, 2 * np.pi), # sigma
594
- },
595
- }
596
-
597
- # for the Gaussian Move
598
- factor = 0.00001
599
- cov = {
600
- "gauss": np.diag(np.ones(ndims["gauss"])) * factor,
601
- }
602
-
603
- # pass boolean array of shape (nleaves_max["gauss"], ndims["gauss"])
604
- gibbs_sampling_gauss = [
605
- ("gauss", np.zeros((nleaves_max["gauss"], ndims["gauss"]), dtype=bool))
606
- for _ in range(nleaves_max["gauss"])
607
- ]
608
-
609
- for i in range(nleaves_max["gauss"]):
610
- gibbs_sampling_gauss[i][-1][i] = True
611
-
612
- gauss_move = GaussianMove(cov, gibbs_sampling_setup=gibbs_sampling_gauss)
613
-
614
- gibbs_sampling_sine = [
615
- ("sine", np.zeros((nleaves_max["sine"], ndims["sine"]), dtype=bool))
616
- for _ in range(2 * nleaves_max["sine"])
617
- ]
618
- for i in range(nleaves_max["sine"]):
619
- for j in range(2):
620
- if j == 0:
621
- gibbs_sampling_sine[2 * i + j][-1][i, :2] = True
622
- else:
623
- gibbs_sampling_sine[2 * i + j][-1][i, 2:] = True
624
-
625
- sine_move = StretchMove(
626
- live_dangerously=True, gibbs_sampling_setup=gibbs_sampling_sine
627
- )
628
-
629
- move = CombineMove([gauss_move, sine_move])
630
-
631
- ensemble = EnsembleSampler(
632
- nwalkers,
633
- ndims,
634
- log_like_fn_gauss_and_sine,
635
- priors,
636
- args=[t, y, sigma],
637
- tempering_kwargs=dict(ntemps=ntemps),
638
- nbranches=len(branch_names),
639
- branch_names=branch_names,
640
- nleaves_max=nleaves_max,
641
- nleaves_min=nleaves_min,
642
- moves=move,
643
- rj_moves=True, # basic generation of new leaves from the prior
644
- )
645
-
646
- log_prior = ensemble.compute_log_prior(coords, inds=inds)
647
- log_like = ensemble.compute_log_like(coords, inds=inds, logp=log_prior)[0]
648
-
649
- # make sure it is reasonably close to the maximum which this is
650
- # will not be zero due to noise
651
-
652
- # setup starting state
653
- state = State(coords, log_like=log_like, log_prior=log_prior, inds=inds)
654
-
655
- nsteps = 50
656
- last_sample = ensemble.run_mcmc(
657
- state, nsteps, burn=10, progress=False, thin_by=1
658
- )
659
-
660
- def test_utilities(self):
661
- def transform1(x, y):
662
- return x * y, y / x
663
-
664
- # this will do transform lambda x, y: (x**2, y**2) before transform1
665
- parameter_transforms = {
666
- 0: lambda x: np.log(x),
667
- (1, 2): lambda x, y: (x**2, y**2),
668
- (0, 2): transform1,
669
- }
670
-
671
- fill_dict = {
672
- "ndim_full": 6, # full dimensionality after values are added
673
- "fill_inds": np.array([2, 3, 5]), # indexes for fill values in final array
674
- "fill_values": np.array([0.0, 1.0, -1.0]), # associated values for filling
675
- }
676
-
677
- tc = TransformContainer(
678
- parameter_transforms=parameter_transforms, fill_dict=fill_dict
679
- )
680
-
681
- x = np.random.uniform(0.1, 4.0, size=(40, 3))
682
-
683
- # can copy and transpose values if needed
684
- out = tc.transform_base_parameters(x, copy=True, return_transpose=False)
685
-
686
- def lnprob(x1, group1, x2, group2, transform_containers):
687
- x = [x1, x2]
688
- for i, (x_i, transform) in enumerate(zip([x1, x2], transform_containers)):
689
- temp = transform.transform_base_parameters(
690
- x_i, copy=True, return_transpose=False
691
- )
692
- x[i] = transform.fill_values(temp)
693
-
694
- ## do more in the likelihood here with transformed information
695
-
696
- # setup transforms for x1
697
- parameter_transforms1 = {0: lambda x: np.log(x)}
698
-
699
- # setup transforms for x2
700
- parameter_transforms2 = {(1, 2): lambda x, y: (x**2, y**2)}
701
-
702
- # fill dict for x1
703
- fill_dict1 = {
704
- "ndim_full": 6, # full dimensionality after values are added
705
- "fill_inds": np.array([2, 3, 5]), # indexes for fill values in final array
706
- "fill_values": np.array([0.0, 1.0, -1.0]), # associated values for filling
707
- }
708
-
709
- # fill dict for x2
710
- fill_dict2 = {
711
- "ndim_full": 5, # full dimensionality after values are added
712
- "fill_inds": np.array([1]), # indexes for fill values in final array
713
- "fill_values": np.array([-1.0]), # associated values for filling
714
- }
715
-
716
- tcs = [
717
- TransformContainer(
718
- parameter_transforms=parameter_transforms1, fill_dict=fill_dict1
719
- ),
720
- TransformContainer(
721
- parameter_transforms=parameter_transforms2, fill_dict=fill_dict2
722
- ),
723
- ]
724
-
725
- num = 40
726
- x1 = np.random.uniform(0.1, 4.0, size=(num, 3))
727
- x2 = np.random.uniform(0.1, 4.0, size=(num, 4))
728
-
729
- group1 = np.arange(num)
730
- group2 = np.arange(num)
731
-
732
- # it can be added via args or kwargs in the ensemble sampler
733
- lnprob(x1, group1, x2, group2, tcs)
734
-
735
- # ### Periodic Container
736
-
737
- from eryn.utils import PeriodicContainer
738
-
739
- periodic = PeriodicContainer({"sine": {2: 2 * np.pi}})
740
- ntemps, nwalkers, nleaves_max, ndim = (10, 100, 2, 3)
741
-
742
- params_before_1 = {
743
- "sine": np.random.uniform(
744
- 0, 7.0, size=(ntemps * nwalkers, nleaves_max, ndim)
745
- )
746
- }
747
- params_before_2 = {
748
- "sine": np.random.uniform(
749
- 0, 7.0, size=(ntemps * nwalkers, nleaves_max, ndim)
750
- )
751
- }
752
-
753
- distance = periodic.distance(params_before_1, params_before_2)
754
-
755
- # the max distance should be near half the period
756
-
757
- params_after_1 = periodic.wrap(params_before_1)
758
-
759
- # max after wrapping should be near the period
760
-
761
- # ### Stopping & Update Functions
762
- from eryn.utils import SearchConvergeStopping
763
-
764
- ndim = 5
765
- nwalkers = 100
766
-
767
- # mean
768
- means = np.zeros(ndim) # np.random.rand(ndim)
769
-
770
- # define covariance matrix
771
- cov = np.diag(np.ones(ndim))
772
- invcov = np.linalg.inv(cov)
773
-
774
- # set prior limits
775
- lims = 50.0
776
- priors_in = {
777
- i: uniform_dist(-lims + means[i], lims + means[i]) for i in range(ndim)
778
- }
779
- priors = ProbDistContainer(priors_in)
780
-
781
- stop = SearchConvergeStopping(n_iters=5, diff=0.01, verbose=False)
782
-
783
- ensemble = EnsembleSampler(
784
- nwalkers,
785
- ndim,
786
- log_like_fn,
787
- priors,
788
- args=[means, invcov],
789
- stopping_fn=stop,
790
- stopping_iterations=5,
791
- )
792
-
793
- # starting positions
794
- # randomize throughout prior
795
- coords = priors.rvs(size=(nwalkers,))
796
-
797
- # check log_like
798
- log_like = np.asarray(
799
- [log_like_fn(coords[i], means, invcov) for i in range(nwalkers)]
800
- )
801
-
802
- # check log_prior
803
- log_prior = np.asarray([priors.logpdf(coords[i]) for i in range(nwalkers)])
804
-
805
- nsteps = 50
806
- # burn for 1000 steps
807
- burn = 10
808
- # thin by 5
809
- thin_by = 1
810
- out = ensemble.run_mcmc(
811
- coords, nsteps, burn=burn, progress=False, thin_by=thin_by
812
- )
813
-
814
- def test_group_stretch(self):
815
-
816
- from eryn.moves import GroupStretchMove
817
-
818
- class MeanGaussianGroupMove(GroupStretchMove):
819
- def __init__(self, **kwargs):
820
- # make sure kwargs get sent into group stretch parent class
821
- GroupStretchMove.__init__(self, **kwargs)
822
-
823
- def setup_friends(self, branches):
824
-
825
- # store cold-chain information
826
- friends = branches["gauss"].coords[0, branches["gauss"].inds[0]]
827
- means = friends[:, 1].copy() # need the copy
828
-
829
- # take unique to avoid errors at the start of sampling
830
- self.means, uni_inds = np.unique(means, return_index=True)
831
- self.friends = friends[uni_inds]
832
-
833
- # sort
834
- inds_sort = np.argsort(self.means)
835
- self.friends[:] = self.friends[inds_sort]
836
- self.means[:] = self.means[inds_sort]
837
-
838
- # get all current means from all temperatures
839
- current_means = branches["gauss"].coords[branches["gauss"].inds, 1]
840
-
841
- # calculate their distances to each stored friend
842
- dist = np.abs(current_means[:, None] - self.means[None, :])
843
-
844
- # get closest friends
845
- inds_closest = np.argsort(dist, axis=1)[:, : self.nfriends]
846
-
847
- # store in branch supplemental
848
- branches["gauss"].branch_supplemental[branches["gauss"].inds] = {
849
- "inds_closest": inds_closest
850
- }
851
-
852
- # make sure to "turn off" leaves that are deactivated by setting their
853
- # index to -1.
854
- branches["gauss"].branch_supplemental[~branches["gauss"].inds] = {
855
- "inds_closest": -np.ones(
856
- (ntemps, nwalkers, nleaves_max, self.nfriends), dtype=int
857
- )[~branches["gauss"].inds]
858
- }
859
-
860
- def fix_friends(self, branches):
861
- # when RJMCMC activates a new leaf, when it gets to this proposal, its inds_closest
862
- # will need to be updated
863
-
864
- # activated & does not have an assigned index
865
- fix = branches["gauss"].inds & (
866
- np.all(
867
- branches["gauss"].branch_supplemental[:]["inds_closest"] == -1,
868
- axis=-1,
869
- )
870
- )
871
-
872
- if not np.any(fix):
873
- return
874
-
875
- # same process as above, only for fix
876
- current_means = branches["gauss"].coords[fix, 1]
877
-
878
- dist = np.abs(current_means[:, None] - self.means[None, :])
879
- inds_closest = np.argsort(dist, axis=1)[:, : self.nfriends]
880
-
881
- branches["gauss"].branch_supplemental[fix] = {
882
- "inds_closest": inds_closest
883
- }
884
-
885
- # verify everything worked
886
- fix_check = branches["gauss"].inds & (
887
- np.all(
888
- branches["gauss"].branch_supplemental[:]["inds_closest"] == -1,
889
- axis=-1,
890
- )
891
- )
892
- assert not np.any(fix_check)
893
-
894
- def find_friends(self, name, s, s_inds=None, branch_supps=None):
895
-
896
- # prepare buffer array
897
- friends = np.zeros_like(s)
898
-
899
- # determine the closest friends for s_inds == True
900
- inds_closest_here = branch_supps[name][s_inds]["inds_closest"]
901
-
902
- # take one at random
903
- random_inds = inds_closest_here[
904
- np.arange(inds_closest_here.shape[0]),
905
- np.random.randint(
906
- self.nfriends, size=(inds_closest_here.shape[0],)
907
- ),
908
- ]
909
-
910
- # store in buffer array
911
- friends[s_inds] = self.friends[random_inds]
912
- return friends
913
-
914
- # set random seed
915
- np.random.seed(42)
916
-
917
- def gaussian_pulse(x, a, b, c):
918
- f_x = a * np.exp(-((x - b) ** 2) / (2 * c**2))
919
- return f_x
920
-
921
- def combine_gaussians(t, params):
922
- template = np.zeros_like(t)
923
- for param in params:
924
- template += gaussian_pulse(t, *param) # *params -> a, b, c
925
- return template
926
-
927
- def log_like_fn_gauss_pulse(params, t, data, sigma):
928
- template = combine_gaussians(t, params)
929
-
930
- ll = -0.5 * np.sum(((template - data) / sigma) ** 2, axis=-1)
931
- return ll
932
-
933
- nwalkers = 20
934
- ntemps = 8
935
- ndim = 3
936
- nleaves_max = 8
937
- nleaves_min = 0
938
-
939
- branch_names = ["gauss"]
940
-
941
- # define time stream
942
- num = 500
943
- t = np.linspace(-1, 1, num)
944
-
945
- gauss_inj_params = [
946
- [3.3, -0.2, 0.1],
947
- [2.6, -0.1, 0.1],
948
- [3.4, 0.0, 0.1],
949
- [2.9, 0.3, 0.1],
950
- ]
951
-
952
- # combine gaussians
953
- injection = combine_gaussians(t, np.asarray(gauss_inj_params))
954
-
955
- # set noise level
956
- sigma = 2.0
957
-
958
- # produce full data
959
- y = injection + sigma * np.random.randn(len(injection))
960
-
961
- coords = {"gauss": np.zeros((ntemps, nwalkers, nleaves_max, ndim))}
962
-
963
- # this is the sigma for the multivariate Gaussian that sets starting points
964
- # We need it to be very small to assume we are passed the search phase
965
- # we will verify this is with likelihood calculations
966
- sig1 = 0.0001
967
-
968
- # setup initial walkers to be the correct count (it will spread out)
969
- for nn in range(nleaves_max):
970
- if nn >= len(gauss_inj_params):
971
- # not going to add parameters for these unused leaves
972
- continue
973
-
974
- coords["gauss"][:, :, nn] = np.random.multivariate_normal(
975
- gauss_inj_params[nn],
976
- np.diag(np.ones(3) * sig1),
977
- size=(ntemps, nwalkers),
978
- )
979
-
980
- # make sure to start near the proper setup
981
- inds = {"gauss": np.zeros((ntemps, nwalkers, nleaves_max), dtype=bool)}
982
-
983
- # turn False -> True for any binary in the sampler
984
- inds["gauss"][:, :, : len(gauss_inj_params)] = True
985
-
986
- # describes priors for all leaves independently
987
- priors = {
988
- "gauss": {
989
- 0: uniform_dist(2.5, 3.5), # amplitude
990
- 1: uniform_dist(t.min(), t.max()), # mean
991
- 2: uniform_dist(0.01, 0.21), # sigma
992
- },
993
- }
994
-
995
- # for the Gaussian Move, will be explained later
996
- # factor = 0.00001
997
- # cov = {"gauss": np.diag(np.ones(ndim)) * factor}
998
-
999
- # moves = GaussianMove(cov)
1000
- nfriends = nwalkers
1001
- moves = MeanGaussianGroupMove(nfriends=nfriends)
1002
-
1003
- ensemble = EnsembleSampler(
1004
- nwalkers,
1005
- ndim,
1006
- log_like_fn_gauss_pulse,
1007
- priors,
1008
- args=[t, y, sigma],
1009
- tempering_kwargs=dict(ntemps=ntemps),
1010
- nbranches=len(branch_names),
1011
- branch_names=branch_names,
1012
- nleaves_max=nleaves_max,
1013
- nleaves_min=nleaves_min,
1014
- moves=moves,
1015
- rj_moves=True, # basic generation of new leaves from the prior
1016
- )
1017
-
1018
- log_prior = ensemble.compute_log_prior(coords, inds=inds)
1019
- log_like = ensemble.compute_log_like(coords, inds=inds, logp=log_prior)[0]
1020
-
1021
- # make sure it is reasonably close to the maximum which this is
1022
- # will not be zero due to noise
1023
-
1024
- # setup starting state
1025
- from eryn.state import BranchSupplemental
1026
-
1027
- branch_supps = {
1028
- "gauss": BranchSupplemental(
1029
- {
1030
- "inds_closest": np.zeros(
1031
- inds["gauss"].shape + (nfriends,), dtype=int
1032
- )
1033
- },
1034
- base_shape=(ntemps, nwalkers, nleaves_max),
1035
- )
1036
- }
1037
- state = State(
1038
- coords,
1039
- log_like=log_like,
1040
- log_prior=log_prior,
1041
- inds=inds,
1042
- branch_supplemental=branch_supps,
1043
- )
1044
-
1045
- nsteps = 2000
1046
- last_sample = ensemble.run_mcmc(
1047
- state, nsteps, burn=10, progress=False, thin_by=1
1048
- )
1049
-
1050
- nleaves = ensemble.get_nleaves()["gauss"][:, 0].flatten()
1051
-
1052
- def test_mt(self):
1053
- # Gaussian likelihood
1054
- def log_like_fn(x, mu, invcov):
1055
- diff = x - mu
1056
- return -0.5 * (diff * np.dot(invcov, diff.T).T).sum()
1057
-
1058
- ndim = 5
1059
- nwalkers = 100
1060
-
1061
- # mean
1062
- means = np.zeros(ndim) # np.random.rand(ndim)
1063
-
1064
- # define covariance matrix
1065
- cov = np.diag(np.ones(ndim))
1066
- invcov = np.linalg.inv(cov)
1067
-
1068
- # set prior limits
1069
- lims = 5.0
1070
- priors_in = {
1071
- i: uniform_dist(-lims + means[i], lims + means[i]) for i in range(ndim)
1072
- }
1073
- priors = ProbDistContainer(priors_in)
1074
-
1075
- nwalkers = 20
1076
- ntemps = 10
1077
- nleaves_max = 1
1078
-
1079
- from eryn.moves import MTDistGenMove
1080
-
1081
- mt_prior = MTDistGenMove(priors, num_try=25, independent=True)
1082
-
1083
- ensemble = EnsembleSampler(
1084
- nwalkers,
1085
- ndim,
1086
- log_like_fn,
1087
- priors,
1088
- args=[means, invcov],
1089
- moves=mt_prior,
1090
- tempering_kwargs={"ntemps": ntemps},
1091
- )
1092
-
1093
- # starting positions
1094
- # randomize throughout prior
1095
- coords = priors.rvs(size=(ntemps, nwalkers, 1))
1096
-
1097
- nsteps = 50
1098
- # burn for 1000 steps
1099
- burn = 10
1100
- # thin by 5
1101
- thin_by = 1
1102
-
1103
- out = ensemble.run_mcmc(
1104
- coords, nsteps, burn=burn, progress=False, thin_by=thin_by
1105
- )
1106
-
1107
- samples_out = ensemble.get_chain()["model_0"][:, 0].reshape(-1, ndim)
1108
-
1109
- def test_mt_rj(self):
1110
- def gaussian_pulse(x, a, b, c):
1111
- f_x = a * np.exp(-((x - b) ** 2) / (2 * c**2))
1112
- return f_x
1113
-
1114
- def combine_gaussians(t, params):
1115
- template = np.zeros_like(t)
1116
- for param in params:
1117
- template += gaussian_pulse(t, *param) # *params -> a, b, c
1118
- return template
1119
-
1120
- def log_like_fn_gauss_pulse(params, t, data, sigma):
1121
- template = combine_gaussians(t, params)
1122
-
1123
- ll = -0.5 * np.sum(((template - data) / sigma) ** 2, axis=-1)
1124
- return ll
1125
-
1126
- nwalkers = 20
1127
- ntemps = 8
1128
- ndim = 3
1129
- nleaves_max = 8
1130
- nleaves_min = 0
1131
-
1132
- branch_names = ["gauss"]
1133
-
1134
- # define time stream
1135
- num = 500
1136
- t = np.linspace(-1, 1, num)
1137
-
1138
- gauss_inj_params = [
1139
- [3.3, -0.2, 0.1],
1140
- [2.6, -0.1, 0.1],
1141
- [3.4, 0.0, 0.1],
1142
- [2.9, 0.3, 0.1],
1143
- ]
1144
-
1145
- # combine gaussians
1146
- injection = combine_gaussians(t, np.asarray(gauss_inj_params))
1147
-
1148
- # set noise level
1149
- sigma = 2.0
1150
-
1151
- # produce full data
1152
- y = injection + sigma * np.random.randn(len(injection))
1153
-
1154
- coords = {"gauss": np.zeros((ntemps, nwalkers, nleaves_max, ndim))}
1155
-
1156
- # this is the sigma for the multivariate Gaussian that sets starting points
1157
- # We need it to be very small to assume we are passed the search phase
1158
- # we will verify this is with likelihood calculations
1159
- sig1 = 0.0001
1160
-
1161
- # setup initial walkers to be the correct count (it will spread out)
1162
- for nn in range(nleaves_max):
1163
- if nn >= len(gauss_inj_params):
1164
- # not going to add parameters for these unused leaves
1165
- continue
1166
-
1167
- coords["gauss"][:, :, nn] = np.random.multivariate_normal(
1168
- gauss_inj_params[nn],
1169
- np.diag(np.ones(3) * sig1),
1170
- size=(ntemps, nwalkers),
1171
- )
1172
-
1173
- # make sure to start near the proper setup
1174
- inds = {"gauss": np.zeros((ntemps, nwalkers, nleaves_max), dtype=bool)}
1175
-
1176
- # turn False -> True for any binary in the sampler
1177
- inds["gauss"][:, :, : len(gauss_inj_params)] = True
1178
-
1179
- # describes priors for all leaves independently
1180
- priors = {
1181
- "gauss": ProbDistContainer(
1182
- {
1183
- 0: uniform_dist(2.5, 3.5), # amplitude
1184
- 1: uniform_dist(t.min(), t.max()), # mean
1185
- 2: uniform_dist(0.01, 0.21), # sigma
1186
- }
1187
- )
1188
- }
1189
-
1190
- # for the Gaussian Move, will be explained later
1191
- factor = 0.00001
1192
- cov = {"gauss": np.diag(np.ones(ndim)) * factor}
1193
-
1194
- moves = GaussianMove(cov)
1195
-
1196
- from eryn.moves import MTDistGenMoveRJ
1197
-
1198
- mt_rj_prior = MTDistGenMoveRJ(
1199
- priors,
1200
- nleaves_max={"gauss": nleaves_max},
1201
- nleaves_min={"gauss": nleaves_min},
1202
- num_try=25,
1203
- rj=True,
1204
- )
1205
-
1206
- ensemble = EnsembleSampler(
1207
- nwalkers,
1208
- ndim,
1209
- log_like_fn_gauss_pulse,
1210
- priors,
1211
- args=[t, y, sigma],
1212
- tempering_kwargs=dict(ntemps=ntemps),
1213
- nbranches=len(branch_names),
1214
- branch_names=branch_names,
1215
- nleaves_max=nleaves_max,
1216
- nleaves_min=nleaves_min,
1217
- moves=moves,
1218
- rj_moves=mt_rj_prior, # basic generation of new leaves from the prior
1219
- )
1220
-
1221
- log_prior = ensemble.compute_log_prior(coords, inds=inds)
1222
- log_like = ensemble.compute_log_like(coords, inds=inds, logp=log_prior)[0]
1223
-
1224
- # make sure it is reasonably close to the maximum which this is
1225
- # will not be zero due to noise
1226
-
1227
- # setup starting state
1228
- state = State(coords, log_like=log_like, log_prior=log_prior, inds=inds)
1229
-
1230
- nsteps = 20
1231
- last_sample = ensemble.run_mcmc(
1232
- state, nsteps, burn=10, progress=False, thin_by=1
1233
- )
1234
-
1235
- nleaves = ensemble.get_nleaves()["gauss"]
1236
- bns = (
1237
- np.arange(1, nleaves_max + 2) - 0.5
1238
- ) # Just to make it pretty and center the bins
1239
-
1240
- def test_2d_prior(self):
1241
- cov = np.array([[0.8, -0.2], [-0.2, 0.4]])
1242
- from scipy.stats import multivariate_normal
1243
-
1244
- priors_in = {(0, 1): multivariate_normal(cov=cov)}
1245
- priors = ProbDistContainer(priors_in)
1246
- prior_vals = priors.rvs(size=12)