Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions autofit/non_linear/search/mcmc/emcee/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def raw_samples_from(self, model, search_internal):

else:
discard = int(3.0 * np.max(auto_correlations.times))
thin = int(np.max(auto_correlations.times) / 2.0)
thin = max(1, int(np.max(auto_correlations.times) / 2.0))

parameters, log_posterior = ChainPosterior.from_sampler(
search_internal, label="Emcee"
Expand All @@ -311,12 +311,16 @@ def auto_correlations_from(self, search_internal=None):

times = search_internal.get_autocorr_time(tol=0)

previous_auto_correlation_times = emcee.autocorr.integrated_time(
x=search_internal.get_chain()[
: -self.auto_correlation_settings.check_size, :, :
],
tol=0,
)
previous_chain = search_internal.get_chain()[
: -self.auto_correlation_settings.check_size, :, :
]
if len(previous_chain) == 0:
self.logger.debug("Unable to compute previous auto correlation times.")
previous_auto_correlation_times = None
else:
previous_auto_correlation_times = emcee.autocorr.integrated_time(
x=previous_chain, tol=0,
)

return AutoCorrelations(
check_size=self.auto_correlation_settings.check_size,
Expand Down
2 changes: 1 addition & 1 deletion autofit/non_linear/search/mcmc/zeus/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ def raw_samples_from(self, model, search_internal):

else:
discard = int(3.0 * np.max(auto_correlations.times))
thin = int(np.max(auto_correlations.times) / 2.0)
thin = max(1, int(np.max(auto_correlations.times) / 2.0))

parameters, log_posterior = ChainPosterior.from_sampler(
search_internal, label="Zeus"
Expand Down
7 changes: 2 additions & 5 deletions test_autofit/non_linear/search/mcmc/test_emcee.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,13 @@ def test__log_posteriors_are_aligned_with_the_thinned_chain(monkeypatch):
noise_map=np.full(100, 1.0),
)

# Test mode 1 runs the real sampler for 10 steps with 20 walkers, so the
# auto-correlation `check_size` must be smaller than the chain for the
# auto-correlation calculation to have samples to work with.
# Test mode runs only 10 steps; keep the default check_size=100 to
# exercise unavailable previous autocorrelations on a real short chain.
search = af.Emcee(
name="emcee_log_prob_alignment",
unique_tag="log_prob_alignment_test",
auto_correlation_settings=af.AutoCorrelationsSettings(
check_for_convergence=False,
check_size=5,
required_length=2,
),
number_of_cores=1,
Expand Down Expand Up @@ -119,7 +117,6 @@ def test__update_computes_auto_correlations_once(monkeypatch):
unique_tag="auto_correlations_once_test",
auto_correlation_settings=af.AutoCorrelationsSettings(
check_for_convergence=False,
check_size=5,
required_length=2,
),
number_of_cores=1,
Expand Down
61 changes: 61 additions & 0 deletions test_autofit/non_linear/search/mcmc/test_short_chain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""Short chains keep aligned draws and never request a zero thinning step."""
from types import SimpleNamespace

import numpy as np
import pytest

import autofit as af
from autofit.non_linear.search.mcmc.auto_correlations import AutoCorrelations


@pytest.mark.parametrize("search_cls", [af.Emcee, af.Zeus])
@pytest.mark.parametrize("tau, thin", [(0.5, 1), (1.9, 1), (4.0, 2)])
def test_thinning_preserves_matching_draws(search_cls, tau, thin, monkeypatch):
monkeypatch.delenv("PYAUTO_TEST_MODE", raising=False)
chain = np.arange(60.0).reshape(30, 2, 1)
log_prob = -chain[..., 0] ** 2

def select(values, discard=0, thin=1, flat=False):
selected = values[discard + thin - 1::thin]
return selected.reshape((-1,) + values.shape[2:]) if flat else selected

sampler = SimpleNamespace(
get_chain=lambda **kw: select(chain, **kw),
get_log_prob=lambda **kw: select(log_prob, **kw),
ncall_total=60,
)
search = search_cls()
monkeypatch.setattr(search, "auto_correlations_from", lambda **_: AutoCorrelations(
times=np.array([tau]), previous_times=None,
check_size=100, required_length=50, change_threshold=0.01,
))
raw = search.raw_samples_from(af.Collection(x=af.GaussianPrior(mean=0, sigma=1)), sampler)
expected = chain[int(3 * tau) + thin - 1::thin].reshape(-1, 1)
np.testing.assert_array_equal(raw.parameters, expected)
np.testing.assert_array_equal(raw.log_posterior, -expected[:, 0] ** 2)


@pytest.mark.parametrize("length", [10, 100, 101])
def test_previous_autocorrelation_requires_a_nonempty_chain(length, monkeypatch):
import emcee

calls = []

def integrated_time(x, tol):
calls.append(x)
assert len(x) > 0
return np.array([2.0])

monkeypatch.setattr(emcee.autocorr, "integrated_time", integrated_time)
sampler = SimpleNamespace(
get_chain=lambda: np.ones((length, 4, 1)),
get_autocorr_time=lambda **_: np.array([3.0]),
)
result = af.Emcee().auto_correlations_from(sampler)
if length <= 100:
assert result.previous_times is None
assert calls == []
assert not result.check_if_converged(total_samples=length)
else:
np.testing.assert_array_equal(result.previous_times, [2.0])
assert calls[0].shape == (1, 4, 1)
6 changes: 2 additions & 4 deletions test_autofit/non_linear/search/mcmc/test_zeus.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,13 @@ def test__log_posteriors_are_aligned_with_the_thinned_chain(monkeypatch):
noise_map=np.full(100, 1.0),
)

# Test mode 1 runs the real sampler for 10 steps with 20 walkers, so the
# auto-correlation `check_size` must be smaller than the chain for the
# auto-correlation calculation to have samples to work with.
# Test mode runs only 10 steps; keep the default check_size=100 to
# exercise unavailable previous autocorrelations on a real short chain.
search = af.Zeus(
name="zeus_log_prob_alignment",
unique_tag="log_prob_alignment_test",
auto_correlation_settings=af.AutoCorrelationsSettings(
check_for_convergence=False,
check_size=5,
required_length=2,
),
number_of_cores=1,
Expand Down
Loading