예제 #1
0
    def _normal_lml(self):
        self._update()

        m = self.m()
        ttau = self._sitelik_tau
        teta = self._sitelik_eta

        # NEW PHENOTYPE
        y = teta.copy()

        # NEW MEAN
        m = ttau * m

        # NEW COVARIANCE
        K = self.K()
        K = ddot(ttau, ddot(K, ttau, left=False), left=True)
        sum2diag(K, ttau, out=K)
        (Q, S0) = economic_qs(K)
        Q0, Q1 = Q

        from ...lmm import FastLMM
        from numpy import newaxis

        fastlmm = FastLMM(y, Q0, Q1, S0, covariates=m[:, newaxis])
        fastlmm.learn(progress=False)
        return fastlmm.lml()
예제 #2
0
    def lml_derivative_over_cov(self, dQS):
        from numpy_sugar.linalg import cho_solve, ddot, dotd

        self._update()

        L = self._posterior.L()
        Q = self._posterior.cov["QS"][0][0]
        ttau = self._site.tau
        teta = self._site.eta

        diff = teta - ttau * self._posterior.mean

        v0 = dot(dQS[0][0], dQS[1] * dot(dQS[0][0].T, diff))
        v1 = ttau * dot(Q, cho_solve(L, dot(Q.T, diff)))
        dlml = 0.5 * dot(diff, v0)
        dlml -= dot(v0, v1)
        dlml += 0.5 * dot(v1, dot(dQS[0][0], dQS[1] * dot(dQS[0][0].T, v1)))
        dqs = ddot(dQS[1], dQS[0][0].T, left=True)
        diag = dotd(dQS[0][0], dqs)
        dlml -= 0.5 * sum(ttau * diag)

        tmp = cho_solve(L, dot(ddot(Q.T, ttau, left=False), dQS[0][0]))
        dlml += 0.5 * sum(ttau * dotd(Q, dot(tmp, dqs)))

        return dlml
예제 #3
0
    def _gradient_over_v(self):
        self._update()

        A = self._A()
        Q = self._Q
        S = self._S
        C = self._C()
        m = self.m()
        delta = self.delta
        v = self.v
        teta = self._sitelik_eta

        AQ = ddot(A, Q, left=True)
        SQt = ddot(S, Q.T, left=True)

        Am = A * m
        Em = Am - A * self._QBiQtAm()

        Cteta = C * teta
        Eu = Cteta - A * self._QBiQtCteta()

        u = Em - Eu

        uBiQtAK0, uBiQtAK1 = self._uBiQtAK()

        out = dot(u, self._Kdot(u))
        out /= v
        out -= (1 - delta) * trace2(AQ, SQt)
        out -= delta * A.sum()
        out += (1 - delta) * trace2(AQ, uBiQtAK0)
        out += delta * trace2(AQ, uBiQtAK1)
        out /= 2
        return out
예제 #4
0
    def _uBiQtAK(self):
        BiQt = self._BiQt()
        S = self._S
        Q = self._Q
        BiQtA = ddot(BiQt, self._A(), left=False)
        BiQtAQS = dot(BiQtA, Q)
        ddot(BiQtAQS, S, left=False, out=BiQtAQS)

        return dot(BiQtAQS, Q.T), BiQtA
예제 #5
0
    def _gradient_over_both(self):
        self._update()

        v = self.v
        delta = self.delta
        Q = self._Q
        S = self._S
        A = self._A()
        AQ = ddot(A, Q, left=True)
        SQt = ddot(S, Q.T, left=True)
        BiQt = self._BiQt()
        uBiQtAK0, uBiQtAK1 = self._uBiQtAK()

        C = self._C()
        m = self.m()
        teta = self._sitelik_eta
        Q = self._Q
        As = A.sum()

        Am = A * m
        Em = Am - A * self._QBiQtAm()

        Cteta = C * teta
        Eu = Cteta - A * self._QBiQtCteta()

        u = Em - Eu
        uKu = dot(u, self._Kdot(u))
        tr1 = trace2(AQ, uBiQtAK0)
        tr2 = trace2(AQ, uBiQtAK1)

        dv = uKu / v
        dv -= (1 - delta) * trace2(AQ, SQt)
        dv -= delta * As
        dv += (1 - delta) * tr1
        dv += delta * tr2
        dv /= 2

        dd = delta / (1 - delta)
        ddelta = -tr1
        ddelta -= dd * tr2
        ddelta += trace2(AQ, ddot(BiQt, A, left=False)) * (dd + 1)
        ddelta += (dd + 1) * dot(u, u)
        ddelta += trace2(AQ, SQt)
        ddelta -= As
        ddelta *= v
        ddelta -= uKu / (1 - delta)
        ddelta /= 2

        v = asarray([dv, ddelta])

        if not is_all_finite(v):
            raise ValueError("LML gradient should not be %s." % str(v))

        return v
예제 #6
0
    def QSQtATQLQtA(self):
        from numpy_sugar.linalg import ddot, dotd

        if self._QSQtATQLQtA_cache is not None:
            return self._QSQtATQLQtA_cache

        LQt = self.LQt()
        A = self.A
        Q = self._cov["QS"][0][0]
        LQtA = ddot(LQt, A)
        AQ = self.AQ()
        QS = self.QS()
        T = self._site.tau
        self._QSQtATQLQtA_cache = dotd(QS, dot(dot(ddot(AQ.T, T), Q), LQtA))
        return self._QSQtATQLQtA_cache
예제 #7
0
    def compute(self, covariates, X):
        A = self._A
        L = self._L
        Q = self._Q
        C = self._C

        AMs0 = ddot(A, covariates, left=True)
        dens0 = AMs0 - ddot(A, dot(Q, cho_solve(L, dot(Q.T, AMs0))), left=True)
        noms0 = dot(self._beta_nom, covariates)

        AMs1 = ddot(A, X, left=True)
        dens1 = AMs1 - ddot(A, dot(Q, cho_solve(L, dot(Q.T, AMs1))), left=True)
        noms1 = dot(self._beta_nom, X)

        row00 = sum(covariates * dens0, 0)
        row01 = sum(covariates * dens1, 0)
        row11 = sum(X * dens1, 0)

        betas0 = noms0 * row11
        betas0 -= noms1 * row01
        betas1 = -noms0 * row01
        betas1 += noms1 * row00

        denom = row00 * row11
        denom -= row01**2

        with errstate(divide='ignore', invalid='ignore'):
            betas0 /= denom
            betas1 /= denom

        betas0 = nan_to_num(betas0)
        betas1 = nan_to_num(betas1)

        ms = dot(covariates, betas0[newaxis, :])
        ms += X * betas1
        QBiQtCteta = self._QBiQtCteta
        teta = self._teta

        Am = ddot(A, ms, left=True)
        w4 = dot(C * teta, ms)
        w4 -= dot(QBiQtCteta, Am)
        QBiQtAm = dot(Q, cho_solve(L, dot(Q.T, Am)))
        w5 = -sum(Am * ms, 0)
        w5 += sum(Am * QBiQtAm, 0)
        w5 /= 2
        lmls = self._lml_const + w4 + w5

        return (lmls, betas1)
예제 #8
0
    def _LhD(self):
        """
        Implements Lₕ and D.

        Returns
        -------
        Lh : ndarray
            Uₕᵀ S₁⁻½ U₁ᵀ.
        D : ndarray
            (Sₕ ⊗ Sₓ + Iₕₓ)⁻¹.
        """
        from numpy_sugar.linalg import ddot

        self._init_svd()
        if self._cache["LhD"] is not None:
            return self._cache["LhD"]
        S1, U1 = self._C1.eigh()
        U1S1 = ddot(U1, 1 / sqrt(S1))
        Sh, Uh = eigh(U1S1.T @ self.C0.value() @ U1S1)
        self._cache["LhD"] = {
            "Lh": (U1S1 @ Uh).T,
            "D": 1 / (kron(Sh, self._Sx) + 1),
            "De": 1 / (kron(Sh, self._Sxe) + 1),
        }
        return self._cache["LhD"]
예제 #9
0
    def update(self):
        from numpy_sugar.linalg import ddot, dotd

        self._flush_cache()

        Q = self._cov["QS"][0][0]

        K = dot(self.QS(), Q.T)

        BiQt = self.LQt()
        TK = ddot(self._site.tau, K, left=True)
        BiQtTK = dot(BiQt, TK)

        self.tau[:] = K.diagonal()
        self.tau -= dotd(Q, BiQtTK)
        self.tau[:] = 1 / self.tau

        if not all(self.tau >= 0.0):
            raise RuntimeError("'tau' has to be non-negative.")

        self.eta[:] = dot(K, self._site.eta)
        self.eta[:] += self._mean
        self.eta[:] -= dot(Q, dot(BiQtTK, self._site.eta))
        self.eta[:] -= dot(Q, dot(BiQt, self._site.tau * self._mean))

        self.eta *= self.tau
예제 #10
0
파일: _lmm.py 프로젝트: mindis/glimix-core
    def beta_covariance(self):
        """
        Estimates the covariance-matrix of the optimal beta.

        Returns
        -------
        beta-covariance : ndarray
            (Xᵀ(s((1-𝛿)K + 𝛿I))⁻¹X)⁻¹.

        References
        ----------
        .. Rencher, A. C., & Schaalje, G. B. (2008). Linear models in statistics. John
           Wiley & Sons.
        """
        from numpy_sugar.linalg import ddot

        tX = self._X["tX"]
        Q = concatenate(self._QS[0], axis=1)
        S0 = self._QS[1]
        D = self.v0 * S0 + self.v1
        D = D.tolist() + [self.v1] * (len(self._y) - len(D))
        D = asarray(D)
        A = inv(tX.T @ (Q @ ddot(1 / D, Q.T @ tX)))
        VT = self._X["VT"]
        H = lstsq(VT, A, rcond=None)[0]
        return lstsq(VT, H.T, rcond=None)[0]
예제 #11
0
    def update(self):
        from numpy_sugar.linalg import ddot, dotd

        self._flush_cache()

        s = self._cov["scale"]
        d = self._cov["delta"]
        Q = self._cov["QS"][0][0]

        A = self.A
        LQt = self.LQt()

        T = self._site.tau
        E = self._site.eta

        AQ = self.AQ()
        QS = self.QS()

        LQtA = ddot(LQt, A)
        D = self.QSQtATQLQtA()

        self.tau[:] = s * (1 - d) * dotd(QS, AQ.T)
        self.tau -= s * (1 - d) * D * (1 - d)
        self.tau += s * d * A
        self.tau -= s * d * dotd(self.ATQ(), LQtA) * (1 - d)
        self.tau **= -1

        v = s * (1 - d) * dot(Q, dot(QS.T, E)) + s * d * E + self._mean

        self.eta[:] = A * v
        self.eta -= dot(AQ, dot(LQtA, T * v)) * (1 - d)
        self.eta *= self.tau
예제 #12
0
    def __init__(self, A=None, USVt=None):
        from numpy_sugar.linalg import ddot, economic_svd

        if A is None and USVt is None:
            raise ValueError("Both `A` and `USVt` cannot be `None`.")

        if A is None:
            self._US = ddot(USVt[0], USVt[1])
            self._Vt = USVt[2]
            self._A = self._US @ self._Vt
        else:
            USVt = economic_svd(A)
            self._US = ddot(USVt[0], USVt[1])
            self._Vt = USVt[2]
            self._A = A

        self._rank = len(USVt[1])
예제 #13
0
    def ATQ(self):
        from numpy_sugar.linalg import ddot

        if self._TAQ_cache is not None:
            return self._TAQ_cache

        self._TAQ_cache = ddot(self._site.tau, self.AQ())
        return self._TAQ_cache
예제 #14
0
 def _covariate_setup(self, M):
     self._M = M
     SVD = economic_svd(M)
     self._svd_U = SVD[0]
     self._svd_S12 = sqrt(SVD[1])
     self._svd_V = SVD[2]
     self._tM = ddot(self._svd_U, self._svd_S12, left=False)
     if self.__tbeta is not None:
         self.__tbeta = resize(self.__tbeta, self._tM.shape[1])
예제 #15
0
 def _optimal_tbeta_denom(self):
     L = self._L()
     Q = self._Q
     AM = ddot(self._A(), self._tM, left=True)
     QBiQtAM = dot(Q, cho_solve(L, dot(Q.T, AM)))
     v = dot(self._tM.T, AM) - dot(AM.T, QBiQtAM)
     if not is_all_finite(v):
         raise ValueError("tbeta_denom should not be %s." % str(v))
     return v
예제 #16
0
    def QS(self):
        from numpy_sugar.linalg import ddot

        if self._QS_cache is not None:
            return self._QS_cache

        Q = self._cov["QS"][0][0]
        S = self._cov["QS"][1]

        self._QS_cache = ddot(Q, S)
        return self._QS_cache
예제 #17
0
    def AQ(self):
        from numpy_sugar.linalg import ddot

        if self._AQ_cache is not None:
            return self._AQ_cache

        Q = self._cov["QS"][0][0]
        A = self.A

        self._AQ_cache = ddot(A, Q)
        return self._AQ_cache
예제 #18
0
    def _gradient_over_delta(self):
        self._update()

        v = self.v
        delta = self.delta
        Q = self._Q
        S = self._S

        A = self._A()
        C = self._C()
        m = self.m()
        teta = self._sitelik_eta

        Am = A * m
        Em = Am - A * self._QBiQtAm()

        Cteta = C * teta
        Eu = Cteta - A * self._QBiQtCteta()

        u = Em - Eu

        AQ = ddot(A, Q, left=True)
        SQt = ddot(S, Q.T, left=True)

        BiQt = self._BiQt()

        uBiQtAK0, uBiQtAK1 = self._uBiQtAK()

        out = -trace2(AQ, uBiQtAK0)
        out -= (delta / (1 - delta)) * trace2(AQ, uBiQtAK1)
        out += trace2(AQ, ddot(BiQt, A, left=False)) * \
            ((delta / (1 - delta)) + 1)
        out += (1 + delta / (1 - delta)) * dot(u, u)
        out += trace2(AQ, SQt) + (delta / (1 - delta)) * A.sum()
        out -= (1 + delta / (1 - delta)) * A.sum()

        out *= v

        out -= dot(u, self._Kdot(u)) / (1 - delta)

        return out / 2
예제 #19
0
    def Ge(self):
        """
        Result of US from the SVD decomposition G = USVᵀ.
        """

        from numpy_sugar.linalg import ddot
        from scipy.linalg import svd

        U, S, _ = svd(self._G, full_matrices=False, check_finite=False)
        if U.shape[1] < self._G.shape[1]:
            return ddot(U, S)
        return self._G
예제 #20
0
    def value(self):
        r"""Log of the marginal likelihood.

        Formally,

        .. math::

            - \frac{n}{2}\log{2\pi} - \frac{1}{2} \log{\left|
                v_0 \mathrm K + v_1 \mathrm I + \tilde{\Sigma} \right|}
                    - \frac{1}{2}
                    \left(\tilde{\boldsymbol\mu} -
                    \mathrm X\boldsymbol\beta\right)^{\intercal}
                    \left( v_0 \mathrm K + v_1 \mathrm I +
                    \tilde{\Sigma} \right)^{-1}
                    \left(\tilde{\boldsymbol\mu} -
                    \mathrm X\boldsymbol\beta\right)

        Returns
        -------
        float
            :math:`\log{p(\tilde{\boldsymbol\mu})}`
        """
        from numpy_sugar.linalg import ddot, sum2diag

        if self._cache["value"] is not None:
            return self._cache["value"]

        scale = exp(self.logscale)
        delta = 1 / (1 + exp(-self.logitdelta))

        v0 = scale * (1 - delta)
        v1 = scale * delta

        mu = self.eta / self.tau
        n = len(mu)
        if self._QS is None:
            K = zeros((n, n))
        else:
            Q0 = self._QS[0][0]
            S0 = self._QS[1]
            K = dot(ddot(Q0, S0), Q0.T)

        A = sum2diag(sum2diag(v0 * K, v1), 1 / self.tau)
        m = mu - self.mean()

        v = -n * log(2 * pi)
        v -= slogdet(A)[1]
        v -= dot(m, solve(A, m))

        self._cache["value"] = v / 2

        return self._cache["value"]
예제 #21
0
    def gradient(self):
        from numpy_sugar.linalg import ddot, sum2diag

        if self._cache["grad"] is not None:
            return self._cache["grad"]

        scale = exp(self.logscale)
        delta = 1 / (1 + exp(-self.logitdelta))

        v0 = scale * (1 - delta)
        v1 = scale * delta

        mu = self.eta / self.tau
        n = len(mu)
        if self._QS is None:
            K = zeros((n, n))
        else:
            Q0 = self._QS[0][0]
            S0 = self._QS[1]
            K = dot(ddot(Q0, S0), Q0.T)

        A = sum2diag(sum2diag(v0 * K, v1), 1 / self.tau)
        X = self._X

        m = mu - self.mean()
        g = dict()
        Aim = solve(A, m)

        g["beta"] = dot(m, solve(A, X))

        Kd0 = sum2diag((1 - delta) * K, delta)
        Kd1 = sum2diag(-scale * K, scale)

        g["scale"] = -trace(solve(A, Kd0))
        g["scale"] += dot(Aim, dot(Kd0, Aim))
        g["scale"] *= 1 / 2

        g["delta"] = -trace(solve(A, Kd1))
        g["delta"] += dot(Aim, dot(Kd1, Aim))
        g["delta"] *= 1 / 2

        ed = exp(-self.logitdelta)
        es = exp(self.logscale)

        grad = dict()
        grad["logitdelta"] = g["delta"] * (ed / (1 + ed)) / (1 + ed)
        grad["logscale"] = g["scale"] * es
        grad["beta"] = g["beta"]

        self._cache["grad"] = grad

        return self._cache["grad"]
예제 #22
0
파일: _glmm.py 프로젝트: mindis/glimix-core
    def covariance(self):
        r"""Covariance of the prior.

        Returns
        -------
        :class:`numpy.ndarray`
            :math:`v_0 \mathrm K + v_1 \mathrm I`.
        """
        from numpy_sugar.linalg import ddot, sum2diag

        Q0 = self._QS[0][0]
        S0 = self._QS[1]
        return sum2diag(dot(ddot(Q0, self.v0 * S0), Q0.T), self.v1)
예제 #23
0
    def get_normal_likelihood_trick(self):
        # Covariance: nK = K + \tilde\Sigma = K + 1/self._sitelik_tau
        # via (K + 1/self._sitelik_tau)^{-1} = A1 - A1QB1^-1QTA1
        # Mean: \mathbf m
        # New phenotype: \tilde\mu
        #
        # I.e.: \tilde\mu \sim N(\mathbf m, K + \tilde\Sigma)
        #
        #
        # We transform the above Normal in an equivalent but more robust
        # one: \tilde\y \sim N(\tilde\m, \tilde\nK + \Sigma^{-1})
        #
        # \tilde\y = \tilde\Sigma^{-1} \tilde\mu
        # \tilde\m = \tilde\Sigma^{-1} \tilde\m
        # \tilde\nK = \tilde\Sigma^{-1} \nK \tilde\Sigma^{-1}

        m = self.m()
        ttau = self._sitelik_tau
        teta = self._sitelik_eta

        # NEW PHENOTYPE
        y = teta.copy()

        # NEW MEAN
        m = ttau * m

        # NEW COVARIANCE
        K = self.K()
        K = ddot(ttau, ddot(K, ttau, left=False), left=True)
        sum2diag(K, ttau, out=K)
        (Q, S0) = economic_qs(K)
        Q0, Q1 = Q

        from ...lmm import FastLMM
        from numpy import newaxis

        fastlmm = FastLMM(y, Q0, Q1, S0, covariates=m[:, newaxis])
        fastlmm.learn(progress=False)
        return fastlmm.get_normal_likelihood_trick()
예제 #24
0
    def _L(self):
        r"""Returns the Cholesky factorization of :math:`\mathcal B`.

        .. math::

            \mathcal B = \mathrm Q^{\intercal}\mathcal A\mathrm Q
                (\sigma_b^2 \mathrm S)^{-1}
        """
        Q = self._Q
        A = self._A()
        B = dot(Q.T, ddot(A, Q, left=True))
        sum2diag(B, 1. / (self.sigma2_b * self._S), out=B)
        return cho_factor(B, lower=True)[0]
예제 #25
0
파일: _vardec.py 프로젝트: phue/limix
    def _fit_lmm_multi_trait(self, verbose):
        from numpy import sqrt, asarray
        from glimix_core.lmm import Kron2Sum
        from numpy_sugar.linalg import economic_qs, ddot

        X = asarray(self._M, float)
        QS = economic_qs(self._covariance[0]._K)
        G = ddot(QS[0][0], sqrt(QS[1]))
        lmm = Kron2Sum(self._y, self._mean.A, X, G, rank=1, restricted=True)
        lmm.fit(verbose=verbose)
        self._glmm = lmm
        self._covariance[0]._set_kron2sum(lmm)
        self._covariance[1]._set_kron2sum(lmm)
        self._mean.B = lmm.B
예제 #26
0
    def covariance(self):
        """
        Covariance of the prior.

        Returns
        -------
        covariance : ndarray
            v₀𝙺 + v₁𝙸.
        """
        from numpy_sugar.linalg import ddot, sum2diag

        Q0 = self._Q0
        S0 = self._S0
        return sum2diag(dot(ddot(Q0, self.v0 * S0), Q0.T), self.v1)
예제 #27
0
    def scan(self, M):
        """
        LML, fixed-effect sizes, and scale of the candidate set.

        Parameters
        ----------
        M : array_like
            Fixed-effects set.

        Returns
        -------
        lml : float
            Log of the marginal likelihood.
        effsizes0 : ndarray
            Covariates fixed-effect sizes.
        effsizes0_se : ndarray
            Covariates fixed-effect size standard errors.
        effsizes1 : ndarray
            Candidate set fixed-effect sizes.
        effsizes1_se : ndarray
            Candidate fixed-effect size standard errors.
        scale : ndarray
            Optimal scale.
        """
        from numpy_sugar.linalg import ddot
        from numpy_sugar import is_all_finite

        M = asarray(M, float)

        if M.shape[1] == 0:
            return {
                "lml": self.null_lml(),
                "effsizes0": self.null_beta,
                "effsizes0_se": self.null_beta_se,
                "effsizes1": empty((0)),
                "effsizes1_se": empty((0)),
                "scale": self.null_scale,
            }

        if not is_all_finite(M):
            raise ValueError("M parameter has non-finite elements.")

        MTQ = [dot(M.T, Q) for Q in self._QS[0] if Q.size > 0]
        yTBM = [dot(i, j.T) for (i, j) in zip(self._yTQDi, MTQ)]
        XTBM = [dot(i, j.T) for (i, j) in zip(self._XTQDi, MTQ)]
        D = self._D
        MTBM = [ddot(i, 1 / j) @ i.T for i, j in zip(MTQ, D) if j.min() > 0]

        return self._multicovariate_set(yTBM, XTBM, MTBM)
예제 #28
0
    def LU(self):
        r"""LU factor of :math:`\mathrm B`.

        .. math::

            \mathrm B = \mathrm Q^{\intercal}\tilde{\mathrm{T}}\mathrm Q
                + \mathrm{S}^{-1}
        """
        from numpy_sugar.linalg import ddot, sum2diag

        if self._LU_cache is not None:
            return self._LU_cache

        s = self._cov["scale"]
        d = self._cov["delta"]
        Q = self._cov["QS"][0][0]
        S = self._cov["QS"][1]

        ddot(self.A * self._site.tau, Q, left=True, out=self._NxR)
        B = dot(Q.T, self._NxR, out=self._RxR)
        B *= 1 - d
        sum2diag(B, 1.0 / S / s, out=B)
        self._LU_cache = lu_factor(B, overwrite_a=True, check_finite=False)
        return self._LU_cache
예제 #29
0
def _get_mvn_restricted(y, X, G):
    SVD = economic_svd(X)
    tX = ddot(SVD[0], SVD[1])

    def mvn_restricted(beta, v0, v1, y, X, K0):
        n = K0.shape[0]
        m = X @ beta
        K = v0 * K0 + v1 * eye(K0.shape[0])
        lml = st.multivariate_normal(m, K).logpdf(y)
        lml += slogdet(tX.T @ tX)[1] / 2 - slogdet(tX.T @ solve(K, tX))[1] / 2
        lml += n * log(2 * pi) / 2
        lml -= (n - tX.shape[1]) * log(2 * pi) / 2
        return lml

    return mvn_restricted
예제 #30
0
    def L(self):
        r"""Cholesky decomposition of :math:`\mathrm B`.

        .. math::

            \mathrm B = \mathrm Q^{\intercal}\tilde{\mathrm{T}}\mathrm Q
                + \mathrm{S}^{-1}
        """
        from numpy_sugar.linalg import ddot, sum2diag

        if self._L_cache is not None:
            return self._L_cache

        s = self._cov["scale"]
        d = self._cov["delta"]
        Q = self._cov["QS"][0][0]
        S = self._cov["QS"][1]

        ddot(self.A * self._site.tau, Q, left=True, out=self._NxR)
        B = dot(Q.T, self._NxR, out=self._RxR)
        B *= 1 - d
        sum2diag(B, 1.0 / S / s, out=B)
        self._L_cache = _cho_factor(B)
        return self._L_cache