def cov(self) -> NDArray:
        """Estimated covariance"""
        x = self._x
        nobs = x.shape[0]
        xpxi = inv(x.T @ x / nobs)

        eps = self.eps
        xe = x * eps
        if self._clusters.ndim == 1:
            xeex = cov_cluster(xe, self._clusters)
            if self._group_debias:
                xeex *= group_debias_coefficient(self._clusters)

        else:
            clusters0 = self._clusters[:, 0]
            clusters1 = self._clusters[:, 1]
            xeex0 = cov_cluster(xe, clusters0)
            xeex1 = cov_cluster(xe, clusters1)

            clusters01 = cluster_union(self._clusters)
            xeex01 = cov_cluster(xe, clusters01)

            if self._group_debias:
                xeex0 *= group_debias_coefficient(clusters0)
                xeex1 *= group_debias_coefficient(clusters1)
                xeex01 *= group_debias_coefficient(clusters01)

            xeex = xeex0 + xeex1 - xeex01

        xeex *= self._scale
        out = (xpxi @ xeex @ xpxi) / nobs
        return (out + out.T) / 2
    def _xeex(self) -> NDArray:
        if self._clusters.shape[1] == 0:
            # Heteroskedastic but not clustered
            return super()._xeex()
        elif self._clusters.shape[1] == 1:
            s = cov_cluster(self._moments, self._clusters[:, 0])
            if self._group_debias:
                s *= group_debias_coefficient(self._clusters[:, 0])
            return s

        else:
            xeex0 = cov_cluster(self._moments, self._clusters[:, 0])
            xeex1 = cov_cluster(self._moments, self._clusters[:, 1])

            clusters01 = cluster_union(self._clusters)
            xeex01 = cov_cluster(self._moments, clusters01)

            if self._group_debias:
                xeex0 *= group_debias_coefficient(self._clusters[:, 0])
                xeex1 *= group_debias_coefficient(self._clusters[:, 1])
                xeex01 *= group_debias_coefficient(clusters01)

            return xeex0 + xeex1 - xeex01