import os
import timeit
from typing import List

import numpy as np
from numpy.random import RandomState
from numpy.testing import assert_allclose, assert_almost_equal
import pytest
from scipy.special import gamma

import arch.univariate.recursions_python as recpy

CYTHON_COVERAGE = os.environ.get("ARCH_CYTHON_COVERAGE", "0") in ("true", "1", "True")

try:
    import arch.univariate.recursions as rec_cython

    missing_extension = False
except ImportError:
    missing_extension = True

if missing_extension:
    rec = recpy
else:
    rec = rec_cython

try:
    import numba  # noqa

    missing_numba = False
except ImportError:
    missing_numba = True

pytestmark = pytest.mark.filterwarnings("ignore::arch.compat.numba.PerformanceWarning")


class Timer(object):
    def __init__(
        self,
        first,
        first_name,
        second,
        second_name,
        model_name,
        setup,
        repeat=5,
        number=10,
    ) -> None:
        self.first_code = first
        self.second_code = second
        self.setup = setup
        self.first_name = first_name
        self.second_name = second_name
        self.model_name = model_name
        self.repeat = repeat
        self.number = number
        self._run = False
        self.times: List[float] = []
        self._codes = [first, second]
        self.ratio = np.inf

    def display(self):
        if not self._run:
            self.time()
        self.ratio = self.times[0] / self.times[1]
        title = self.model_name + " timing"
        print("\n" + title)
        print("-" * len(title))
        print(self.first_name + ": " + "{:0.3f} ms".format(1000 * self.times[0]))
        print(self.second_name + ": " + "{:0.3f} ms".format(1000 * self.times[1]))
        if self.ratio < 1:
            print(
                "{0} is {1:0.1f}% faster".format(
                    self.first_name, 100 * (1 / self.ratio - 1)
                )
            )
        else:
            print(
                "{0} is {1:0.1f}% faster".format(
                    self.second_name, 100 * (self.ratio - 1)
                )
            )
        print(
            self.first_name
            + "/"
            + self.second_name
            + " Ratio: {:0.3f}\n".format(self.ratio)
        )

    def time(self):
        self.times = []
        for code in self._codes:
            timer = timeit.Timer(code, setup=self.setup)
            self.times.append(min(timer.repeat(self.repeat, self.number)))


class TestRecursions(object):
    @classmethod
    def setup_class(cls):
        cls.nobs = 1000
        cls.rng = RandomState(12345)
        cls.resids = cls.rng.standard_normal(cls.nobs)
        cls.sigma2 = np.zeros_like(cls.resids)
        var = cls.resids.var()
        var_bounds = np.array([var / 1000000.0, var * 1000000.0])
        cls.var_bounds = np.ones((cls.nobs, 2)) * var_bounds
        cls.backcast = 1.0
        cls.timer_setup = """
import numpy as np
import arch.univariate.recursions as rec
import arch.univariate.recursions_python as recpy

nobs = 10000
resids = np.random.standard_normal(nobs)
sigma2 = np.zeros_like(resids)
var = resids.var()
backcast = 1.0
var_bounds = np.array([var / 1000000.0, var * 1000000.0])
var_bounds = np.ones((nobs, 2)) * var_bounds
"""

    def test_garch(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast

        parameters = np.array([0.1, 0.4, 0.3, 0.2])
        fresids = resids ** 2.0
        sresids = np.sign(resids)

        recpy.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        sigma2_numba = sigma2.copy()
        recpy.garch_recursion_python(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        sigma2_python = sigma2.copy()
        rec.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert_almost_equal(sigma2_numba, sigma2)
        assert_almost_equal(sigma2_python, sigma2)

        parameters = np.array([0.1, -0.4, 0.3, 0.2])
        recpy.garch_recursion_python(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([0.1, 0.4, 3, 2])
        recpy.garch_recursion_python(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([0.1, 0.4, 0.3, 0.2])
        mod_fresids = fresids.copy()
        mod_fresids[:1] = np.inf
        recpy.garch_recursion_python(
            parameters,
            mod_fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])
        rec.garch_recursion(
            parameters,
            mod_fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

    def test_harch(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast

        parameters = np.array([0.1, 0.4, 0.3, 0.2])
        lags = np.array([1, 5, 22], dtype=np.int32)
        recpy.harch_recursion_python(
            parameters, resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        sigma2_python = sigma2.copy()
        recpy.harch_recursion(
            parameters, resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        sigma2_numba = sigma2.copy()
        rec.harch_recursion(
            parameters, resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        assert_almost_equal(sigma2_numba, sigma2)
        assert_almost_equal(sigma2_python, sigma2)

        parameters = np.array([-0.1, -0.4, 0.3, 0.2])
        recpy.harch_recursion_python(
            parameters, resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([0.1, 4e8, 3, 2])
        recpy.harch_recursion_python(
            parameters, resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([0.1, 4e8, 3, 2])
        mod_resids = resids.copy()
        mod_resids[:10] = np.inf
        recpy.harch_recursion_python(
            parameters, mod_resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])
        rec.harch_recursion(
            parameters, mod_resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

    def test_arch(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast

        parameters = np.array([0.1, 0.4, 0.3, 0.2])
        p = 3

        recpy.arch_recursion_python(
            parameters, resids, sigma2, p, nobs, backcast, self.var_bounds
        )
        sigma2_python = sigma2.copy()
        recpy.arch_recursion(
            parameters, resids, sigma2, p, nobs, backcast, self.var_bounds
        )
        sigma2_numba = sigma2.copy()
        rec.arch_recursion(
            parameters, resids, sigma2, p, nobs, backcast, self.var_bounds
        )
        assert_almost_equal(sigma2_numba, sigma2)
        assert_almost_equal(sigma2_python, sigma2)

        parameters = np.array([-0.1, -0.4, 0.3, 0.2])
        recpy.arch_recursion_python(
            parameters, resids, sigma2, p, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([0.1, 4e8, 3, 2])
        recpy.arch_recursion_python(
            parameters, resids, sigma2, p, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        mod_resids = resids.copy()
        mod_resids[:10] = np.inf
        recpy.arch_recursion_python(
            parameters, mod_resids, sigma2, p, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])
        rec.arch_recursion(
            parameters, mod_resids, sigma2, p, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

    def test_garch_power_1(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast

        parameters = np.array([0.1, 0.4, 0.3, 0.2])
        fresids = np.abs(resids) ** 1.0
        sresids = np.sign(resids)

        recpy.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        sigma2_python = sigma2.copy()
        rec.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert_almost_equal(sigma2_python, sigma2)

    def test_garch_direct(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast

        parameters = np.array([0.1, 0.4, 0.3, 0.2])
        fresids = np.abs(resids) ** 2.0
        sresids = np.sign(resids)

        for t in range(nobs):
            if t == 0:
                sigma2[t] = parameters.dot(
                    np.array([1.0, backcast, 0.5 * backcast, backcast])
                )
            else:
                var = np.array(
                    [
                        1.0,
                        resids[t - 1] ** 2.0,
                        resids[t - 1] ** 2.0 * (resids[t - 1] < 0),
                        sigma2[t - 1],
                    ]
                )
                sigma2[t] = parameters.dot(var)

        sigma2_python = sigma2.copy()
        rec.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert_almost_equal(sigma2_python, sigma2)

    def test_garch_no_q(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast

        parameters = np.array([0.1, 0.4, 0.3])
        fresids = resids ** 2.0
        sresids = np.sign(resids)

        recpy.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            0,
            nobs,
            backcast,
            self.var_bounds,
        )
        sigma2_python = sigma2.copy()
        rec.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            0,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert_almost_equal(sigma2_python, sigma2)

    def test_garch_no_p(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast

        parameters = np.array([0.1, 0.4, 0.3])
        fresids = resids ** 2.0
        sresids = np.sign(resids)

        recpy.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            0,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        sigma2_python = sigma2.copy()
        rec.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            0,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert_almost_equal(sigma2_python, sigma2)

    def test_garch_no_o(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast

        parameters = np.array([0.1, 0.4, 0.3, 0.2])
        fresids = resids ** 2.0
        sresids = np.sign(resids)

        recpy.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            0,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        sigma2_python = sigma2.copy()
        rec.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            0,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert_almost_equal(sigma2_python, sigma2)

    def test_garch_arch(self):
        backcast = self.backcast
        nobs, resids, sigma2 = self.nobs, self.resids, self.sigma2

        parameters = np.array([0.1, 0.4, 0.3, 0.2])
        fresids = resids ** 2.0
        sresids = np.sign(resids)

        rec.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            3,
            0,
            0,
            nobs,
            backcast,
            self.var_bounds,
        )
        sigma2_garch = sigma2.copy()
        rec.arch_recursion(
            parameters, resids, sigma2, 3, nobs, backcast, self.var_bounds
        )

        assert_almost_equal(sigma2_garch, sigma2)

    def test_bounds(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast

        parameters = np.array([1e100, 0.4, 0.3, 0.2])
        lags = np.array([1, 5, 22], dtype=np.int32)
        recpy.harch_recursion(
            parameters, resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        sigma2_python = sigma2.copy()
        rec.harch_recursion(
            parameters, resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        assert_almost_equal(sigma2_python, sigma2)
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([-1e100, 0.4, 0.3, 0.2])
        recpy.harch_recursion(
            parameters, resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        sigma2_python = sigma2.copy()
        rec.harch_recursion(
            parameters, resids, sigma2, lags, nobs, backcast, self.var_bounds
        )
        assert_almost_equal(sigma2_python, sigma2)
        assert_almost_equal(sigma2, self.var_bounds[:, 0])

        parameters = np.array([1e100, 0.4, 0.3, 0.2])
        fresids = resids ** 2.0
        sresids = np.sign(resids)

        recpy.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        sigma2_python = sigma2.copy()
        rec.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert_almost_equal(sigma2_python, sigma2)
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([-1e100, 0.4, 0.3, 0.2])
        recpy.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        sigma2_python = sigma2.copy()
        rec.garch_recursion(
            parameters,
            fresids,
            sresids,
            sigma2,
            1,
            1,
            1,
            nobs,
            backcast,
            self.var_bounds,
        )
        assert_almost_equal(sigma2_python, sigma2)
        assert_almost_equal(sigma2, self.var_bounds[:, 0])

        parameters = np.array([1e100, 0.4, 0.3, 0.2])
        recpy.arch_recursion(
            parameters, resids, sigma2, 3, nobs, backcast, self.var_bounds
        )
        sigma2_python = sigma2.copy()
        rec.arch_recursion(
            parameters, resids, sigma2, 3, nobs, backcast, self.var_bounds
        )
        assert_almost_equal(sigma2_python, sigma2)
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([-1e100, 0.4, 0.3, 0.2])
        recpy.arch_recursion(
            parameters, resids, sigma2, 3, nobs, backcast, self.var_bounds
        )
        sigma2_python = sigma2.copy()
        rec.arch_recursion(
            parameters, resids, sigma2, 3, nobs, backcast, self.var_bounds
        )
        assert_almost_equal(sigma2_python, sigma2)
        assert_almost_equal(sigma2, self.var_bounds[:, 0])

    def test_egarch(self):
        nobs = self.nobs
        parameters = np.array([0.0, 0.1, -0.1, 0.95])
        resids, sigma2 = self.resids, self.sigma2
        p = o = q = 1
        backcast = 0.0
        var_bounds = self.var_bounds
        lnsigma2 = np.empty_like(sigma2)
        std_resids = np.empty_like(sigma2)
        abs_std_resids = np.empty_like(sigma2)
        recpy.egarch_recursion(
            parameters,
            resids,
            sigma2,
            p,
            o,
            q,
            nobs,
            backcast,
            var_bounds,
            lnsigma2,
            std_resids,
            abs_std_resids,
        )
        sigma2_numba = sigma2.copy()
        recpy.egarch_recursion_python(
            parameters,
            resids,
            sigma2,
            p,
            o,
            q,
            nobs,
            backcast,
            var_bounds,
            lnsigma2,
            std_resids,
            abs_std_resids,
        )
        sigma2_python = sigma2.copy()
        rec.egarch_recursion(
            parameters,
            resids,
            sigma2,
            p,
            o,
            q,
            nobs,
            backcast,
            var_bounds,
            lnsigma2,
            std_resids,
            abs_std_resids,
        )
        assert_almost_equal(sigma2_numba, sigma2)
        assert_almost_equal(sigma2_python, sigma2)

        norm_const = np.sqrt(2 / np.pi)
        for t in range(nobs):
            lnsigma2[t] = parameters[0]
            if t == 0:
                lnsigma2[t] += parameters[3] * backcast
            else:
                stdresid = resids[t - 1] / np.sqrt(sigma2[t - 1])
                lnsigma2[t] += parameters[1] * (np.abs(stdresid) - norm_const)
                lnsigma2[t] += parameters[2] * stdresid
                lnsigma2[t] += parameters[3] * lnsigma2[t - 1]
            sigma2[t] = np.exp(lnsigma2[t])
        assert_almost_equal(sigma2_python, sigma2)

        parameters = np.array([-100.0, 0.1, -0.1, 0.95])
        recpy.egarch_recursion_python(
            parameters,
            resids,
            sigma2,
            p,
            o,
            q,
            nobs,
            backcast,
            var_bounds,
            lnsigma2,
            std_resids,
            abs_std_resids,
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([0.0, 0.1, -0.1, 9.5])
        recpy.egarch_recursion_python(
            parameters,
            resids,
            sigma2,
            p,
            o,
            q,
            nobs,
            backcast,
            var_bounds,
            lnsigma2,
            std_resids,
            abs_std_resids,
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([0.0, 0.1, -0.1, 0.95])
        mod_resids = resids.copy()
        mod_resids[:1] = np.inf
        recpy.egarch_recursion_python(
            parameters,
            resids,
            sigma2,
            p,
            o,
            q,
            nobs,
            backcast,
            var_bounds,
            lnsigma2,
            std_resids,
            abs_std_resids,
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

    def test_midas_hyperbolic(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast

        parameters = np.array([0.1, 0.8, 0])
        j = np.arange(1, 22 + 1)
        weights = gamma(j + 0.6) / (gamma(j + 1) * gamma(0.6))
        weights = weights / weights.sum()
        recpy.midas_recursion(
            parameters, weights, resids, sigma2, nobs, backcast, self.var_bounds
        )
        sigma2_numba = sigma2.copy()
        recpy.midas_recursion_python(
            parameters, weights, resids, sigma2, nobs, backcast, self.var_bounds
        )
        sigma2_python = sigma2.copy()
        rec.midas_recursion(
            parameters, weights, resids, sigma2, nobs, backcast, self.var_bounds
        )
        assert_almost_equal(sigma2_numba, sigma2)
        assert_almost_equal(sigma2_python, sigma2)

        mod_resids = resids.copy()
        mod_resids[:10] = np.inf
        recpy.midas_recursion_python(
            parameters, weights, mod_resids, sigma2, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([0.1, 10e10, 0])
        j = np.arange(1, 22 + 1)
        weights = gamma(j + 0.6) / (gamma(j + 1) * gamma(0.6))
        weights = weights / weights.sum()
        recpy.midas_recursion_python(
            parameters, weights, resids, sigma2, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])
        rec.midas_recursion(
            parameters, weights, resids, sigma2, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

        parameters = np.array([0.1, -0.4, 0])
        recpy.midas_recursion_python(
            parameters, weights, resids, sigma2, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])
        rec.midas_recursion(
            parameters, weights, resids, sigma2, nobs, backcast, self.var_bounds
        )
        assert np.all(sigma2 >= self.var_bounds[:, 0])
        assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])

    def test_figarch_recursion(self):
        nobs, resids = self.nobs, self.resids
        sigma2, backcast = self.sigma2, self.backcast
        parameters = np.array([1.0, 0.2, 0.4, 0.3])
        fresids = resids ** 2
        p = q = 1
        trunc_lag = 1000
        rec.figarch_recursion(
            parameters,
            fresids,
            sigma2,
            p,
            q,
            nobs,
            trunc_lag,
            backcast,
            self.var_bounds,
        )
        lam = rec.figarch_weights(parameters[1:], p, q, trunc_lag=trunc_lag)
        lam_rev = lam[::-1]
        omega_tilde = parameters[0] / (1 - parameters[-1])
        sigma2_direct = np.empty_like(sigma2)
        for t in range(nobs):
            backcasts = trunc_lag - t
            sigma2_direct[t] = omega_tilde
            if backcasts:
                sigma2_direct[t] += backcast * lam_rev[:backcasts].sum()
            if t:
                sigma2_direct[t] += np.sum(lam_rev[-t:] * fresids[max(0, t - 1000) : t])
        assert_almost_equal(sigma2_direct, sigma2)

        recpy.figarch_recursion(
            parameters,
            fresids,
            sigma2,
            p,
            q,
            nobs,
            trunc_lag,
            backcast,
            self.var_bounds,
        )
        sigma2_numba = sigma2.copy()
        recpy.figarch_recursion_python(
            parameters,
            fresids,
            sigma2,
            p,
            q,
            nobs,
            trunc_lag,
            backcast,
            self.var_bounds,
        )
        sigma2_python = sigma2.copy()
        rec.figarch_recursion(
            parameters,
            fresids,
            sigma2,
            p,
            q,
            nobs,
            trunc_lag,
            backcast,
            self.var_bounds,
        )
        assert_almost_equal(sigma2_numba, sigma2)
        assert_almost_equal(sigma2_python, sigma2)

    def test_figarch_weights(self):
        parameters = np.array([1.0, 0.4])
        lam = rec.figarch_weights(parameters[1:], 0, 0, trunc_lag=1000)
        lam_direct = np.empty_like(lam)
        lam_direct[0] = parameters[-1]
        for i in range(1, 1000):
            lam_direct[i] = (i - parameters[-1]) / (i + 1) * lam_direct[i - 1]
        assert_almost_equal(lam, lam_direct)

    @pytest.mark.skipif(
        missing_numba or missing_extension, reason="numba not installed"
    )
    def test_garch_performance(self):
        garch_setup = """
parameters = np.array([.1, .4, .3, .2])
fresids = resids ** 2.0
sresids = np.sign(resids)
        """

        garch_first = """
recpy.garch_recursion(parameters, fresids, sresids, sigma2, 1, 1, 1, nobs,
backcast, var_bounds)
        """
        garch_second = """
rec.garch_recursion(parameters, fresids, sresids, sigma2, 1, 1, 1, nobs, backcast,
var_bounds)
        """
        timer = Timer(
            garch_first,
            "Numba",
            garch_second,
            "Cython",
            "GARCH",
            self.timer_setup + garch_setup,
        )
        timer.display()
        assert timer.ratio < 10.0
        if not (missing_numba or CYTHON_COVERAGE):
            assert 0.1 < timer.ratio

    @pytest.mark.skipif(
        missing_numba or missing_extension, reason="numba not installed"
    )
    def test_harch_performance(self):
        harch_setup = """
parameters = np.array([.1, .4, .3, .2])
lags = np.array([1, 5, 22], dtype=np.int32)
        """

        harch_first = """
recpy.harch_recursion(parameters, resids, sigma2, lags, nobs, backcast,
var_bounds)
        """

        harch_second = """
rec.harch_recursion(parameters, resids, sigma2, lags, nobs, backcast, var_bounds)
        """

        timer = Timer(
            harch_first,
            "Numba",
            harch_second,
            "Cython",
            "HARCH",
            self.timer_setup + harch_setup,
        )
        timer.display()
        assert timer.ratio < 10.0
        if not (missing_numba or CYTHON_COVERAGE):
            assert 0.1 < timer.ratio

    @pytest.mark.skipif(
        missing_numba or missing_extension, reason="numba not installed"
    )
    def test_egarch_performance(self):
        egarch_setup = """
parameters = np.array([0.0, 0.1, -0.1, 0.95])
p = o = q = 1
backcast = 0.0
lnsigma2 = np.empty_like(sigma2)
std_resids = np.empty_like(sigma2)
abs_std_resids = np.empty_like(sigma2)
        """

        egarch_first = """
recpy.egarch_recursion(parameters, resids, sigma2, p, o, q, nobs, backcast,
var_bounds, lnsigma2, std_resids, abs_std_resids)
"""

        egarch_second = """
rec.egarch_recursion(parameters, resids, sigma2, p, o, q, nobs, backcast,
var_bounds, lnsigma2, std_resids, abs_std_resids)
"""
        timer = Timer(
            egarch_first,
            "Numba",
            egarch_second,
            "Cython",
            "EGARCH",
            self.timer_setup + egarch_setup,
        )
        timer.display()
        assert timer.ratio < 10.0
        if not (missing_numba or CYTHON_COVERAGE):
            assert 0.1 < timer.ratio

    @pytest.mark.skipif(
        missing_numba or missing_extension, reason="numba not installed"
    )
    def test_midas_performance(self):
        midas_setup = """
from scipy.special import gamma
parameters = np.array([.1, 0.8, 0])
j = np.arange(1,22+1)
weights = gamma(j+0.6) / (gamma(j+1) * gamma(0.6))
weights = weights / weights.sum()
"""

        midas_first = """
recpy.midas_recursion(parameters, weights, resids, sigma2, nobs, backcast, var_bounds)
                """
        midas_second = """
rec.midas_recursion(parameters, weights, resids, sigma2, nobs, backcast, var_bounds)
"""
        timer = Timer(
            midas_first,
            "Numba",
            midas_second,
            "Cython",
            "MIDAS",
            self.timer_setup + midas_setup,
        )
        timer.display()
        assert timer.ratio < 10.0
        if not (missing_numba or CYTHON_COVERAGE):
            assert 0.1 < timer.ratio

    @pytest.mark.skipif(
        missing_numba or missing_extension, reason="numba not installed"
    )
    def test_figarch_performance(self):
        midas_setup = """
p = q = 1
trunc_lag = 1000
parameters = np.array([1.0, 0.2, 0.2, 0.04])
fresids = resids ** 2.0
"""

        midas_first = """
recpy.figarch_recursion(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, var_bounds)
                """
        midas_second = """
rec.figarch_recursion(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, var_bounds)
"""
        timer = Timer(
            midas_first,
            "Numba",
            midas_second,
            "Cython",
            "FIGARCH",
            self.timer_setup + midas_setup,
        )
        timer.display()
        assert timer.ratio < 10.0
        if not (missing_numba or CYTHON_COVERAGE):
            assert 0.1 < timer.ratio

    def test_garch_aparch_equiv(self):
        parameters = np.array([0.1, 0.1, 0.8])
        fresids = self.resids ** 2
        sresids = np.sign(self.resids)
        sigma2 = np.empty(1000)
        p = q = 1
        o = 0
        recpy.garch_recursion_python(
            parameters,
            fresids,
            sresids,
            sigma2,
            p,
            o,
            q,
            self.nobs,
            self.backcast,
            self.var_bounds,
        )
        sigma2_garch = sigma2.copy()

        parameters = np.array([0.1, 0.1, 0.8, 2])
        sigma2[:] = np.nan
        sigma2_delta = np.empty_like(sigma2)
        recpy.aparch_recursion_python(
            parameters,
            self.resids,
            np.abs(self.resids),
            sigma2,
            sigma2_delta,
            p,
            o,
            q,
            self.nobs,
            self.backcast,
            self.var_bounds,
        )
        assert_allclose(sigma2_garch, sigma2, atol=1e-6)

        sigma2[:] = np.nan
        recpy.aparch_recursion(
            parameters,
            self.resids,
            np.abs(self.resids),
            sigma2,
            sigma2_delta,
            p,
            o,
            q,
            self.nobs,
            self.backcast,
            self.var_bounds,
        )
        assert_allclose(sigma2_garch, sigma2, atol=1e-6)

        sigma2[:] = np.nan
        rec.aparch_recursion(
            parameters,
            self.resids,
            np.abs(self.resids),
            sigma2,
            sigma2_delta,
            p,
            o,
            q,
            self.nobs,
            self.backcast,
            self.var_bounds,
        )
        assert_allclose(sigma2_garch, sigma2, atol=1e-6)

    def test_asym_aparch_smoke(self):
        sigma2 = np.empty(1000)
        p = o = q = 1
        parameters = np.array([0.1, 0.1, 0.1, 0.8, 1.3])
        sigma2[:] = np.nan
        sigma2_delta = np.empty_like(sigma2)
        recpy.aparch_recursion_python(
            parameters,
            self.resids,
            np.abs(self.resids),
            sigma2,
            sigma2_delta,
            p,
            o,
            q,
            self.nobs,
            self.backcast,
            self.var_bounds,
        )
        assert np.all(np.isfinite(sigma2))
        sigma2_py = sigma2.copy()
        sigma2[:] = np.nan
        recpy.aparch_recursion(
            parameters,
            self.resids,
            np.abs(self.resids),
            sigma2,
            sigma2_delta,
            p,
            o,
            q,
            self.nobs,
            self.backcast,
            self.var_bounds,
        )
        assert np.all(np.isfinite(sigma2))
        assert_allclose(sigma2_py, sigma2)

        sigma2[:] = np.nan
        rec.aparch_recursion(
            parameters,
            self.resids,
            np.abs(self.resids),
            sigma2,
            sigma2_delta,
            p,
            o,
            q,
            self.nobs,
            self.backcast,
            self.var_bounds,
        )
        assert np.all(np.isfinite(sigma2))
        assert_allclose(sigma2_py, sigma2)


def test_bounds_check():
    var_bounds = np.array([0.1, 10])
    assert_almost_equal(recpy.bounds_check_python(-1.0, var_bounds), 0.1)
    assert_almost_equal(
        recpy.bounds_check_python(20.0, var_bounds), 10 + np.log(20.0 / 10.0)
    )
    assert_almost_equal(recpy.bounds_check_python(np.inf, var_bounds), 1010.0)

[(34, 'pytest.mark.filterwarnings', 'pytest.mark.filterwarnings', (['"""ignore::arch.compat.numba.PerformanceWarning"""'], {}), False, 'import pytest\n'), (13, 'os.environ.get', 'os.environ.get', (['"""ARCH_CYTHON_COVERAGE"""', '"""0"""'], {}), False, 'import os\n'), (911, 'pytest.mark.skipif', 'pytest.mark.skipif', (['(missing_numba or missing_extension)'], {'reason': '"""numba not installed"""'}), False, 'import pytest\n'), (942, 'pytest.mark.skipif', 'pytest.mark.skipif', (['(missing_numba or missing_extension)'], {'reason': '"""numba not installed"""'}), False, 'import pytest\n'), (973, 'pytest.mark.skipif', 'pytest.mark.skipif', (['(missing_numba or missing_extension)'], {'reason': '"""numba not installed"""'}), False, 'import pytest\n'), (1008, 'pytest.mark.skipif', 'pytest.mark.skipif', (['(missing_numba or missing_extension)'], {'reason': '"""numba not installed"""'}), False, 'import pytest\n'), (1039, 'pytest.mark.skipif', 'pytest.mark.skipif', (['(missing_numba or missing_extension)'], {'reason': '"""numba not installed"""'}), False, 'import pytest\n'), (1197, 'numpy.array', 'np.array', (['[0.1, 10]'], {}), True, 'import numpy as np\n'), (101, 'numpy.random.RandomState', 'RandomState', (['(12345)'], {}), False, 'from numpy.random import RandomState\n'), (103, 'numpy.zeros_like', 'np.zeros_like', (['cls.resids'], {}), True, 'import numpy as np\n'), (105, 'numpy.array', 'np.array', (['[var / 1000000.0, var * 1000000.0]'], {}), True, 'import numpy as np\n'), (126, 'numpy.array', 'np.array', (['[0.1, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (128, 'numpy.sign', 'np.sign', (['resids'], {}), True, 'import numpy as np\n'), (130, 'arch.univariate.recursions_python.garch_recursion', 'recpy.garch_recursion', (['parameters', 'fresids', 'sresids', 'sigma2', '(1)', '(1)', '(1)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (143, 'arch.univariate.recursions_python.garch_recursion_python', 'recpy.garch_recursion_python', (['parameters', 'fresids', 'sresids', 'sigma2', '(1)', '(1)', '(1)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (168, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_numba', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (169, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (171, 'numpy.array', 'np.array', (['[0.1, -0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (172, 'arch.univariate.recursions_python.garch_recursion_python', 'recpy.garch_recursion_python', (['parameters', 'fresids', 'sresids', 'sigma2', '(1)', '(1)', '(1)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (184, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (185, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (187, 'numpy.array', 'np.array', (['[0.1, 0.4, 3, 2]'], {}), True, 'import numpy as np\n'), (188, 'arch.univariate.recursions_python.garch_recursion_python', 'recpy.garch_recursion_python', (['parameters', 'fresids', 'sresids', 'sigma2', '(1)', '(1)', '(1)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (200, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (201, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (203, 'numpy.array', 'np.array', (['[0.1, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (206, 'arch.univariate.recursions_python.garch_recursion_python', 'recpy.garch_recursion_python', (['parameters', 'mod_fresids', 'sresids', 'sigma2', '(1)', '(1)', '(1)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (218, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (219, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (232, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (233, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (239, 'numpy.array', 'np.array', (['[0.1, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (240, 'numpy.array', 'np.array', (['[1, 5, 22]'], {'dtype': 'np.int32'}), True, 'import numpy as np\n'), (241, 'arch.univariate.recursions_python.harch_recursion_python', 'recpy.harch_recursion_python', (['parameters', 'resids', 'sigma2', 'lags', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (245, 'arch.univariate.recursions_python.harch_recursion', 'recpy.harch_recursion', (['parameters', 'resids', 'sigma2', 'lags', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (252, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_numba', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (253, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (255, 'numpy.array', 'np.array', (['[-0.1, -0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (256, 'arch.univariate.recursions_python.harch_recursion_python', 'recpy.harch_recursion_python', (['parameters', 'resids', 'sigma2', 'lags', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (259, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (260, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (262, 'numpy.array', 'np.array', (['[0.1, 400000000.0, 3, 2]'], {}), True, 'import numpy as np\n'), (263, 'arch.univariate.recursions_python.harch_recursion_python', 'recpy.harch_recursion_python', (['parameters', 'resids', 'sigma2', 'lags', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (266, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (267, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (269, 'numpy.array', 'np.array', (['[0.1, 400000000.0, 3, 2]'], {}), True, 'import numpy as np\n'), (272, 'arch.univariate.recursions_python.harch_recursion_python', 'recpy.harch_recursion_python', (['parameters', 'mod_resids', 'sigma2', 'lags', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (275, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (276, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (280, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (281, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (287, 'numpy.array', 'np.array', (['[0.1, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (290, 'arch.univariate.recursions_python.arch_recursion_python', 'recpy.arch_recursion_python', (['parameters', 'resids', 'sigma2', 'p', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (294, 'arch.univariate.recursions_python.arch_recursion', 'recpy.arch_recursion', (['parameters', 'resids', 'sigma2', 'p', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (301, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_numba', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (302, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (304, 'numpy.array', 'np.array', (['[-0.1, -0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (305, 'arch.univariate.recursions_python.arch_recursion_python', 'recpy.arch_recursion_python', (['parameters', 'resids', 'sigma2', 'p', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (308, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (309, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (311, 'numpy.array', 'np.array', (['[0.1, 400000000.0, 3, 2]'], {}), True, 'import numpy as np\n'), (312, 'arch.univariate.recursions_python.arch_recursion_python', 'recpy.arch_recursion_python', (['parameters', 'resids', 'sigma2', 'p', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (315, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (316, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (320, 'arch.univariate.recursions_python.arch_recursion_python', 'recpy.arch_recursion_python', (['parameters', 'mod_resids', 'sigma2', 'p', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (323, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (324, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (328, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (329, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (335, 'numpy.array', 'np.array', (['[0.1, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (337, 'numpy.sign', 'np.sign', (['resids'], {}), True, 'import numpy as np\n'), (339, 'arch.univariate.recursions_python.garch_recursion', 'recpy.garch_recursion', (['parameters', 'fresids', 'sresids', 'sigma2', '(1)', '(1)', '(1)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (364, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (370, 'numpy.array', 'np.array', (['[0.1, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (372, 'numpy.sign', 'np.sign', (['resids'], {}), True, 'import numpy as np\n'), (403, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (409, 'numpy.array', 'np.array', (['[0.1, 0.4, 0.3]'], {}), True, 'import numpy as np\n'), (411, 'numpy.sign', 'np.sign', (['resids'], {}), True, 'import numpy as np\n'), (413, 'arch.univariate.recursions_python.garch_recursion', 'recpy.garch_recursion', (['parameters', 'fresids', 'sresids', 'sigma2', '(1)', '(1)', '(0)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (438, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (444, 'numpy.array', 'np.array', (['[0.1, 0.4, 0.3]'], {}), True, 'import numpy as np\n'), (446, 'numpy.sign', 'np.sign', (['resids'], {}), True, 'import numpy as np\n'), (448, 'arch.univariate.recursions_python.garch_recursion', 'recpy.garch_recursion', (['parameters', 'fresids', 'sresids', 'sigma2', '(0)', '(1)', '(1)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (473, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (479, 'numpy.array', 'np.array', (['[0.1, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (481, 'numpy.sign', 'np.sign', (['resids'], {}), True, 'import numpy as np\n'), (483, 'arch.univariate.recursions_python.garch_recursion', 'recpy.garch_recursion', (['parameters', 'fresids', 'sresids', 'sigma2', '(1)', '(0)', '(1)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (508, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (514, 'numpy.array', 'np.array', (['[0.1, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (516, 'numpy.sign', 'np.sign', (['resids'], {}), True, 'import numpy as np\n'), (535, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_garch', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (541, 'numpy.array', 'np.array', (['[1e+100, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (542, 'numpy.array', 'np.array', (['[1, 5, 22]'], {'dtype': 'np.int32'}), True, 'import numpy as np\n'), (543, 'arch.univariate.recursions_python.harch_recursion', 'recpy.harch_recursion', (['parameters', 'resids', 'sigma2', 'lags', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (550, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (551, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (552, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (554, 'numpy.array', 'np.array', (['[-1e+100, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (555, 'arch.univariate.recursions_python.harch_recursion', 'recpy.harch_recursion', (['parameters', 'resids', 'sigma2', 'lags', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (562, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (563, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2', 'self.var_bounds[:, (0)]'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (565, 'numpy.array', 'np.array', (['[1e+100, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (567, 'numpy.sign', 'np.sign', (['resids'], {}), True, 'import numpy as np\n'), (569, 'arch.univariate.recursions_python.garch_recursion', 'recpy.garch_recursion', (['parameters', 'fresids', 'sresids', 'sigma2', '(1)', '(1)', '(1)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (594, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (595, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (596, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (598, 'numpy.array', 'np.array', (['[-1e+100, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (599, 'arch.univariate.recursions_python.garch_recursion', 'recpy.garch_recursion', (['parameters', 'fresids', 'sresids', 'sigma2', '(1)', '(1)', '(1)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (624, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (625, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2', 'self.var_bounds[:, (0)]'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (627, 'numpy.array', 'np.array', (['[1e+100, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (628, 'arch.univariate.recursions_python.arch_recursion', 'recpy.arch_recursion', (['parameters', 'resids', 'sigma2', '(3)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (635, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (636, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (637, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (639, 'numpy.array', 'np.array', (['[-1e+100, 0.4, 0.3, 0.2]'], {}), True, 'import numpy as np\n'), (640, 'arch.univariate.recursions_python.arch_recursion', 'recpy.arch_recursion', (['parameters', 'resids', 'sigma2', '(3)', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (647, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (648, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2', 'self.var_bounds[:, (0)]'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (652, 'numpy.array', 'np.array', (['[0.0, 0.1, -0.1, 0.95]'], {}), True, 'import numpy as np\n'), (657, 'numpy.empty_like', 'np.empty_like', (['sigma2'], {}), True, 'import numpy as np\n'), (658, 'numpy.empty_like', 'np.empty_like', (['sigma2'], {}), True, 'import numpy as np\n'), (659, 'numpy.empty_like', 'np.empty_like', (['sigma2'], {}), True, 'import numpy as np\n'), (660, 'arch.univariate.recursions_python.egarch_recursion', 'recpy.egarch_recursion', (['parameters', 'resids', 'sigma2', 'p', 'o', 'q', 'nobs', 'backcast', 'var_bounds', 'lnsigma2', 'std_resids', 'abs_std_resids'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (675, 'arch.univariate.recursions_python.egarch_recursion_python', 'recpy.egarch_recursion_python', (['parameters', 'resids', 'sigma2', 'p', 'o', 'q', 'nobs', 'backcast', 'var_bounds', 'lnsigma2', 'std_resids', 'abs_std_resids'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (704, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_numba', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (705, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (707, 'numpy.sqrt', 'np.sqrt', (['(2 / np.pi)'], {}), True, 'import numpy as np\n'), (718, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (720, 'numpy.array', 'np.array', (['[-100.0, 0.1, -0.1, 0.95]'], {}), True, 'import numpy as np\n'), (721, 'arch.univariate.recursions_python.egarch_recursion_python', 'recpy.egarch_recursion_python', (['parameters', 'resids', 'sigma2', 'p', 'o', 'q', 'nobs', 'backcast', 'var_bounds', 'lnsigma2', 'std_resids', 'abs_std_resids'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (735, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (736, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (738, 'numpy.array', 'np.array', (['[0.0, 0.1, -0.1, 9.5]'], {}), True, 'import numpy as np\n'), (739, 'arch.univariate.recursions_python.egarch_recursion_python', 'recpy.egarch_recursion_python', (['parameters', 'resids', 'sigma2', 'p', 'o', 'q', 'nobs', 'backcast', 'var_bounds', 'lnsigma2', 'std_resids', 'abs_std_resids'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (753, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (754, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (756, 'numpy.array', 'np.array', (['[0.0, 0.1, -0.1, 0.95]'], {}), True, 'import numpy as np\n'), (759, 'arch.univariate.recursions_python.egarch_recursion_python', 'recpy.egarch_recursion_python', (['parameters', 'resids', 'sigma2', 'p', 'o', 'q', 'nobs', 'backcast', 'var_bounds', 'lnsigma2', 'std_resids', 'abs_std_resids'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (773, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (774, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (780, 'numpy.array', 'np.array', (['[0.1, 0.8, 0]'], {}), True, 'import numpy as np\n'), (781, 'numpy.arange', 'np.arange', (['(1)', '(22 + 1)'], {}), True, 'import numpy as np\n'), (784, 'arch.univariate.recursions_python.midas_recursion', 'recpy.midas_recursion', (['parameters', 'weights', 'resids', 'sigma2', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (788, 'arch.univariate.recursions_python.midas_recursion_python', 'recpy.midas_recursion_python', (['parameters', 'weights', 'resids', 'sigma2', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (795, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_numba', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (796, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (800, 'arch.univariate.recursions_python.midas_recursion_python', 'recpy.midas_recursion_python', (['parameters', 'weights', 'mod_resids', 'sigma2', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (803, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (804, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (806, 'numpy.array', 'np.array', (['[0.1, 100000000000.0, 0]'], {}), True, 'import numpy as np\n'), (807, 'numpy.arange', 'np.arange', (['(1)', '(22 + 1)'], {}), True, 'import numpy as np\n'), (810, 'arch.univariate.recursions_python.midas_recursion_python', 'recpy.midas_recursion_python', (['parameters', 'weights', 'resids', 'sigma2', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (813, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (814, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (818, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (819, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (821, 'numpy.array', 'np.array', (['[0.1, -0.4, 0]'], {}), True, 'import numpy as np\n'), (822, 'arch.univariate.recursions_python.midas_recursion_python', 'recpy.midas_recursion_python', (['parameters', 'weights', 'resids', 'sigma2', 'nobs', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (825, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (826, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (830, 'numpy.all', 'np.all', (['(sigma2 >= self.var_bounds[:, (0)])'], {}), True, 'import numpy as np\n'), (831, 'numpy.all', 'np.all', (['(sigma2 <= 2 * self.var_bounds[:, (1)])'], {}), True, 'import numpy as np\n'), (836, 'numpy.array', 'np.array', (['[1.0, 0.2, 0.4, 0.3]'], {}), True, 'import numpy as np\n'), (854, 'numpy.empty_like', 'np.empty_like', (['sigma2'], {}), True, 'import numpy as np\n'), (862, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_direct', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (864, 'arch.univariate.recursions_python.figarch_recursion', 'recpy.figarch_recursion', (['parameters', 'fresids', 'sigma2', 'p', 'q', 'nobs', 'trunc_lag', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (876, 'arch.univariate.recursions_python.figarch_recursion_python', 'recpy.figarch_recursion_python', (['parameters', 'fresids', 'sigma2', 'p', 'q', 'nobs', 'trunc_lag', 'backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (899, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_numba', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (900, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['sigma2_python', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (903, 'numpy.array', 'np.array', (['[1.0, 0.4]'], {}), True, 'import numpy as np\n'), (905, 'numpy.empty_like', 'np.empty_like', (['lam'], {}), True, 'import numpy as np\n'), (909, 'numpy.testing.assert_almost_equal', 'assert_almost_equal', (['lam', 'lam_direct'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (1070, 'numpy.array', 'np.array', (['[0.1, 0.1, 0.8]'], {}), True, 'import numpy as np\n'), (1072, 'numpy.sign', 'np.sign', (['self.resids'], {}), True, 'import numpy as np\n'), (1073, 'numpy.empty', 'np.empty', (['(1000)'], {}), True, 'import numpy as np\n'), (1076, 'arch.univariate.recursions_python.garch_recursion_python', 'recpy.garch_recursion_python', (['parameters', 'fresids', 'sresids', 'sigma2', 'p', 'o', 'q', 'self.nobs', 'self.backcast', 'self.var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (1090, 'numpy.array', 'np.array', (['[0.1, 0.1, 0.8, 2]'], {}), True, 'import numpy as np\n'), (1092, 'numpy.empty_like', 'np.empty_like', (['sigma2'], {}), True, 'import numpy as np\n'), (1106, 'numpy.testing.assert_allclose', 'assert_allclose', (['sigma2_garch', 'sigma2'], {'atol': '(1e-06)'}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (1122, 'numpy.testing.assert_allclose', 'assert_allclose', (['sigma2_garch', 'sigma2'], {'atol': '(1e-06)'}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (1138, 'numpy.testing.assert_allclose', 'assert_allclose', (['sigma2_garch', 'sigma2'], {'atol': '(1e-06)'}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (1141, 'numpy.empty', 'np.empty', (['(1000)'], {}), True, 'import numpy as np\n'), (1143, 'numpy.array', 'np.array', (['[0.1, 0.1, 0.1, 0.8, 1.3]'], {}), True, 'import numpy as np\n'), (1145, 'numpy.empty_like', 'np.empty_like', (['sigma2'], {}), True, 'import numpy as np\n'), (1176, 'numpy.testing.assert_allclose', 'assert_allclose', (['sigma2_py', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (1193, 'numpy.testing.assert_allclose', 'assert_allclose', (['sigma2_py', 'sigma2'], {}), False, 'from numpy.testing import assert_allclose, assert_almost_equal\n'), (1198, 'arch.univariate.recursions_python.bounds_check_python', 'recpy.bounds_check_python', (['(-1.0)', 'var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (1200, 'arch.univariate.recursions_python.bounds_check_python', 'recpy.bounds_check_python', (['(20.0)', 'var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (1202, 'arch.univariate.recursions_python.bounds_check_python', 'recpy.bounds_check_python', (['np.inf', 'var_bounds'], {}), True, 'import arch.univariate.recursions_python as recpy\n'), (93, 'timeit.Timer', 'timeit.Timer', (['code'], {'setup': 'self.setup'}), False, 'import timeit\n'), (106, 'numpy.ones', 'np.ones', (['(cls.nobs, 2)'], {}), True, 'import numpy as np\n'), (336, 'numpy.abs', 'np.abs', (['resids'], {}), True, 'import numpy as np\n'), (371, 'numpy.abs', 'np.abs', (['resids'], {}), True, 'import numpy as np\n'), (717, 'numpy.exp', 'np.exp', (['lnsigma2[t]'], {}), True, 'import numpy as np\n'), (782, 'scipy.special.gamma', 'gamma', (['(j + 0.6)'], {}), False, 'from scipy.special import gamma\n'), (808, 'scipy.special.gamma', 'gamma', (['(j + 0.6)'], {}), False, 'from scipy.special import gamma\n'), (1096, 'numpy.abs', 'np.abs', (['self.resids'], {}), True, 'import numpy as np\n'), (1112, 'numpy.abs', 'np.abs', (['self.resids'], {}), True, 'import numpy as np\n'), (1128, 'numpy.abs', 'np.abs', (['self.resids'], {}), True, 'import numpy as np\n'), (1149, 'numpy.abs', 'np.abs', (['self.resids'], {}), True, 'import numpy as np\n'), (1159, 'numpy.isfinite', 'np.isfinite', (['sigma2'], {}), True, 'import numpy as np\n'), (1165, 'numpy.abs', 'np.abs', (['self.resids'], {}), True, 'import numpy as np\n'), (1175, 'numpy.isfinite', 'np.isfinite', (['sigma2'], {}), True, 'import numpy as np\n'), (1182, 'numpy.abs', 'np.abs', (['self.resids'], {}), True, 'import numpy as np\n'), (1192, 'numpy.isfinite', 'np.isfinite', (['sigma2'], {}), True, 'import numpy as np\n'), (1200, 'numpy.log', 'np.log', (['(20.0 / 10.0)'], {}), True, 'import numpy as np\n'), (380, 'numpy.array', 'np.array', (['[1.0, resids[t - 1] ** 2.0, resids[t - 1] ** 2.0 * (resids[t - 1] < 0),\n    sigma2[t - 1]]'], {}), True, 'import numpy as np\n'), (782, 'scipy.special.gamma', 'gamma', (['(j + 1)'], {}), False, 'from scipy.special import gamma\n'), (782, 'scipy.special.gamma', 'gamma', (['(0.6)'], {}), False, 'from scipy.special import gamma\n'), (808, 'scipy.special.gamma', 'gamma', (['(j + 1)'], {}), False, 'from scipy.special import gamma\n'), (808, 'scipy.special.gamma', 'gamma', (['(0.6)'], {}), False, 'from scipy.special import gamma\n'), (377, 'numpy.array', 'np.array', (['[1.0, backcast, 0.5 * backcast, backcast]'], {}), True, 'import numpy as np\n'), (713, 'numpy.sqrt', 'np.sqrt', (['sigma2[t - 1]'], {}), True, 'import numpy as np\n'), (714, 'numpy.abs', 'np.abs', (['stdresid'], {}), True, 'import numpy as np\n')]