neuroprob/GP/linalg.py
def p_F_U(out_dims, X, X_u, kernel, f_loc, f_scale_tril=None, Lff=None, cov_type='diagonal',
        whiten=False, jitter=1e-6):
    r"""
    Single kernel parameter set shared over all output dimensions.

    :param int out_dims: number of output dimensions
    :param torch.Tensor X: Input data to evaluate the posterior over
    :param torch.Tensor X_u: Input data to conditioned on, inducing points in sparse GP
    :param GP.kernels.Kernel kernel: A kernel module object
    :param torch.Tensor f_loc: Mean of :math:`q(f)`. In case ``f_scale_tril=None``,
        :math:`f_{loc} = f`
    :param torch.Tensor f_scale_tril: Lower triangular decomposition of covariance
        matrix of :math:`q(f)`'s
    :param torch.Tensor Lff: Lower triangular decomposition of :math:`kernel(X, X)`
        (optional)
    :param string cov_type: A flag to decide what form of covariance to compute
    :param bool whiten: A flag to tell if ``f_loc`` and ``f_scale_tril`` are
        already transformed by the inverse of ``Lff``
    :param float jitter: A small positive term which is added into the diagonal part of
        a covariance matrix to help stablize its Cholesky decomposition
    :returns: loc and covariance matrix (or variance) of :math:`p(f^*(X_{new}))`
    :rtype: tuple(torch.Tensor, torch.Tensor)
    """
    N_u = X_u.size(1) # number of inducing, inducing points
    T = X.size(1) # timesteps from KxTxD
    K = X.size(0)

    # broadcasting
    X = X[None, ...]
    X_u = X_u[:, None, ...]

    if Lff is None:
        Kff = kernel(X_u)[:, 0, ...].contiguous()
        Kff.data.view(Kff.shape[0], -1)[:, ::N_u+1] += jitter  # add jitter to diagonal
        Lff = Kff.cholesky() # N, N_u, N_u
    Kfs = kernel(X_u, X) # N, K, N_u, T, previously X_u[:, None, ...].repeat(1, K, 1, 1)

    N = Kfs.shape[0] # if 1, only one lengthscale, otherwise equal to out_dims, N_ is opposite
    Kfs = Kfs.permute(0, 2, 1, 3).reshape(N, N_u, -1) # N, N_u, KxT

    if N == 1: # single lengthscale for all outputs
        # convert f_loc_shape from N, N_u to 1, N_u, N
        f_loc = f_loc.permute(-1, 0)[None, ...]

        # f_scale_tril N, N_u, N_u
        if f_scale_tril is not None:
            # convert f_scale_tril_shape from N, N_u, N_u to N_u, N_u, N, convert to 1 x 2D tensor for packing
            f_scale_tril = f_scale_tril.permute(-2, -1, 0).reshape(1, N_u, -1)

    else: # multi-lengthscale
        # convert f_loc_shape to N, N_u, 1
        f_loc = f_loc[..., None]
        # f_scale_tril N, N_u, N_u

    if whiten:
        v_4D = f_loc[None, ...].repeat(K, 1, 1, 1) # K, N, N_u, N_
        W = Kfs.triangular_solve(Lff, upper=False)[0]
        W = W.view(N, N_u, K, T).permute(2, 0, 3, 1) # K, N, T, N_u
        if f_scale_tril is not None:
            S_4D = f_scale_tril[None, ...].repeat(K, 1, 1, 1)
    else:
        pack = torch.cat((f_loc, Kfs), dim=-1) # N, N_u, L
        if f_scale_tril is not None:
            pack = torch.cat((pack, f_scale_tril), dim=-1)

        Lffinv_pack = pack.triangular_solve(Lff, upper=False)[0] # unpack
        v_4D = Lffinv_pack[None, :, :, :f_loc.size(-1)].repeat(K, 1, 1, 1) # K, N, N_u, N_
        if f_scale_tril is not None:
            S_4D = Lffinv_pack[None, :, :, -f_scale_tril.size(-1):].repeat(K, 1, 1, 1) # K, N, N_u, N_u or N_xN_u

        W = Lffinv_pack[:, :, f_loc.size(-1):f_loc.size(-1)+K*T]
        W = W.view(N, N_u, K, T).permute(2, 0, 3, 1) # K, N, T, N_u

    if N == 1:
        loc = W.matmul(v_4D).permute(0, 3, 2, 1)[..., 0] # K, N, T
    else:
        loc = W.matmul(v_4D)[..., 0] # K, N, T
        
    if cov_type is None:
        return loc, 0, Lff
        
    full_cov = (cov_type == 'full')
    
    if full_cov:
        Kss = kernel(X).transpose(0, 1)
        Qss = W.matmul(W.transpose(-2, -1))
        cov = Kss - Qss # K, N, T, T
    else:
        Kssdiag = kernel(X, diag=True).transpose(0, 1)
        Qssdiag = W.pow(2).sum(dim=-1)
        # Theoretically, Kss - Qss is non-negative; but due to numerical
        # computation, that might not be the case in practice.
        cov = (Kssdiag - Qssdiag).clamp(min=0) # K, N, T

    if f_scale_tril is not None:
        W_S = W.matmul(S_4D) # K, N, T, N_xN_u
        if N == 1:
            W_S = W_S.view(K, 1, T, N_u, out_dims).permute(0, 4, 2, 3, 1)[..., 0]

        if full_cov:
            St_Wt = W_S.transpose(-2, -1)
            K = W_S.matmul(St_Wt)
            cov = cov + K
        else:
            Kdiag = W_S.pow(2).sum(dim=-1)
            cov = cov + Kdiag
    
    return loc, cov, Lff
r"""
    Single kernel parameter set shared over all output dimensions.

    :param int out_dims: number of output dimensions
    :param torch.Tensor X: Input data to evaluate the posterior over
    :param torch.Tensor X_u: Input data to conditioned on, inducing points in sparse GP
    :param GP.kernels.Kernel kernel: A kernel module object
    :param torch.Tensor f_loc: Mean of :math:`q(f)`. In case ``f_scale_tril=None``,
        :math:`f_{loc} = f`
    :param torch.Tensor f_scale_tril: Lower triangular decomposition of covariance
        matrix of :math:`q(f)`'s
    :param torch.Tensor Lff: Lower triangular decomposition of :math:`kernel(X, X)`
        (optional)
    :param string cov_type: A flag to decide what form of covariance to compute
    :param bool whiten: A flag to tell if ``f_loc`` and ``f_scale_tril`` are
        already transformed by the inverse of ``Lff``
    :param float jitter: A small positive term which is added into the diagonal part of
        a covariance matrix to help stablize its Cholesky decomposition
    :returns: loc and covariance matrix (or variance) of :math:`p(f^*(X_{new}))`
    :rtype: tuple(torch.Tensor, torch.Tensor)
    
r"""
Single kernel parameter set shared over all output dimensions.
r " " " Single kernel parameter set shared over all output dimensions .
def p_F_U(out_dims, X, X_u, kernel, f_loc, f_scale_tril=None, Lff=None, cov_type='diagonal',
        whiten=False, jitter=1e-6):
    N_u = X_u.size(1) 
    T = X.size(1) 
    K = X.size(0)
    X = X[None, ...]
    X_u = X_u[:, None, ...]
    if Lff is None:
        Kff = kernel(X_u)[:, 0, ...].contiguous()
        Kff.data.view(Kff.shape[0], -1)[:, ::N_u+1] += jitter  
        Lff = Kff.cholesky() 
    Kfs = kernel(X_u, X) 
    N = Kfs.shape[0] 
    Kfs = Kfs.permute(0, 2, 1, 3).reshape(N, N_u, -1) 
    if N == 1: 
        f_loc = f_loc.permute(-1, 0)[None, ...]
        if f_scale_tril is not None:
            f_scale_tril = f_scale_tril.permute(-2, -1, 0).reshape(1, N_u, -1)
    else: 
        f_loc = f_loc[..., None]
    if whiten:
        v_4D = f_loc[None, ...].repeat(K, 1, 1, 1) 
        W = Kfs.triangular_solve(Lff, upper=False)[0]
        W = W.view(N, N_u, K, T).permute(2, 0, 3, 1) 
        if f_scale_tril is not None:
            S_4D = f_scale_tril[None, ...].repeat(K, 1, 1, 1)
    else:
        pack = torch.cat((f_loc, Kfs), dim=-1) 
        if f_scale_tril is not None:
            pack = torch.cat((pack, f_scale_tril), dim=-1)
        Lffinv_pack = pack.triangular_solve(Lff, upper=False)[0] 
        v_4D = Lffinv_pack[None, :, :, :f_loc.size(-1)].repeat(K, 1, 1, 1) 
        if f_scale_tril is not None:
            S_4D = Lffinv_pack[None, :, :, -f_scale_tril.size(-1):].repeat(K, 1, 1, 1) u or N_xN_u
        W = Lffinv_pack[:, :, f_loc.size(-1):f_loc.size(-1)+K*T]
        W = W.view(N, N_u, K, T).permute(2, 0, 3, 1) 
    if N == 1:
        loc = W.matmul(v_4D).permute(0, 3, 2, 1)[..., 0] 
    else:
        loc = W.matmul(v_4D)[..., 0] 
    if cov_type is None:
        return loc, 0, Lff
    full_cov = (cov_type == 'full')
    if full_cov:
        Kss = kernel(X).transpose(0, 1)
        Qss = W.matmul(W.transpose(-2, -1))
        cov = Kss - Qss , T
    else:
        Kssdiag = kernel(X, diag=True).transpose(0, 1)
        Qssdiag = W.pow(2).sum(dim=-1)
        cov = (Kssdiag - Qssdiag).clamp(min=0) 
    if f_scale_tril is not None:
        W_S = W.matmul(S_4D) , N_xN_u
        if N == 1:
            W_S = W_S.view(K, 1, T, N_u, out_dims).permute(0, 4, 2, 3, 1)[..., 0]
        if full_cov:
            St_Wt = W_S.transpose(-2, -1)
            K = W_S.matmul(St_Wt)
            cov = cov + K
        else:
            Kdiag = W_S.pow(2).sum(dim=-1)
            cov = cov + Kdiag
    return loc, cov, Lff
def p_F_U ( out_dims , X , X_u , kernel , f_loc , f_scale_tril = None , Lff = None , cov_type = 'diagonal' , whiten = False , jitter = 1e-6 ) : N_u = X_u . size ( 1 ) T = X . size ( 1 ) K = X . size ( 0 ) X = X [ None , ... ] X_u = X_u [ : , None , ... ] if Lff is None : Kff = kernel ( X_u ) [ : , 0 , ... ] . contiguous ( ) Kff . data . view ( Kff . shape [ 0 ] , - 1 ) [ : , : : N_u + 1 ] += jitter Lff = Kff . cholesky ( ) Kfs = kernel ( X_u , X ) N = Kfs . shape [ 0 ] Kfs = Kfs . permute ( 0 , 2 , 1 , 3 ) . reshape ( N , N_u , - 1 ) if N == 1 : f_loc = f_loc . permute ( - 1 , 0 ) [ None , ... ] if f_scale_tril is not None : f_scale_tril = f_scale_tril . permute ( - 2 , - 1 , 0 ) . reshape ( 1 , N_u , - 1 ) else : f_loc = f_loc [ ... , None ] if whiten : v_4D = f_loc [ None , ... ] . repeat ( K , 1 , 1 , 1 ) W = Kfs . triangular_solve ( Lff , upper = False ) [ 0 ] W = W . view ( N , N_u , K , T ) . permute ( 2 , 0 , 3 , 1 ) if f_scale_tril is not None : S_4D = f_scale_tril [ None , ... ] . repeat ( K , 1 , 1 , 1 ) else : pack = torch . cat ( ( f_loc , Kfs ) , dim = - 1 ) if f_scale_tril is not None : pack = torch . cat ( ( pack , f_scale_tril ) , dim = - 1 ) Lffinv_pack = pack . triangular_solve ( Lff , upper = False ) [ 0 ] v_4D = Lffinv_pack [ None , : , : , : f_loc . size ( - 1 ) ] . repeat ( K , 1 , 1 , 1 ) if f_scale_tril is not None : S_4D = Lffinv_pack [ None , : , : , - f_scale_tril . size ( - 1 ) : ] . repeat ( K , 1 , 1 , 1 ) W = Lffinv_pack [ : , : , f_loc . size ( - 1 ) : f_loc . size ( - 1 ) + K * T ] W = W . view ( N , N_u , K , T ) . permute ( 2 , 0 , 3 , 1 ) if N == 1 : loc = W . matmul ( v_4D ) . permute ( 0 , 3 , 2 , 1 ) [ ... , 0 ] else : loc = W . matmul ( v_4D ) [ ... , 0 ] if cov_type is None : return loc , 0 , Lff full_cov = ( cov_type == 'full' ) if full_cov : Kss = kernel ( X ) . transpose ( 0 , 1 ) Qss = W . matmul ( W . transpose ( - 2 , - 1 ) ) cov = Kss - Qss else : Kssdiag = kernel ( X , diag = True ) . transpose ( 0 , 1 ) Qssdiag = W . pow ( 2 ) . sum ( dim = - 1 ) cov = ( Kssdiag - Qssdiag ) . clamp ( min = 0 ) if f_scale_tril is not None : W_S = W . matmul ( S_4D ) if N == 1 : W_S = W_S . view ( K , 1 , T , N_u , out_dims ) . permute ( 0 , 4 , 2 , 3 , 1 ) [ ... , 0 ] if full_cov : St_Wt = W_S . transpose ( - 2 , - 1 ) K = W_S . matmul ( St_Wt ) cov = cov + K else : Kdiag = W_S . pow ( 2 ) . sum ( dim = - 1 ) cov = cov + Kdiag return loc , cov , Lff
r"""
Single kernel parameter set shared over all output dimensions.
r " " " Single kernel parameter set shared over all output dimensions .
r"""
    Single kernel parameter set shared over all output dimensions.

    :param int out_dims: number of output dimensions
    :param torch.Tensor X: Input data to evaluate the posterior over
    :param torch.Tensor X_u: Input data to conditioned on, inducing points in sparse GP
    :param GP.kernels.Kernel kernel: A kernel module object
    :param torch.Tensor f_loc: Mean of :math:`q(f)`. In case ``f_scale_tril=None``,
        :math:`f_{loc} = f`
    :param torch.Tensor f_scale_tril: Lower triangular decomposition of covariance
        matrix of :math:`q(f)`'s
    :param torch.Tensor Lff: Lower triangular decomposition of :math:`kernel(X, X)`
        (optional)
    :param string cov_type: A flag to decide what form of covariance to compute
    :param bool whiten: A flag to tell if ``f_loc`` and ``f_scale_tril`` are
        already transformed by the inverse of ``Lff``
    :param float jitter: A small positive term which is added into the diagonal part of
        a covariance matrix to help stablize its Cholesky decomposition
    :returns: loc and covariance matrix (or variance) of :math:`p(f^*(X_{new}))`
    :rtype: tuple(torch.Tensor, torch.Tensor)
    """ # number of inducing, inducing points # timesteps from KxTxD # broadcasting # add jitter to diagonal # N, N_u, N_u # N, K, N_u, T, previously X_u[:, None, ...].repeat(1, K, 1, 1) # if 1, only one lengthscale, otherwise equal to out_dims, N_ is opposite # N, N_u, KxT # single lengthscale for all outputs # convert f_loc_shape from N, N_u to 1, N_u, N # f_scale_tril N, N_u, N_u # convert f_scale_tril_shape from N, N_u, N_u to N_u, N_u, N, convert to 1 x 2D tensor for packing # multi-lengthscale # convert f_loc_shape to N, N_u, 1 # f_scale_tril N, N_u, N_u # K, N, N_u, N_ # K, N, T, N_u # N, N_u, L # unpack # K, N, N_u, N_ # K, N, N_u, N_u or N_xN_u # K, N, T, N_u # K, N, T # K, N, T # K, N, T, T # Theoretically, Kss - Qss is non-negative; but due to numerical # computation, that might not be the case in practice. # K, N, T # K, N, T, N_xN_u
loc and covariance matrix (or variance) of :math:`p(f^*(X_{new}))`
loc and covariance matrix ( or variance ) of : math : ` p ( f^ * ( X_ { new } )) `
tuple(torch.Tensor, torch.Tensor)
out_dims
number of output dimensions
number of output dimensions
X
Input data to evaluate the posterior over
Input data to evaluate the posterior over
X_u
Input data to conditioned on, inducing points in sparse GP
Input data to conditioned on inducing points in sparse GP
kernel
A kernel module object
A kernel module object
f_loc
Mean of :math:`q(f)`.
Mean of : math : ` q ( f ) ` .
f_scale_tril
Lower triangular decomposition of covariance
matrix of :math:`q(f)`'s
Lower triangular decomposition of covariance matrix of : math : ` q ( f ) ` ' s
Lff
Lower triangular decomposition of :math:`kernel(X, X)`
(optional)
Lower triangular decomposition of : math : ` kernel ( X X ) ` ( optional )
cov_type
A flag to decide what form of covariance to compute
A flag to decide what form of covariance to compute
whiten
A flag to tell if ``f_loc`` and ``f_scale_tril`` are
already transformed by the inverse of ``Lff``
A flag to tell if ` ` f_loc ` ` and ` ` f_scale_tril ` ` are already transformed by the inverse of ` ` Lff ` `
jitter
A small positive term which is added into the diagonal part of
a covariance matrix to help stablize its Cholesky decomposition
A small positive term which is added into the diagonal part of a covariance matrix to help stablize its Cholesky decomposition