'Test for Granger-causality as described in chapter 7.6.3 of [1]_.
Test H0: "`causing` does not Granger-cause the remaining variables of
the system" against  H1: "`causing` is Granger-causal for the
remaining variables".
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`.
kind : {\'f\', \'wald\'}
Perform F-test or Wald (chi-sq) test
signif : float, default 5%
Significance level for computing critical values for test,
defaulting to standard 0.05 level
Notes
Null hypothesis is that there is no Granger-causality for the indicated
variables. The degrees of freedom in the F-test are based on the
number of variables in the VAR system, that is, degrees of freedom
are equal to the number of equations in the VAR times degree of freedom
of a single equation.
Returns
results : CausalityTestResults
References
.. [1] Lutkepohl, H. 2005. *New Introduction to Multiple Time Series Analysis*. Springer.'

def test_causality(self, caused, causing=None, kind='f', 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 = [util.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 = [util.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 caused_ind]
    (k, p) = (self.neqs, self.k_ar)
    num_restr = ((len(causing) * len(caused)) * p)
    num_det_terms = self.k_trend
    C = np.zeros((num_restr, ((k * num_det_terms) + ((k ** 2) * p))), dtype=float)
    cols_det = (k * num_det_terms)
    row = 0
    for j in range(p):
        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
    Cb = np.dot(C, vec(self.params.T))
    middle = L.inv(chain_dot(C, self.cov_params, C.T))
    lam_wald = statistic = chain_dot(Cb, middle, Cb)
    if (kind.lower() == 'wald'):
        df = num_restr
        dist = stats.chi2(df)
    elif (kind.lower() == 'f'):
        statistic = (lam_wald / num_restr)
        df = (num_restr, (k * self.df_resid))
        dist = stats.f(*df)
    else:
        raise Exception(('kind    %s    not    recognized' % kind))
    pvalue = dist.sf(statistic)
    crit_value = dist.ppf((1 - signif))
    return CausalityTestResults(causing, caused, statistic, crit_value, pvalue, df, signif, test='granger', method=kind)
