def logdet_gradient(self):
        """
        Implements ∂log|K| = Tr[K⁻¹∂K].

        It can be shown that::

            ∂log|K| = diag(D)ᵀdiag(L(∂K)Lᵀ) = diag(D)ᵀ(diag(Lₕ∂C₀Lₕᵀ)⊗diag(LₓGGᵀLₓᵀ)),

        when the derivative is over the parameters of C₀. Similarly,

            ∂log|K| = diag(D)ᵀdiag(L(∂K)Lᵀ) = diag(D)ᵀ(diag(Lₕ∂C₁Lₕᵀ)⊗diag(I)),

        over the parameters of C₁.

        Returns
        -------
        C0 : ndarray
            Derivative of C₀ over its parameters.
        C1 : ndarray
            Derivative of C₁ over its parameters.
        """
        from numpy_sugar.linalg import dotd

        self._init_svd()

        dC0 = self._C0.gradient()["Lu"]
        grad_C0 = zeros_like(self._C0.Lu)
        for i in range(self._C0.Lu.shape[0]):
            t = kron(dotd(self.Lh, dC0[..., i] @ self.Lh.T), self._diag_LxGGLxe)
            grad_C0[i] = (self._De * t).sum()

        dC1 = self._C1.gradient()["Lu"]
        grad_C1 = zeros_like(self._C1.Lu)
        p = self._Sxe.shape[0]
        np = self._G.shape[0] - p
        for i in range(self._C1.Lu.shape[0]):
            t = (dotd(self.Lh, dC1[..., i] @ self.Lh.T) * np).sum()
            t1 = kron(dotd(self.Lh, dC1[..., i] @ self.Lh.T), eye(p))
            t += (self._De * t1).sum()
            grad_C1[i] = t

        return {"C0.Lu": grad_C0, "C1.Lu": grad_C1}
def logdet_gradient(self):
        """
        Implements ∂log|K| = Tr[K⁻¹∂K].

        It can be shown that::

            ∂log|K| = diag(D)ᵀdiag(L(∂K)Lᵀ) = diag(D)ᵀ(diag(Lₕ∂C₀Lₕᵀ)⊗diag(LₓGGᵀLₓᵀ)),

        when the derivative is over the parameters of C₀. Similarly,

            ∂log|K| = diag(D)ᵀdiag(L(∂K)Lᵀ) = diag(D)ᵀ(diag(Lₕ∂C₁Lₕᵀ)⊗diag(I)),

        over the parameters of C₁.

        Returns
        -------
        C0 : ndarray
            Derivative of C₀ over its parameters.
        C1 : ndarray
            Derivative of C₁ over its parameters.
        """
        from numpy_sugar.linalg import dotd

        self._init_svd()

        dC0 = self._C0.gradient()["Lu"]
        grad_C0 = zeros_like(self._C0.Lu)
        for i in range(self._C0.Lu.shape[0]):
            t = kron(dotd(self.Lh, dC0[..., i] @ self.Lh.T), self._diag_LxGGLxe)
            grad_C0[i] = (self._De * t).sum()

        dC1 = self._C1.gradient()["Lu"]
        grad_C1 = zeros_like(self._C1.Lu)
        p = self._Sxe.shape[0]
        np = self._G.shape[0] - p
        for i in range(self._C1.Lu.shape[0]):
            t = (dotd(self.Lh, dC1[..., i] @ self.Lh.T) * np).sum()
            t1 = kron(dotd(self.Lh, dC1[..., i] @ self.Lh.T), eye(p))
            t += (self._De * t1).sum()
            grad_C1[i] = t

        return {"C0.Lu": grad_C0, "C1.Lu": grad_C1}
def logdet_gradient ( self ) : from numpy_sugar . linalg import dotd self . _init_svd ( ) dC0 = self . _C0 . gradient ( ) [ "Lu" ] grad_C0 = zeros_like ( self . _C0 . Lu ) for i in range ( self . _C0 . Lu . shape [ 0 ] ) : t = kron ( dotd ( self . Lh , dC0 [ ... , i ] @ self . Lh . T ) , self . _diag_LxGGLxe ) grad_C0 [ i ] = ( self . _De * t ) . sum ( ) dC1 = self . _C1 . gradient ( ) [ "Lu" ] grad_C1 = zeros_like ( self . _C1 . Lu ) p = self . _Sxe . shape [ 0 ] np = self . _G . shape [ 0 ] - p for i in range ( self . _C1 . Lu . shape [ 0 ] ) : t = ( dotd ( self . Lh , dC1 [ ... , i ] @ self . Lh . T ) * np ) . sum ( ) t1 = kron ( dotd ( self . Lh , dC1 [ ... , i ] @ self . Lh . T ) , eye ( p ) ) t += ( self . _De * t1 ) . sum ( ) grad_C1 [ i ] = t return { "C0.Lu" : grad_C0 , "C1.Lu" : grad_C1 }
Implements ∂log|K| = Tr[K⁻¹∂K].

        It can be shown that::

            ∂log|K| = diag(D)ᵀdiag(L(∂K)Lᵀ) = diag(D)ᵀ(diag(Lₕ∂C₀Lₕᵀ)⊗diag(LₓGGᵀLₓᵀ)),

        when the derivative is over the parameters of C₀. Similarly,

            ∂log|K| = diag(D)ᵀdiag(L(∂K)Lᵀ) = diag(D)ᵀ(diag(Lₕ∂C₁Lₕᵀ)⊗diag(I)),

        over the parameters of C₁.

        Returns
        -------
        C0 : ndarray
            Derivative of C₀ over its parameters.
        C1 : ndarray
            Derivative of C₁ over its parameters.
Implements ∂log|K| = Tr [ K⁻¹∂K ] .