'Test for Granger-causality.
The concept of Granger-causality is described in chapter 7.6.3 of [1]_.
Test |H0|: "The variables in `causing` do not Granger-cause those in
`caused`" against  |H1|: "`causing` is Granger-causal for
`caused`".
Parameters
caused : int or str or sequence of int or str
If int or str, test whether the variable specified via this index
(int) or name (str) is Granger-caused by the variable(s) specified
by `causing`.
If a sequence of int or str, test whether the corresponding
variables are Granger-caused by the variable(s) specified
by `causing`.
causing : int or str or sequence of int or str or `None`, default: `None`
If int or str, test whether the variable specified via this index
(int) or name (str) is Granger-causing the variable(s) specified by
`caused`.
If a sequence of int or str, test whether the corresponding
variables are Granger-causing the variable(s) specified by
`caused`.
If `None`, `causing` is assumed to be the complement of
`caused` (the remaining variables of the system).
signif : float, 0 < `signif` < 1, default 5 %
Significance level for computing critical values for test,
defaulting to standard 0.05 level.
Returns
results : :class:`statsmodels.tsa.vector_ar.hypothesis_test_results.CausalityTestResults`
References
.. [1] Lutkepohl, H. 2005. *New Introduction to Multiple Time Series Analysis*. Springer.
.. |H0| replace:: H\ :sub:`0`
.. |H1| replace:: H\ :sub:`1`'

def test_granger_causality(self, caused, causing=None, signif=0.05):

    if (not (0 < signif < 1)):
        raise ValueError('signif    has    to    be    between    0    and    1')
    allowed_types = (string_types, int)
    if isinstance(caused, allowed_types):
        caused = [caused]
    if (not all((isinstance(c, allowed_types) for c in caused))):
        raise TypeError('caused    has    to    be    of    type    string    or    int    (or    a    sequence    of    these    types).')
    caused = [(self.names[c] if (type(c) == int) else c) for c in caused]
    caused_ind = [get_index(self.names, c) for c in caused]
    if (causing is not None):
        if isinstance(causing, allowed_types):
            causing = [causing]
        if (not all((isinstance(c, allowed_types) for c in causing))):
            raise TypeError('causing    has    to    be    of    type    string    or    int    (or    a    sequence    of    these    types)    or    None.')
        causing = [(self.names[c] if (type(c) == int) else c) for c in causing]
        causing_ind = [get_index(self.names, c) for c in causing]
    if (causing is None):
        causing_ind = [i for i in range(self.neqs) if (i not in caused_ind)]
        causing = [self.names[c] for c in causing_ind]
    (y, k, t, p) = (self.y_all, self.neqs, (self.nobs - 1), (self.k_ar + 1))
    exog = _deterministic_to_exog(self.deterministic, self.seasons, nobs_tot=(self.nobs + self.k_ar), first_season=self.first_season, seasons_centered=True, exog=self.exog, exog_coint=self.exog_coint)
    var_results = VAR(y.T, exog).fit(maxlags=p, trend='nc')
    num_restr = ((len(causing) * len(caused)) * (p - 1))
    num_det_terms = _num_det_vars(self.deterministic, self.seasons)
    if (self.exog is not None):
        num_det_terms += self.exog.shape[1]
    if (self.exog_coint is not None):
        num_det_terms += self.exog_coint.shape[1]
    C = np.zeros((num_restr, ((k * num_det_terms) + ((k ** 2) * (p - 1)))), dtype=float)
    cols_det = (k * num_det_terms)
    row = 0
    for j in range((p - 1)):
        for ing_ind in causing_ind:
            for ed_ind in caused_ind:
                C[(row, (((cols_det + ed_ind) + (k * ing_ind)) + ((k ** 2) * j)))] = 1
                row += 1
    Ca = np.dot(C, vec(var_results.params[:(- k)].T))
    x_min_p_components = []
    if (exog is not None):
        x_min_p_components.append(exog[(- t):].T)
    x_min_p = np.zeros(((k * p), t))
    for i in range((p - 1)):
        x_min_p[(i * k):((i + 1) * k), :] = (y[:, ((p - 1) - i):((-1) - i)] - y[:, :(- p)])
    x_min_p[(- k):, :] = y[:, :(- p)]
    x_min_p_components.append(x_min_p)
    x_min_p = np.row_stack(x_min_p_components)
    x_x = np.dot(x_min_p, x_min_p.T)
    x_x_11 = inv(x_x)[:((k * (p - 1)) + num_det_terms), :((k * (p - 1)) + num_det_terms)]
    sigma_u = ((var_results.sigma_u * ((t - (k * p)) - num_det_terms)) / t)
    sig_alpha_min_p = (t * np.kron(x_x_11, sigma_u))
    middle = inv(chain_dot(C, sig_alpha_min_p, C.T))
    wald_statistic = (t * chain_dot(Ca.T, middle, Ca))
    f_statistic = (wald_statistic / num_restr)
    df = (num_restr, (k * var_results.df_resid))
    f_distribution = scipy.stats.f(*df)
    pvalue = f_distribution.sf(f_statistic)
    crit_value = f_distribution.ppf((1 - signif))
    return CausalityTestResults(causing, caused, f_statistic, crit_value, pvalue, df, signif, test='granger', method='f')
