Skip to content

Commit bbcf8e3

Browse files
committed
switch K to Cholesky LL^T to simplify multiple steps
1 parent be20c8b commit bbcf8e3

4 files changed

Lines changed: 30 additions & 9 deletions

File tree

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ importFrom(BiocParallel,bpstopOnError)
9797
importFrom(BiocParallel,bptry)
9898
importFrom(BiocSingular,bsparam)
9999
importFrom(Matrix,Matrix)
100+
importFrom(Matrix,chol)
100101
importFrom(Matrix,colSums)
101102
importFrom(Matrix,crossprod)
102103
importFrom(Matrix,diag)

R/glmm.R

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
#' @name fitGLMM
7777
#'
7878
#' @importMethodsFrom Matrix %*%
79-
#' @importFrom Matrix Matrix solve crossprod kronecker
79+
#' @importFrom Matrix Matrix solve crossprod kronecker chol
8080
#' @importFrom stats runif var
8181
#' @importFrom BiocParallel bpstopOnError
8282
#' @export
@@ -176,9 +176,13 @@ fitGLMM <- function(X, Z, y, offsets, init.theta=NULL, Kin=NULL,
176176

177177
## add the genetic components
178178
## augment Z with I
179-
geno.I <- diag(nrow(full.Z))
179+
## Use K=LD^1/2(LD^1/2)^T instead of ZZ^T for GRM
180+
## chol return L^T
181+
geno.I <- t(chol(Kin))
182+
# geno.I <- diag(nrow(full.Z))
180183
colnames(geno.I) <- paste0("CovarMat", seq_len(ncol(geno.I)))
181184
full.Z <- do.call(cbind, list(full.Z, geno.I))
185+
182186
# add a genetic variance component
183187
sigma_g <- Matrix(runif(1, 0, 1), ncol=1, nrow=1, sparse=TRUE)
184188
rownames(sigma_g) <- "CovarMat"
@@ -201,7 +205,10 @@ fitGLMM <- function(X, Z, y, offsets, init.theta=NULL, Kin=NULL,
201205

202206
# if we only have a GRM then Z _is_ full.Z?
203207
# full.Z <- initializeFullZ(Z, cluster_levels=random.levels)
204-
full.Z <- Z
208+
## Use K=LD^1/2(LD^1/2)^T instead of ZZ^T for GRM
209+
## chol return L^T
210+
full.Z <- t(chol(Kin))
211+
# full.Z <- Z
205212
# should this be the matrix R?
206213
colnames(full.Z) <- paste0(names(random.levels), seq_len(ncol(full.Z)))
207214

@@ -456,7 +463,7 @@ initialiseG <- function(cluster_levels, sigmas, Kin=NULL){
456463
diag(G[c(i:(i+x.q-1)), c(i:(i+x.q-1)), drop=FALSE]) <- sigmas[x, ] # is this sufficient to transform the sigma to the model scale?
457464
} else{
458465
if(rownames(sigmas[x, , drop=FALSE]) %in% c("Genetic")){
459-
diag(G[c(i:(i+x.q-1)), c(i:(i+x.q-1)), drop=FALSE]) <- sigmas[x, ] * Kin
466+
diag(G[c(i:(i+x.q-1)), c(i:(i+x.q-1)), drop=FALSE]) <- sigmas[x, ] #* Kin
460467
}else{
461468
diag(G[c(i:(i+x.q-1)), c(i:(i+x.q-1)), drop=FALSE]) <- sigmas[x, ] # is this sufficient to transform the sigma to the model scale?
462469
}

src/paramEst.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,12 @@ arma::mat vectoriseZGenetic(const arma::mat& Z, const Rcpp::List& u_indices,
700700

701701
// always set the last component to the genetic variance if there is a kinship matrix
702702
if(i == c-1){
703-
arma::vec _vecZ = Kin(lower_indices);
703+
// arma::vec _vecZ = Kin(lower_indices);
704+
// Cholesky LL^T of kinship == ZZ^T
705+
arma::mat _ZZT = PZ.cols(u_idx - 1) * Z.cols(u_idx - 1).t() * P.t(); // REML projection
706+
707+
// vectorise
708+
arma::vec _vecZ = _ZZT(lower_indices);
704709
vecMat.col(i+1) = _vecZ;
705710
// vecMat.col(i) = _vecZ;
706711
} else{
@@ -741,7 +746,12 @@ arma::mat vectoriseZGeneticML(const arma::mat& Z, const Rcpp::List& u_indices,
741746

742747
// always set the last component to the genetic variance if there is a kinship matrix
743748
if(i == c-1){
744-
arma::vec _vecZ = Kin(lower_indices);
749+
// arma::vec _vecZ = Kin(lower_indices);
750+
// Cholesky LL^T of kinship == ZZ^T
751+
arma::mat _ZZT = Z.cols(u_idx - 1) * Z.cols(u_idx - 1).t();
752+
753+
// vectorise
754+
arma::vec _vecZ = _ZZT(lower_indices);
745755
vecMat.col(i+1) = _vecZ;
746756
// vecMat.col(i) = _vecZ;
747757
} else{

src/pseudovarPartial.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ List computePZList_G(const List& u_indices, const arma::mat& PZ, const arma::mat
7575
arma::mat _pzz(n, n);
7676

7777
if(i == c - 1){
78-
_pzz = PZ.cols(u_idx-1) * K * Z.cols(u_idx-1).t(); // convert 1-based to 0-based
78+
// _pzz = PZ.cols(u_idx-1) * K * Z.cols(u_idx-1).t(); // convert 1-based to 0-based
79+
_pzz = PZ.cols(u_idx-1) * Z.cols(u_idx-1).t(); // convert 1-based to 0-based
7980
} else{
8081
_pzz = PZ.cols(u_idx-1) * Z.cols(u_idx-1).t(); // convert 1-based to 0-based
8182
}
@@ -160,7 +161,8 @@ List pseudovarPartial_VG(const List& u_indices, const arma::mat& Z, const arma::
160161
arma::mat Zcols = Z.cols(u_idx-1).t();
161162

162163
if(i == c - 1){
163-
omat = VstarZ.cols(u_idx-1) * K * Zcols;
164+
//omat = VstarZ.cols(u_idx-1) * K * Zcols;
165+
omat = VstarZ.cols(u_idx-1) * Zcols;
164166
} else{
165167
omat = VstarZ.cols(u_idx-1) * Zcols;
166168
}
@@ -181,7 +183,8 @@ List pseudovarPartial_G(arma::mat Z, const arma::mat& K, List u_indices){
181183
for(unsigned int i = 0; i < items; i++){
182184
if(i == items - 1){
183185
arma::uvec icols = u_indices[i];
184-
arma::mat _omat(Z.cols(icols - 1) * K * Z.cols(icols - 1).t());
186+
// arma::mat _omat(Z.cols(icols - 1) * K * Z.cols(icols - 1).t());
187+
arma::mat _omat(K);
185188
outlist[i] = _omat; // K is equivalent to ZZ^T
186189
} else{
187190
arma::uvec icols = u_indices[i];

0 commit comments

Comments
 (0)