library(nimble); library(tmvtnorm)
## define multivariate probit function ----
mvprobit <- function(z, mu, sigma, log = 0){
lb <- z
ub <- z
lb[z == 0] <- -Inf
lb[z == 1] <- 0
ub[z == 0] <- 0
ub[z == 1] <- Inf
as.numeric(pmvnorm(mean = mu, sigma = sigma, lower = lb, upper = ub))
}
## nimble-ize mvprobit ----
nimble_mvprobit <-
nimbleRcall(prototype = function(z = double(1), mu = double(1),
sigma = double(2), log = integer(0, default = 0)){},
Rfun = 'mvprobit',
returnType = double(0))
## define multivariate bernoulli based on multivariate Gaussian ----
dmbern <- nimbleFunction(
run = function(x = double(1), mu = double(1), sigma = double(2),
log = integer(0, default = 0)) {
returnType(double(0))
Prob <- nimble_mvprobit(z = x, mu = mu, sigma = sigma, log = log)
if(log) return(log(Prob))
else return(Prob)
})
rmbern <- nimbleFunction(
run = function(n = integer(0, default = 1), mu = double(1), sigma = double(2)) {
returnType(double(1))
chol_mat <- chol(sigma)
latent <- rmnorm_chol(n = 1, mean = mu, cholesky = chol_mat, prec_param = F)
return(latent > 0)
})
## define the model ----
code <- nimbleCode({
## mixture probabilities + response distribution ----
mean[1:n_species] ~ dmnorm(mean = prior_mean[1:n_species],
prec = prior_prec[1:n_species, 1:n_species])
for(i in 1:n_observations){
z[i, 1:n_species] ~ dmbern(mu = means[1:n_species], sigma = cov[1:n_species, 1:n_species])
}
})
## constants + inits ----
n_observations <- 1e2
n_species <- 2
constants <- list(
n_observations = n_observations,
n_species = n_species,
prior_mean = rep(0, n_species),
prior_prec = diag(n_species),
cov = diag(n_species)
)
inits <- list(
mean = rep(0, n_species)
)
## nimbleModel ----
model <- nimbleModel(code = code, constants = constants, inits = inits)