# Path: emcee3/autocorr.py
# def integrated_time(x, low=10, high=None, step=1, c=10, full_output=False,
#                     axis=0, fast=False, quiet=False):
#     """Estimate the integrated autocorrelation time of a time series.
# 
#     This estimate uses the iterative procedure described on page 16 of `Sokal's
#     notes <http://www.stat.unc.edu/faculty/cji/Sokal.pdf>`_ to determine a
#     reasonable window size.
# 
#     Args:
#         x: The time series. If multidimensional, set the time axis using the
#             ``axis`` keyword argument and the function will be computed for
#             every other axis.
#         low (Optional[int]): The minimum window size to test. (default: ``10``)
#         high (Optional[int]): The maximum window size to test. (default:
#             ``x.shape[axis] / (2*c)``)
#         step (Optional[int]): The step size for the window search. (default:
#             ``1``)
#         c (Optional[float]): The minimum number of autocorrelation times
#             needed to trust the estimate. (default: ``10``)
#         full_output (Optional[bool]): Return the final window size as well as
#             the autocorrelation time. (default: ``False``)
#         axis (Optional[int]): The time axis of ``x``. Assumed to be the first
#             axis if not specified.
#         fast (Optional[bool]): If ``True``, only use the first ``2^n`` (for
#             the largest power) entries for efficiency. (default: False)
#         quiet (Optional[bool]): If ``True``, silence the ``AutocorrError``
#             that should occur if the chain is too short for a reliable
#             estimate and return ``None`` instead. (default: False)
# 
#     Returns:
#         float or array: An estimate of the integrated autocorrelation time of
#             the time series ``x`` computed along the axis ``axis``.
#         Optional[int]: The final window size that was used. Only returned if
#             ``full_output`` is ``True``.
# 
#     Raises
#         AutocorrError: If the autocorrelation time can't be reliably estimated
#             from the chain. This normally means that the chain is too short.
# 
#     """
#     size = 0.5 * x.shape[axis]
#     if c * low >= size:
#         raise AutocorrError("The chain is too short")
# 
#     # Compute the autocorrelation function.
#     f = function(x, axis=axis, fast=fast)
# 
#     # Check the dimensions of the array.
#     oned = len(f.shape) == 1
#     m = [slice(None), ] * len(f.shape)
# 
#     # Loop over proposed window sizes until convergence is reached.
#     if high is None:
#         high = int(0.5 * size)
#     tau = None
#     for M in np.arange(low, high, step).astype(int):
#         # Compute the autocorrelation time with the given window.
#         if oned:
#             # Special case 1D for simplicity.
#             tau = 1 + 2 * np.sum(f[1:M])
#         else:
#             # N-dimensional case.
#             m[axis] = slice(1, M)
#             tau = 1 + 2 * np.sum(f[m], axis=axis)
# 
#         # Accept the window size if it satisfies the convergence criterion.
#         if np.all(tau > 1.0) and M > c * tau.max():
#             if full_output:
#                 return tau, M
#             return tau
# 
#         # If the autocorrelation time is too long to be estimated reliably
#         # from the chain, it should fail.
#         if c * tau.max() >= size:
#             break
# 
#     msg = ("The chain is too short to reliably estimate the autocorrelation "
#            "time.")
#     if tau is not None:
#         msg += " Current estimate: \n{0}".format(tau)
#     if quiet:
#         logging.warn(msg)
#         return None
#     raise AutocorrError(msg)
# 
# class AutocorrError(Exception):
#     """Raised if the chain is too short to estimate an autocorrelation time.
# 
#     """
#     pass


import pytest
import numpy as np
from ...autocorr import integrated_time, AutocorrError


def get_chain(seed=1234, ndim=3, N=100000):
    np.random.seed(seed)
    a = 0.9
    x = np.empty((N, ndim))
    x[0] = np.zeros(ndim)
    for i in range(1, N):
        x[i] = x[i-1] * a + np.random.rand(ndim)
    return x


def test_1d(seed=1234, ndim=1, N=150000, c=6):
    x = get_chain(seed=seed, ndim=ndim, N=N)
    tau, M = integrated_time(x, c=c, full_output=True)
    assert np.all(M > c * tau)
    assert np.all(np.abs(tau - 19.0) / 19. < 0.2)


def test_nd(seed=1234, ndim=3, N=150000):
    x = get_chain(seed=seed, ndim=ndim, N=N)
    tau = integrated_time(x)
    assert np.all(np.abs(tau - 19.0) / 19. < 0.2)


def test_too_short(seed=1234, ndim=3, N=500):
    x = get_chain(seed=seed, ndim=ndim, N=N)
    with pytest.raises(AutocorrError):
        integrated_time(x)
    with pytest.raises(AutocorrError):

# Path: emcee3/autocorr.py
# def integrated_time(x, low=10, high=None, step=1, c=10, full_output=False,
#                     axis=0, fast=False, quiet=False):
#     """Estimate the integrated autocorrelation time of a time series.
# 
#     This estimate uses the iterative procedure described on page 16 of `Sokal's
#     notes <http://www.stat.unc.edu/faculty/cji/Sokal.pdf>`_ to determine a
#     reasonable window size.
# 
#     Args:
#         x: The time series. If multidimensional, set the time axis using the
#             ``axis`` keyword argument and the function will be computed for
#             every other axis.
#         low (Optional[int]): The minimum window size to test. (default: ``10``)
#         high (Optional[int]): The maximum window size to test. (default:
#             ``x.shape[axis] / (2*c)``)
#         step (Optional[int]): The step size for the window search. (default:
#             ``1``)
#         c (Optional[float]): The minimum number of autocorrelation times
#             needed to trust the estimate. (default: ``10``)
#         full_output (Optional[bool]): Return the final window size as well as
#             the autocorrelation time. (default: ``False``)
#         axis (Optional[int]): The time axis of ``x``. Assumed to be the first
#             axis if not specified.
#         fast (Optional[bool]): If ``True``, only use the first ``2^n`` (for
#             the largest power) entries for efficiency. (default: False)
#         quiet (Optional[bool]): If ``True``, silence the ``AutocorrError``
#             that should occur if the chain is too short for a reliable
#             estimate and return ``None`` instead. (default: False)
# 
#     Returns:
#         float or array: An estimate of the integrated autocorrelation time of
#             the time series ``x`` computed along the axis ``axis``.
#         Optional[int]: The final window size that was used. Only returned if
#             ``full_output`` is ``True``.
# 
#     Raises
#         AutocorrError: If the autocorrelation time can't be reliably estimated
#             from the chain. This normally means that the chain is too short.
# 
#     """
#     size = 0.5 * x.shape[axis]
#     if c * low >= size:
#         raise AutocorrError("The chain is too short")
# 
#     # Compute the autocorrelation function.
#     f = function(x, axis=axis, fast=fast)
# 
#     # Check the dimensions of the array.
#     oned = len(f.shape) == 1
#     m = [slice(None), ] * len(f.shape)
# 
#     # Loop over proposed window sizes until convergence is reached.
#     if high is None:
#         high = int(0.5 * size)
#     tau = None
#     for M in np.arange(low, high, step).astype(int):
#         # Compute the autocorrelation time with the given window.
#         if oned:
#             # Special case 1D for simplicity.
#             tau = 1 + 2 * np.sum(f[1:M])
#         else:
#             # N-dimensional case.
#             m[axis] = slice(1, M)
#             tau = 1 + 2 * np.sum(f[m], axis=axis)
# 
#         # Accept the window size if it satisfies the convergence criterion.
#         if np.all(tau > 1.0) and M > c * tau.max():
#             if full_output:
#                 return tau, M
#             return tau
# 
#         # If the autocorrelation time is too long to be estimated reliably
#         # from the chain, it should fail.
#         if c * tau.max() >= size:
#             break
# 
#     msg = ("The chain is too short to reliably estimate the autocorrelation "
#            "time.")
#     if tau is not None:
#         msg += " Current estimate: \n{0}".format(tau)
#     if quiet:
#         logging.warn(msg)
#         return None
#     raise AutocorrError(msg)
# 
# class AutocorrError(Exception):
#     """Raised if the chain is too short to estimate an autocorrelation time.
# 
#     """
#     pass


# Path: emcee3/tests/unit/test_autocorr.py
import pytest
import numpy as np
from ...autocorr import integrated_time, AutocorrError



def get_chain(seed=1234, ndim=3, N=100000):
    np.random.seed(seed)
    a = 0.9
    x = np.empty((N, ndim))
    x[0] = np.zeros(ndim)
    for i in range(1, N):
        x[i] = x[i-1] * a + np.random.rand(ndim)
    return x


def test_1d(seed=1234, ndim=1, N=150000, c=6):
    x = get_chain(seed=seed, ndim=ndim, N=N)
    tau, M = integrated_time(x, c=c, full_output=True)
    assert np.all(M > c * tau)
    assert np.all(np.abs(tau - 19.0) / 19. < 0.2)


def test_nd(seed=1234, ndim=3, N=150000):
    x = get_chain(seed=seed, ndim=ndim, N=N)
    tau = integrated_time(x)
    assert np.all(np.abs(tau - 19.0) / 19. < 0.2)


def test_too_short(seed=1234, ndim=3, N=500):
    x = get_chain(seed=seed, ndim=ndim, N=N)
    with pytest.raises(AutocorrError):
        integrated_time(x)
    with pytest.raises(AutocorrError):

        integrated_time(x, low=100)