eryn 1.2.3__py3-none-any.whl → 1.2.5__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 +11 -2
- eryn/backends/hdfbackend.py +15 -0
- eryn/ensemble.py +18 -5
- eryn/moves/gaussian.py +6 -1
- eryn/prior.py +47 -2
- eryn/utils/periodic.py +19 -3
- eryn/utils/transform.py +52 -39
- eryn/utils/utility.py +4 -3
- {eryn-1.2.3.dist-info → eryn-1.2.5.dist-info}/METADATA +1 -1
- {eryn-1.2.3.dist-info → eryn-1.2.5.dist-info}/RECORD +11 -13
- {eryn-1.2.3.dist-info → eryn-1.2.5.dist-info}/WHEEL +1 -1
- eryn/tests/__init__.py +0 -0
- eryn/tests/test_eryn.py +0 -1246
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)
|