'Test for instantaneous causality as described in chapters 3.6.3 and
7.6.4 of [1]_.
Test H0: "No instantaneous causality between caused and causing"
against H1: "Instantaneous causality between caused and causing
exists".
Note that instantaneous causality is a symmetric relation
(i.e. if causing is "instantaneously causing" caused, then also caused
is "instantaneously causing" causing), thus the naming of the
parameters (which is chosen to be in accordance with
test_granger_causality()) may be misleading.
Parameters
causing :
If int or str, test whether the corresponding variable is causing
the variable(s) specified in caused.
If sequence of int or str, test whether the corresponding variables
are causing the variable(s) specified in caused.
signif : float between 0 and 1, default 5 %
Significance level for computing critical values for test,
defaulting to standard 0.05 level
verbose : bool
If True, print a table with the results.
Returns
results : dict
A dict holding the test\'s results. The dict\'s keys are:
* "statistic" : float
The claculated test statistic.
* "crit_value" : float
The critical value of the \Chi^2-distribution.
* "pvalue" : float
The p-value corresponding to the test statistic.
* "df" : float
The degrees of freedom of the \Chi^2-distribution.
* "conclusion" : str {"reject", "fail to reject"}
Whether H0 can be rejected or not.
* "signif" : float
Notes
This method is not returning the same result as JMulTi. This is because
the test is based on a VAR(k_ar) model in statsmodels (in accordance to
pp. 104, 320-321 in [1]_) whereas JMulTi seems to be using a
VAR(k_ar+1) model.
References
.. [1] Lutkepohl, H. 2005. *New Introduction to Multiple Time Series Analysis*. Springer.'

def test_inst_causality(self, causing, 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(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    ' + 'a    sequence    of    these    types).'))
    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]
    caused_ind = [i for i in range(self.neqs) if (i not in causing_ind)]
    caused = [self.names[c] for c in caused_ind]
    (k, t, p) = (self.neqs, self.nobs, self.k_ar)
    num_restr = (len(causing) * len(caused))
    sigma_u = self.sigma_u
    vech_sigma_u = util.vech(sigma_u)
    sig_mask = np.zeros(sigma_u.shape)
    sig_mask[(causing_ind, caused_ind)] = 1
    sig_mask[(caused_ind, causing_ind)] = 1
    vech_sig_mask = util.vech(sig_mask)
    inds = np.nonzero(vech_sig_mask)[0]
    C = np.zeros((num_restr, len(vech_sigma_u)), dtype=float)
    for row in range(num_restr):
        C[(row, inds[row])] = 1
    Cs = np.dot(C, vech_sigma_u)
    d = np.linalg.pinv(duplication_matrix(k))
    Cd = np.dot(C, d)
    middle = (L.inv(chain_dot(Cd, np.kron(sigma_u, sigma_u), Cd.T)) / 2)
    wald_statistic = (t * chain_dot(Cs.T, middle, Cs))
    df = num_restr
    dist = stats.chi2(df)
    pvalue = dist.sf(wald_statistic)
    crit_value = dist.ppf((1 - signif))
    return CausalityTestResults(causing, caused, wald_statistic, crit_value, pvalue, df, signif, test='inst', method='wald')
