Nothing
# #' Function factory for likelihood evaluation for the metric graph SPDE model
# #'
# #' @param graph metric_graph object
# #' @param alpha Order of the SPDE, should be either 1 or 2.
# #' @param data_name Name of the response variable
# #' @param covariates OBSOLETE
# #' @param log_scale Should the parameters `theta` of the returning function be
# #' given in log scale?
# #' @param version if 1, the likelihood is computed by integrating out
# #' @param maximize If `FALSE` the function will return minus the likelihood, so
# #' one can directly apply it to the `optim` function.
# #' @param BC which boundary condition to use (0,1) 0 is no adjustment on boundary point
# #' 1 is making the boundary condition stationary
# #' @return The log-likelihood function, which is returned as a function with
# #' parameter 'theta'.
# #' The parameter `theta` must be supplied as
# #' the vector `c(sigma_e, sigma, kappa)`.
# #'
# #' If `covariates` is `TRUE`, then the parameter `theta` must be supplied as the
# #' vector `c(sigma_e, sigma, kappa, beta[1], ..., beta[p])`,
# #' where `beta[1],...,beta[p]` are the coefficients and `p` is the number of
# #' covariates.
# #' @noRd
# likelihood_graph_spde <- function(graph,
# alpha = 1,
# covariates = FALSE,
# data_name,
# log_scale = TRUE,
# maximize = FALSE,
# version = 1,
# repl=NULL,
# BC = 1) {
# check <- check_graph(graph)
# if(!(alpha%in%c(1,2))){
# stop("alpha must be either 1 or 2!")
# }
# loglik <- function(theta){
# if(log_scale){
# theta_spde <- exp(theta[1:3])
# theta_spde <- c(theta_spde, theta[-c(1:3)])
# } else{
# theta_spde <- theta
# }
# switch(alpha,
# "1" = {
# if(version == 1){
# loglik_val <- likelihood_alpha1(theta_spde, graph, data_name, covariates,BC=BC)
# } else if(version == 2){
# loglik_val <- likelihood_alpha1_v2(theta_spde, graph, X_cov, y, repl,BC=BC)
# } else{
# stop("Version should be either 1 or 2!")
# }
# },
# "2" = {
# loglik_val <- likelihood_alpha2(theta_spde, graph, data_name, covariates, BC=BC)
# }
# )
# if(maximize){
# return(loglik_val)
# } else{
# return(-loglik_val)
# }
# }
# }
#' Log-likelihood calculation for alpha=1 model directional
#' @param theta (sigma_e, reciprocal_tau, kappa)
#' @param graph metric_graph object
#' @param data_name name of the response variable
#' @param repl replicates
#' @param X_cov matrix of covariates
#' @noRd
likelihood_alpha1_directional <- function(theta,
graph,
data_name = NULL,
manual_y = NULL,
X_cov = NULL,
repl = NULL,
parameterization="matern") {
#build Q
if(is.null(graph$C)){
graph$buildDirectionalConstraints(alpha = 1)
} else if(graph$CoB$alpha == 2){
graph$buildDirectionalConstraints(alpha = 1)
}
repl_vec <- graph$.__enclos_env__$private$data[[".group"]]
if(is.null(repl)){
repl <- unique(repl_vec)
}
sigma_e <- exp(theta[1])
if(parameterization == "matern"){
kappa = sqrt(8 * 0.5) / exp(theta[3])
} else{
kappa = exp(theta[3])
}
reciprocal_tau <- exp(theta[2])
Q.list <- Qalpha1_edges(c( 1/reciprocal_tau,kappa),
graph,
w = 0,
BC=1, build=FALSE)
n_const <- length(graph$CoB$S)
ind.const <- c(1:n_const)
Tc <- graph$CoB$T[-ind.const, ]
Q <- Matrix::sparseMatrix(i = Q.list$i,
j = Q.list$j,
x = Q.list$x,
dims = Q.list$dims)
R <- Matrix::Cholesky(forceSymmetric(Tc%*%Q%*%t(Tc)),
LDL = FALSE, perm = TRUE)
det_R <- Matrix::determinant(R, sqrt=TRUE)$modulus[1]
#build BSIGMAB
PtE <- graph$get_PtE()
obs.edges <- unique(PtE[, 1])
i_ <- j_ <- x_ <- rep(0, 4 * length(obs.edges))
if(is.null(repl)){
u_repl <- unique(graph$.__enclos_env__$private$data[[".group"]])
} else{
u_repl <- unique(repl)
}
ind_repl <- (graph$.__enclos_env__$private$data[[".group"]] %in% u_repl)
loglik <- 0
det_R_count <- NULL
if(is.null(manual_y)){
y_resp <- graph$.__enclos_env__$private$data[[data_name]]
} else if(is.null(data_name)){
y_resp <- manual_y
} else{
stop("Either data_name or manual_y must be not NULL")
}
n.o <- sum(ind_repl)
for(repl_y in 1:length(u_repl)){
loglik <- loglik + det_R
count <- 0
Qpmu <- rep(0, 2*nrow(graph$E))
for (e in obs.edges) {
ind_repl <- graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y]
obs.id <- PtE[,1] == e
y_i <- y_resp[ind_repl]
y_i <- y_i[obs.id]
idx_na <- is.na(y_i)
y_i <- y_i[!idx_na]
if(sum(!idx_na) == 0){
next
}
if(!is.null(X_cov)){
n_cov <- ncol(X_cov)
if(n_cov == 0){
X_cov_repl <- 0
} else{
X_cov_repl <- X_cov[graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y], , drop=FALSE]
X_cov_repl <- X_cov_repl[PtE[,1] == e, ,drop = FALSE]
X_cov_repl <- X_cov_repl[!idx_na, , drop = FALSE]
y_i <- y_i - X_cov_repl %*% theta[4:(3+n_cov)]
}
}
l <- graph$edge_lengths[e]
PtE_temp <- PtE[obs.id, 2]
PtE_temp <- PtE_temp[!idx_na]
D_matrix <- as.matrix(dist(c(0, l, l*PtE_temp)))
S <- r_1(D_matrix, kappa = kappa, tau = 1/reciprocal_tau)
#covariance update see Art p.17
E.ind <- c(1:2)
Obs.ind <- -E.ind
Bt <- solve(S[E.ind, E.ind, drop = FALSE], S[E.ind, Obs.ind, drop = FALSE])
Sigma_i <- S[Obs.ind, Obs.ind, drop = FALSE] -
S[Obs.ind, E.ind, drop = FALSE] %*% Bt
diag(Sigma_i) <- diag(Sigma_i) + sigma_e^2
R <- base::chol(Sigma_i)
Sigma_iB <- solve(Sigma_i, t(Bt))
BtSinvB <- Bt %*% Sigma_iB
E <- graph$E[e, ]
if (E[1] == E[2]) {
Qpmu[2*(e-1)+1] <- Qpmu[2*(e-1)+1] + sum(t(Sigma_iB) %*% y_i)
i_[count + 1] <- 2*(e-1)+1
j_[count + 1] <- 2*(e-1)+1
x_[count + 1] <- sum(Bt %*% Sigma_iB)
} else {
Qpmu[2*(e-1) + c(1, 2)] <- Qpmu[2*(e-1) + c(1, 2)] + t(Sigma_iB) %*% y_i
i_[count + (1:4)] <- c(2*(e-1)+1, 2*(e-1)+1, 2*(e-1)+2, 2*(e-1)+2)
j_[count + (1:4)] <- c(2*(e-1)+1, 2*(e-1)+2, 2*(e-1)+1, 2*(e-1)+2)
x_[count + (1:4)] <- c(BtSinvB[1, 1], BtSinvB[1, 2],
BtSinvB[1, 2], BtSinvB[2, 2])
count <- count + 4
}
loglik <- loglik - 0.5 * t(y_i) %*% solve(Sigma_i, y_i)
loglik <- loglik - sum(log(diag(R)))
}
if(is.null(det_R_count)){
i_ <- c(Q.list$i, i_[1:count])
j_ <- c(Q.list$j, j_[1:count])
x_ <- c(Q.list$x, x_[1:count])
Qp <- Matrix::sparseMatrix(i = i_,
j = j_,
x = x_,
dims = Q.list$dims)
Qp <- Tc %*% Qp %*% t(Tc)
R_count <- Matrix::Cholesky(forceSymmetric(Qp), LDL = FALSE, perm = TRUE)
det_R_count <- Matrix::determinant(R_count, sqrt=TRUE)$modulus[1]
}
loglik <- loglik - det_R_count
v <- c(as.matrix(Matrix::solve(R_count, Matrix::solve(R_count, Tc%*%Qpmu,
system = "P"),
system = "L")))
loglik <- loglik + 0.5 * t(v) %*% v - 0.5 * n.o * log(2*pi)
}
return(loglik[1])
}
#' Computes the log likelihood function fo theta for the graph object
#' @param theta parameters (sigma_e, reciprocal_tau, kappa)
#' @param graph metric_graph object
#' @param data_name name of the response variable
#' @param BC which boundary condition to use (0,1)
#' @param covariates OBSOLETE
#' @noRd
likelihood_alpha2 <- function(theta, graph, data_name = NULL, manual_y = NULL,
X_cov = NULL, repl, BC, parameterization) {
if(is.null(graph$C)){
graph$buildC(2)
} else if(graph$CoB$alpha == 1){
graph$buildC(2)
}
repl_vec <- graph$.__enclos_env__$private$data[[".group"]]
if(is.null(repl)){
repl <- unique(repl_vec)
}
sigma_e <- exp(theta[1])
reciprocal_tau <- exp(theta[2])
if(parameterization == "matern"){
kappa = sqrt(8 * 1.5) / exp(theta[3])
} else{
kappa = exp(theta[3])
}
if(is.null(repl)){
u_repl <- unique(graph$.__enclos_env__$private$data[[".group"]])
} else{
u_repl <- unique(repl)
}
ind_repl <- (graph$.__enclos_env__$private$data[[".group"]] %in% u_repl)
if(is.null(manual_y)){
y <- graph$.__enclos_env__$private$data[[data_name]]
} else if(is.null(data_name)){
y <- manual_y
} else{
stop("Either data_name or manual_y must be not NULL")
}
n.o <- sum(ind_repl)
#build Q
n_const <- length(graph$CoB$S)
ind.const <- c(1:n_const)
Tc <- graph$CoB$T[-ind.const, ]
Q <- spde_precision(kappa = kappa, tau = 1/reciprocal_tau,
alpha = 2, graph = graph, BC=BC)
R <- Matrix::Cholesky(forceSymmetric(Tc%*%Q%*%t(Tc)),
LDL = FALSE, perm = TRUE)
PtE <- graph$get_PtE()
obs.edges <- unique(PtE[, 1])
loglik <- 0
det_R <- Matrix::determinant(R, sqrt=TRUE)$modulus[1]
# n.o <- length(graph$.__enclos_env__$private$data[[data_name]])
# u_repl <- unique(graph$.__enclos_env__$private$data[[".group"]])
det_R_count <- NULL
# y <- graph$.__enclos_env__$private$data[[data_name]]
for(repl_y in 1:length(u_repl)){
loglik <- loglik + det_R
Qpmu <- rep(0, 4 * nrow(graph$E))
# y_rep <- graph$.__enclos_env__$private$data[[data_name]][graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y]]
y_rep <- y[graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y]]
#build BSIGMAB
i_ <- j_ <- x_ <- rep(0, 16 * length(obs.edges))
count <- 0
for (e in obs.edges) {
obs.id <- PtE[,1] == e
y_i <- y_rep[obs.id]
if(!is.null(X_cov)){
n_cov <- ncol(X_cov)
if(n_cov == 0){
X_cov_repl <- 0
} else{
X_cov_repl <- X_cov[graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y], , drop=FALSE]
X_cov_repl <- X_cov_repl[obs.id, ,drop = FALSE]
y_i <- y_i - X_cov_repl %*% theta[4:(3+n_cov)]
}
}
l <- graph$edge_lengths[e]
t <- c(0, l, l*PtE[obs.id, 2])
D <- outer (t, t, `-`)
S <- matrix(0, length(t) + 2, length(t) + 2)
d.index <- c(1,2)
S[-d.index, -d.index] <- r_2(D, kappa = kappa,
tau = 1/reciprocal_tau, deriv = 0)
S[ d.index, d.index] <- -r_2(as.matrix(dist(c(0,l))),
kappa = kappa, tau = 1/reciprocal_tau,
deriv = 2)
S[d.index, -d.index] <- -r_2(D[1:2,], kappa = kappa,
tau = 1/reciprocal_tau, deriv = 1)
S[-d.index, d.index] <- t(S[d.index, -d.index])
#covariance update see Art p.17
E.ind <- c(1:4)
Obs.ind <- -E.ind
Bt <- solve(S[E.ind, E.ind], S[E.ind, Obs.ind, drop = FALSE])
Sigma_i <- S[Obs.ind,Obs.ind] - S[Obs.ind, E.ind] %*% Bt
diag(Sigma_i) <- diag(Sigma_i) + sigma_e^2
R <- base::chol(Sigma_i, pivot = TRUE)
if(attr(R, "rank") < dim(R)[1])
return(-Inf)
Sigma_iB <- t(Bt)
Sigma_iB[attr(R,"pivot"),] <- base::forwardsolve(R,
base::backsolve(R, t(Bt[, attr(R,"pivot")]),
transpose = TRUE), upper.tri = TRUE)
# R <- Matrix::Cholesky(Sigma_i)
# Sigma_iB <- solve(R, t(Bt), system = "A")
BtSinvB <- Bt %*% Sigma_iB
E <- graph$E[e, ]
if (E[1] == E[2]) {
warning("Circle not implemented")
}
BtSinvB <- BtSinvB[c(3,1,4,2), c(3,1,4,2)]
Qpmu[4 * (e - 1) + 1:4] <- Qpmu[4 * (e - 1) + 1:4] +
(t(Sigma_iB) %*% y_i)[c(3, 1, 4, 2)]
#lower edge precision u
i_[count + 1] <- 4 * (e - 1) + 1
j_[count + 1] <- 4 * (e - 1) + 1
x_[count + 1] <- BtSinvB[1, 1]
#lower edge u'
i_[count + 2] <- 4 * (e - 1) + 2
j_[count + 2] <- 4 * (e - 1) + 2
x_[count + 2] <- BtSinvB[2, 2]
#upper edge u
i_[count + 3] <- 4 * (e - 1) + 3
j_[count + 3] <- 4 * (e - 1) + 3
x_[count + 3] <- BtSinvB[3, 3]
#upper edge u'
i_[count + 4] <- 4 * (e - 1) + 4
j_[count + 4] <- 4 * (e - 1) + 4
x_[count + 4] <- BtSinvB[4, 4]
#lower edge u, u'
i_[count + 5] <- 4 * (e - 1) + 1
j_[count + 5] <- 4 * (e - 1) + 2
x_[count + 5] <- BtSinvB[1, 2]
i_[count + 6] <- 4 * (e - 1) + 2
j_[count + 6] <- 4 * (e - 1) + 1
x_[count + 6] <- BtSinvB[1, 2]
#upper edge u, u'
i_[count + 7] <- 4 * (e - 1) + 3
j_[count + 7] <- 4 * (e - 1) + 4
x_[count + 7] <- BtSinvB[3, 4]
i_[count + 8] <- 4 * (e - 1) + 4
j_[count + 8] <- 4 * (e - 1) + 3
x_[count + 8] <- BtSinvB[3, 4]
#lower edge u, upper edge u,
i_[count + 9] <- 4 * (e - 1) + 1
j_[count + 9] <- 4 * (e - 1) + 3
x_[count + 9] <- BtSinvB[1, 3]
i_[count + 10] <- 4 * (e - 1) + 3
j_[count + 10] <- 4 * (e - 1) + 1
x_[count + 10] <- BtSinvB[1, 3]
#lower edge u, upper edge u',
i_[count + 11] <- 4 * (e - 1) + 1
j_[count + 11] <- 4 * (e - 1) + 4
x_[count + 11] <- BtSinvB[1, 4]
i_[count + 12] <- 4 * (e - 1) + 4
j_[count + 12] <- 4 * (e - 1) + 1
x_[count + 12] <- BtSinvB[1, 4]
#lower edge u', upper edge u,
i_[count + 13] <- 4 * (e - 1) + 2
j_[count + 13] <- 4 * (e - 1) + 3
x_[count + 13] <- BtSinvB[2, 3]
i_[count + 14] <- 4 * (e - 1) + 3
j_[count + 14] <- 4 * (e - 1) + 2
x_[count + 14] <- BtSinvB[2, 3]
#lower edge u', upper edge u',
i_[count + 15] <- 4 * (e - 1) + 2
j_[count + 15] <- 4 * (e - 1) + 4
x_[count + 15] <- BtSinvB[2, 4]
i_[count + 16] <- 4 * (e - 1) + 4
j_[count + 16] <- 4 * (e - 1) + 2
x_[count + 16] <- BtSinvB[2, 4]
count <- count + 16
loglik <- loglik - 0.5 * t(y_i)%*%solve(Sigma_i, y_i)
loglik <- loglik - sum(log(diag(R)))
# loglik <- loglik - 0.5 * c(determinant(R, logarithm = TRUE)$modulus)
}
if(is.null(det_R_count)){
i_ <- i_[1:count]
j_ <- j_[1:count]
x_ <- x_[1:count]
BtSB <- Matrix::sparseMatrix(i = i_,
j = j_,
x = x_,
dims = dim(Q))
Qp <- Q + BtSB
Qp <- Tc %*% Qp %*% t(Tc)
R_count <- Matrix::Cholesky(forceSymmetric(Qp), LDL = FALSE, perm = TRUE)
det_R_count <- Matrix::determinant(R_count, sqrt=TRUE)$modulus[1]
}
loglik <- loglik - det_R_count
v <- c(as.matrix(Matrix::solve(R_count, Matrix::solve(R_count, Tc%*%Qpmu, system = 'P'),
system='L')))
loglik <- loglik + 0.5 * t(v) %*% v - 0.5 * n.o * log(2 * pi)
}
return(loglik[1])
}
#' Log-likelihood calculation for alpha=1 model
#'
#' @param theta (sigma_e, reciprocal_tau, kappa)
#' @param graph metric_graph object
#' @param X_cov matrix of covariates
#' @param y response vector
#' @param repl replicates to be considered
#' @param BC boundary conditions
#' @param parameterization parameterization to be used.
#' @details This function computes the likelihood without integrating out
#' the vertices.
#' @return The log-likelihood
#' @noRd
likelihood_alpha1_v2 <- function(theta, graph, X_cov, y, repl, BC, parameterization) {
repl_vec <- graph$.__enclos_env__$private$data[[".group"]]
if(is.null(repl)){
repl <- unique(repl_vec)
}
if(parameterization == "matern"){
kappa = sqrt(8 * 0.5) / exp(theta[3])
} else{
kappa = exp(theta[3])
}
sigma_e <- exp(theta[1])
reciprocal_tau <- exp(theta[2])
#build Q
Q <- spde_precision(kappa = kappa, tau = 1/reciprocal_tau,
alpha = 1, graph = graph, BC=BC)
if(is.null(graph$PtV)){
stop("No observation at the vertices! Run observation_to_vertex().")
}
# R <- chol(Q)
# R <- Matrix::chol(Q)
R <- Matrix::Cholesky(Q)
l <- 0
for(i in repl){
A <- Matrix::Diagonal(graph$nV)[graph$PtV, ]
ind_tmp <- (repl_vec %in% i)
y_tmp <- y[ind_tmp]
if(ncol(X_cov) == 0){
X_cov_tmp <- 0
} else {
X_cov_tmp <- X_cov[ind_tmp,,drop=FALSE]
}
na_obs <- is.na(y_tmp)
y_ <- y_tmp[!na_obs]
n.o <- length(y_)
Q.p <- Q + t(A[!na_obs,]) %*% A[!na_obs,]/sigma_e^2
# R.p <- Matrix::chol(Q.p)
R.p <- Matrix::Cholesky(Q.p)
# l <- l + sum(log(diag(R))) - sum(log(diag(R.p))) - n.o*log(sigma_e)
l <- l + determinant(R, logarithm = TRUE, sqrt = TRUE)$modulus - determinant(R.p, logarithm = TRUE, sqrt = TRUE)$modulus - n.o * log(sigma_e)
v <- y_
if(ncol(X_cov) != 0){
X_cov_tmp <- X_cov_tmp[!na_obs, ]
v <- v - X_cov_tmp %*% theta[4:(3+ncol(X_cov))]
}
# mu.p <- solve(Q.p,as.vector(t(A[!na_obs,]) %*% v / sigma_e^2))
mu.p <- solve(R.p, as.vector(t(A[!na_obs,]) %*% v / sigma_e^2), system = "A")
v <- v - A[!na_obs,]%*%mu.p
l <- l - 0.5*(t(mu.p) %*% Q %*% mu.p + t(v) %*% v / sigma_e^2) -
0.5 * n.o * log(2*pi)
}
return(as.double(l))
}
#' Log-likelihood calculation for alpha=1 model
#' @param theta (sigma_e, reciprocal_tau, kappa)
#' @param graph metric_graph object
#' @param data_name name of the response variable
#' @param repl replicates
#' @param X_cov matrix of covariates
#' @param BC. - which boundary condition to use (0,1)
#' @noRd
likelihood_alpha1 <- function(theta, graph, data_name = NULL, manual_y = NULL,
X_cov = NULL, repl, BC, parameterization) {
sigma_e <- exp(theta[1])
#build Q
repl_vec <- graph$.__enclos_env__$private$data[[".group"]]
if(is.null(repl)){
repl <- unique(repl_vec)
}
if(parameterization == "matern"){
kappa = sqrt(8 * 0.5) / exp(theta[3])
} else{
kappa = exp(theta[3])
}
reciprocal_tau <- exp(theta[2])
Q.list <- spde_precision(kappa = kappa, tau = 1/reciprocal_tau, alpha = 1,
graph = graph, build = FALSE,BC=BC)
Qp <- Matrix::sparseMatrix(i = Q.list$i,
j = Q.list$j,
x = Q.list$x,
dims = Q.list$dims)
R <- Matrix::Cholesky(Qp, LDL = FALSE, perm = TRUE)
det_R <- Matrix::determinant(R, sqrt=TRUE)$modulus[1]
#build BSIGMAB
PtE <- graph$get_PtE()
obs.edges <- unique(PtE[, 1])
i_ <- j_ <- x_ <- rep(0, 4 * length(obs.edges))
if(is.null(repl)){
u_repl <- unique(graph$.__enclos_env__$private$data[[".group"]])
} else{
u_repl <- unique(repl)
}
ind_repl <- (graph$.__enclos_env__$private$data[[".group"]] %in% u_repl)
loglik <- 0
det_R_count <- NULL
if(is.null(manual_y)){
y_resp <- graph$.__enclos_env__$private$data[[data_name]]
} else if(is.null(data_name)){
y_resp <- manual_y
} else{
stop("Either data_name or manual_y must be not NULL")
}
n.o <- sum(ind_repl)
for(repl_y in 1:length(u_repl)){
loglik <- loglik + det_R
count <- 0
Qpmu <- rep(0, nrow(graph$V))
for (e in obs.edges) {
ind_repl <- graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y]
obs.id <- PtE[,1] == e
y_i <- y_resp[ind_repl]
y_i <- y_i[obs.id]
idx_na <- is.na(y_i)
y_i <- y_i[!idx_na]
if(sum(!idx_na) == 0){
next
}
# if(covariates){ #obsolete
# n_cov <- ncol(graph$covariates[[1]])
# if(length(graph$covariates)==1){
# X_cov <- graph$covariates[[1]]
# } else if(length(graph$covariates) == ncol(graph$.__enclos_env__$private$data[[data_name]])){
# X_cov <- graph$covariates[[repl_y]]
# } else{
# stop("You should either have a common covariate for all the replicates, or one set of covariates for each replicate!")
# }
# X_cov <- X_cov[obs.id,]
# y_i <- y_i - X_cov %*% theta[4:(3+n_cov)]
# }
if(!is.null(X_cov)){
n_cov <- ncol(X_cov)
if(n_cov == 0){
X_cov_repl <- 0
} else{
X_cov_repl <- X_cov[graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y], , drop=FALSE]
X_cov_repl <- X_cov_repl[PtE[,1] == e, ,drop = FALSE]
X_cov_repl <- X_cov_repl[!idx_na, , drop = FALSE]
y_i <- y_i - X_cov_repl %*% theta[4:(3+n_cov)]
}
}
l <- graph$edge_lengths[e]
PtE_temp <- PtE[obs.id, 2]
PtE_temp <- PtE_temp[!idx_na]
D_matrix <- as.matrix(dist(c(0, l, l*PtE_temp)))
S <- r_1(D_matrix, kappa = kappa, tau = 1/reciprocal_tau)
#covariance update see Art p.17
E.ind <- c(1:2)
Obs.ind <- -E.ind
Bt <- solve(S[E.ind, E.ind, drop = FALSE], S[E.ind, Obs.ind, drop = FALSE])
Sigma_i <- S[Obs.ind, Obs.ind, drop = FALSE] -
S[Obs.ind, E.ind, drop = FALSE] %*% Bt
diag(Sigma_i) <- diag(Sigma_i) + sigma_e^2
R <- base::chol(Sigma_i)
Sigma_iB <- solve(Sigma_i, t(Bt))
BtSinvB <- Bt %*% Sigma_iB
E <- graph$E[e, ]
if (E[1] == E[2]) {
Qpmu[E[1]] <- Qpmu[E[1]] + sum(t(Sigma_iB) %*% y_i)
i_[count + 1] <- E[1]
j_[count + 1] <- E[1]
x_[count + 1] <- sum(Bt %*% Sigma_iB)
} else {
Qpmu[E] <- Qpmu[E] + t(Sigma_iB) %*% y_i
i_[count + (1:4)] <- c(E[1], E[1], E[2], E[2])
j_[count + (1:4)] <- c(E[1], E[2], E[1], E[2])
x_[count + (1:4)] <- c(BtSinvB[1, 1], BtSinvB[1, 2],
BtSinvB[1, 2], BtSinvB[2, 2])
count <- count + 4
}
loglik <- loglik - 0.5 * t(y_i) %*% solve(Sigma_i, y_i)
loglik <- loglik - sum(log(diag(R)))
}
if(is.null(det_R_count)){
i_ <- c(Q.list$i, i_[1:count])
j_ <- c(Q.list$j, j_[1:count])
x_ <- c(Q.list$x, x_[1:count])
Qp <- Matrix::sparseMatrix(i = i_,
j = j_,
x = x_,
dims = Q.list$dims)
R_count <- Matrix::Cholesky(Qp, LDL = FALSE, perm = TRUE)
det_R_count <- Matrix::determinant(R_count, sqrt=TRUE)$modulus[1]
}
loglik <- loglik - det_R_count
v <- c(as.matrix(Matrix::solve(R_count, Matrix::solve(R_count, Qpmu,
system = "P"),
system = "L")))
loglik <- loglik + 0.5 * t(v) %*% v - 0.5 * n.o * log(2*pi)
}
return(loglik[1])
}
#' Function factory for likelihood evaluation not using sparsity
#' @param graph A `metric_graph` object.
#' @param model Type of model: "alpha1" gives SPDE with alpha=1, "GL1" gives
#' the model based on the graph Laplacian with smoothness 1, "GL2" gives the
#' model based on the graph Laplacian with smoothness 2, and "isoCov" gives a
#' model with isotropic covariance.
#' @param cov_function The covariance function to be used in case 'model' is
#' chosen as 'isoCov'. `cov_function` must be a function of `(h, theta_cov)`,
#' where `h` is a vector, or matrix, containing the distances to evaluate the
#' covariance function at, and `theta_cov` is the vector of parameters of the
#' covariance function `cov_function`.
#' @param y_graph Response vector given in the same order as the internal
#' locations from the graph.
#' @param X_cov Matrix with covariates. The order must be the same as the
#' internal order from the graph.
#' @param repl Vector with the replicates to be considered. If `NULL` all
#' replicates will be considered.
#' @param log_scale Should the parameters `theta` of the returning function be
#' given in log-scale?
#' @param maximize If `FALSE` the function will return minus the likelihood, so
#' one can directly apply it to the `optim` function.
#' @return The log-likelihood function.
#' @details The log-likelihood function that is returned is a function of a
#' parameter `theta`. For models 'alpha1', 'alpha2', 'GL1' and 'GL2', the
#' parameter `theta` must be supplied as the vector `c(sigma_e, sigma, kappa)`.
#'
#' For 'isoCov' model, theta must be a vector such that `theta[1]` is `sigma.e`
#' and the vector `theta[2:(q+1)]` is the input of `cov_function`, where `q` is
#' the number of parameters of the covariance function.
#'
#' If `covariates` is `TRUE`, then the parameter `theta` must be supplied as the
#' vector `c(sigma_e, theta[2], ..., theta[q+1], beta[1], ..., beta[p])`,
#' where `beta[1],...,beta[p]` are the coefficients and `p` is the number of
#' covariates.
#'
#' For the remaining models, if `covariates` is `TRUE`, then `theta` must be
#' supplied as the vector `c(sigma_e, sigma, kappa, beta[1], ..., beta[p])`,
#' where `beta[1],...,beta[p]` are the coefficients and `p` is the number of
#' covariates.
#' @noRd
likelihood_graph_covariance <- function(graph,
model = "alpha1",
y_graph,
cov_function = NULL,
X_cov = NULL,
repl,
log_scale = TRUE,
maximize = FALSE,
fix_vec = NULL,
fix_v_val = NULL,
check_euclidean = TRUE) {
# check <- check_graph(graph)
if(!(model%in%c("WM1", "WM2", "GL1", "GL2", "isoCov"))){
stop("The available models are: 'WM1', 'WM2', 'GL1', 'GL2' and 'isoCov'!")
}
loglik <- function(theta){
if(!is.null(X_cov)){
n_cov <- ncol(X_cov)
} else{
n_cov <- 0
}
if(!is.null(fix_v_val)){
# new_theta <- fix_v_val
fix_v_val_full <- c(fix_v_val, rep(NA, n_cov))
fix_vec_full <- c(fix_vec, rep(FALSE, n_cov))
new_theta <- fix_v_val_full
new_theta[!fix_vec_full] <- theta
} else{
new_theta <- theta
}
if(model == "isoCov"){
if(log_scale){
sigma_e <- exp(new_theta[1])
theta_cov <- exp(new_theta[2:(length(new_theta)-n_cov)])
} else{
sigma_e <- new_theta[1]
theta_cov <- new_theta[2:(length(new_theta)-n_cov)]
}
} else{
if(log_scale){
sigma_e <- exp(new_theta[1])
reciprocal_tau <- exp(new_theta[2])
kappa <- exp(new_theta[3])
} else{
sigma_e <- new_theta[1]
reciprocal_tau <- new_theta[2]
kappa <- new_theta[3]
}
}
if(n_cov >0){
theta_covariates <- new_theta[(length(new_theta)-n_cov+1):length(new_theta)]
}
if(is.null(graph$Laplacian) && (model %in% c("GL1", "GL2"))) {
graph$compute_laplacian()
}
#build covariance matrix
switch(model,
WM1 = {
Q <- spde_precision(kappa = kappa, tau = 1/reciprocal_tau,
alpha = 1, graph = graph)
Sigma <- as.matrix(solve(Q))[graph$PtV, graph$PtV]
},
WM2 = {
PtE <- graph$get_PtE()
n.c <- 1:length(graph$CoB$S)
Q <- spde_precision(kappa = kappa, tau = 1/reciprocal_tau, alpha = 2,
graph = graph, BC = 1)
Qtilde <- (graph$CoB$T) %*% Q %*% t(graph$CoB$T)
Qtilde <- Qtilde[-n.c,-n.c]
Sigma.overdetermined = t(graph$CoB$T[-n.c,]) %*% solve(Qtilde) %*%
(graph$CoB$T[-n.c,])
index.obs <- 4 * (PtE[,1] - 1) + 1.0 * (abs(PtE[, 2]) < 1e-14) +
3.0 * (abs(PtE[, 2]) > 1e-14)
Sigma <- as.matrix(Sigma.overdetermined[index.obs, index.obs])
}, GL1 = {
Q <- (kappa^2 * Matrix::Diagonal(graph$nV, 1) + graph$Laplacian[[1]]) / reciprocal_tau^2
Sigma <- as.matrix(solve(Q))[graph$PtV, graph$PtV]
}, GL2 = {
Q <- kappa^2 * Matrix::Diagonal(graph$nV, 1) + graph$Laplacian[[1]]
Q <- Q %*% Q / reciprocal_tau^2
Sigma <- as.matrix(solve(Q))[graph$PtV, graph$PtV]
}, isoCov = {
if(is.null(cov_function)){
stop("If model is 'isoCov' the covariance function must be supplied!")
}
if(!is.function(cov_function)){
stop("'cov_function' must be a function!")
}
if(is.null(graph$res_dist)){
graph$compute_resdist(full = TRUE, check_euclidean = check_euclidean)
}
Sigma <- as.matrix(cov_function(as.matrix(graph$res_dist[[".complete"]]), theta_cov))
# nV <- nrow(graph$res_dist[[".complete"]]) - nrow(graph$get_PtE())
# Sigma <- Sigma[(nV+1):nrow(Sigma), (nV+1):nrow(Sigma)]
})
diag(Sigma) <- diag(Sigma) + sigma_e^2
loglik_val <- 0
repl_vec <- graph$.__enclos_env__$private$data[[".group"]]
if(is.null(repl)){
u_repl <- unique(graph$.__enclos_env__$private$data[[".group"]])
} else{
u_repl <- unique(repl)
}
for(repl_y in 1:length(u_repl)){
ind_tmp <- (repl_vec %in% u_repl[repl_y])
y_tmp <- y_graph[ind_tmp]
na_obs <- is.na(y_tmp)
Sigma_non_na <- Sigma[!na_obs, !na_obs]
R <- base::chol(Sigma_non_na)
v <- y_graph[graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y]]
if(!is.null(X_cov)){
n_cov <- ncol(X_cov)
if(n_cov == 0){
X_cov_repl <- 0
} else{
X_cov_repl <- X_cov[graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y], ,
drop=FALSE]
# v <- v - X_cov_repl %*% theta[4:(3+n_cov)]
v <- v - X_cov_repl %*% theta_covariates
}
}
v <- v[!na_obs]
loglik_val <- loglik_val + as.double(-sum(log(diag(R))) - 0.5*t(v)%*%solve(Sigma_non_na,v) -
length(v)*log(2*pi)/2)
}
if(maximize){
return(loglik_val)
} else{
return(-loglik_val)
}
}
}
#' Function factory for likelihood evaluation for the graph Laplacian model
#'
#' @param graph metric_graph object
#' @param alpha integer greater or equal to 1. Order of the equation.
#' @param covariates Logical. If `TRUE`, the model will be considered with
#' covariates. It requires `graph` to have covariates included by the method
#' `add_covariates()`.
#' @param log_scale Should the parameters `theta` of the returning function be
#' given in log-scale?
#' @param maximize If `FALSE` the function will return minus the likelihood, so
#' one can directly apply it to the `optim` function.
#' @return The log-likelihood function, which is returned as a function with
#' parameter 'theta'. The parameter `theta` must be supplied as
#' the vector `c(sigma_e, reciprocal_tau, kappa)`.
#'
#' If `covariates` is `TRUE`, then the parameter `theta` must be supplied as the
#' vector `c(sigma_e, reciprocal_tau, kappa, beta[1], ..., beta[p])`,
#' where `beta[1],...,beta[p]` are the coefficients and `p` is the number of
#' covariates.
#' @noRd
likelihood_graph_laplacian <- function(graph, alpha, y_graph, repl,
X_cov = NULL, maximize = FALSE, parameterization,
fix_vec = NULL, fix_v_val = NULL) {
check <- check_graph(graph)
if(alpha%%1 != 0){
stop("only integer values of alpha supported")
}
if(alpha<= 0){
stop("alpha must be positive!")
}
graph$compute_laplacian(full = FALSE)
# if(covariates){
# if(is.null(graph$covariates)){
# stop("If 'covariates' is set to TRUE, the graph must have covariates!")
# }
# }
loglik <- function(theta){
if(!is.null(X_cov)){
n_cov <- ncol(X_cov)
} else{
n_cov <- 0
}
if(!is.null(fix_v_val)){
# new_theta <- fix_v_val
fix_v_val_full <- c(fix_v_val, rep(NA, n_cov))
fix_vec_full <- c(fix_vec, rep(FALSE, n_cov))
new_theta <- fix_v_val_full
}
if(!is.null(fix_vec)){
new_theta[!fix_vec_full] <- theta
} else{
new_theta <- theta
}
repl_vec <- graph$.__enclos_env__$private$data[[".group"]]
if(is.null(repl)){
u_repl <- unique(graph$.__enclos_env__$private$data[[".group"]])
} else{
u_repl <- unique(repl)
}
sigma_e <- exp(new_theta[1])
reciprocal_tau <- exp(new_theta[2])
if(parameterization == "matern"){
kappa = sqrt(8 * (alpha-0.5)) / exp(new_theta[3])
} else{
kappa = exp(new_theta[3])
}
y_resp <- y_graph
l <- 0
A <- graph$.__enclos_env__$private$A(group = ".all", drop_all_na = FALSE, drop_na = FALSE)
u_repl <- unique(graph$.__enclos_env__$private$data[[".group"]])
for(repl_y in 1:length(u_repl)){
K <- kappa^2*Diagonal(graph$nV, 1) + graph$Laplacian[[u_repl[repl_y]]]
Q <- K
if (alpha>1) {
for (k in 2:alpha) {
Q <- Q %*% K
}
}
Q <- Q / reciprocal_tau^2
# R <- chol(Q)
R <- Matrix::Cholesky(Q)
v <- y_resp[graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y]]
na.obs <- is.na(v)
A.repl <- A[!na.obs, ]
v <- v[!na.obs]
n.o <- length(v)
Q.p <- Q + t(A.repl) %*% A.repl/sigma_e^2
# R.p <- chol(Q.p)
R.p <- Matrix::Cholesky(Q.p)
# l <- l + sum(log(diag(R))) - sum(log(diag(R.p))) - n.o*log(sigma_e)
l <- l + determinant(R, logarithm = TRUE, sqrt = TRUE)$modulus - determinant(R.p, logarithm = TRUE, sqrt=TRUE)$modulus - n.o * log(sigma_e)
if(!is.null(X_cov)){
n_cov <- ncol(X_cov)
if(n_cov == 0){
X_cov_repl <- 0
} else{
X_cov_repl <- X_cov[graph$.__enclos_env__$private$data[[".group"]] == u_repl[repl_y], , drop=FALSE]
X_cov_repl <- X_cov_repl[!na.obs, , drop = FALSE]
v <- v - X_cov_repl %*% new_theta[4:(3+n_cov)]
}
}
# mu.p <- solve(Q.p,as.vector(t(A.repl) %*% v / sigma_e^2))
mu.p <- solve(R.p, as.vector(t(A.repl) %*% v / sigma_e^2), system = "A")
v <- v - A.repl%*%mu.p
l <- l - 0.5*(t(mu.p)%*%Q%*%mu.p + t(v)%*%v/sigma_e^2) - 0.5 * n.o*log(2*pi)
}
if(maximize){
return(as.double(l))
} else{
return(-as.double(l))
}
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.