def cov(self) -> NDArray: """Parameter covariance""" x, z = self._x, self._z k = len(x) nobs = x[0].shape[0] xpz = blocked_cross_prod(x, z, eye(k)) xpz /= nobs wi = inv(self._w) xpz_wi_zpx = xpz @ wi @ xpz.T omega = self._omega() xpz_wi_omega_wi_zpx = xpz @ wi @ omega @ wi @ xpz.T adj = self._adjustment() if self._constraints is None: xpz_wi_zpxi = inv(xpz_wi_zpx) cov = xpz_wi_zpxi @ xpz_wi_omega_wi_zpx @ xpz_wi_zpxi / nobs else: cons = self._constraints xpz_wi_zpx = cons.t.T @ xpz_wi_zpx @ cons.t xpz_wi_zpxi = inv(xpz_wi_zpx) xpz_wi_omega_wi_zpx = cons.t.T @ xpz_wi_omega_wi_zpx @ cons.t cov = (cons.t @ xpz_wi_zpxi @ xpz_wi_omega_wi_zpx @ xpz_wi_zpxi @ cons.t.T / nobs) cov = (cov + cov.T) / 2 return adj * cov
def test_blocked_outer_product(): nobs = 200 k = 3 x = [np.random.standard_normal((nobs, k)) for _ in range(k)] z = [np.random.standard_normal((nobs, k + 2)) for _ in range(k)] scale = np.linspace(1, 2, k) s = np.ones(k) * (scale[:, None] @ scale[None, :]) + np.diag(np.arange(1, k + 1)) actual = blocked_cross_prod(x, z, s) _x = [] _z = [] for i in range(k): xrow = [] zrow = [] for j in range(k): if i == j: xrow.append(x[i]) zrow.append(z[i]) else: xrow.append(np.zeros((nobs, k))) zrow.append(np.zeros((nobs, k + 2))) _x.append(np.concatenate(xrow, 1)) _z.append(np.concatenate(zrow, 1)) _x = np.concatenate(_x, 0) _z = np.concatenate(_z, 0) desired = _x.T @ np.kron(s, np.eye(nobs)) @ _z assert_allclose(actual, desired)