--
You received this message because you are subscribed to the Google Groups "nimble-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nimble-users...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/nimble-users/cae583c4-7a68-404b-ace9-b229ec070d96n%40googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/nimble-users/5c66275e-2a12-4d4b-8cb9-9908640b9395n%40googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/nimble-users/CA%2B7Ts_qnbJsNowtJKBQRN%2BKN0aBj-2oKEN3S%2BBAu46wmEUvBBQ%40mail.gmail.com.
Thanks Perry and Chris. Those were both helpful suggestions that I have a tried to incorporate into the reprex below. I don't seem to be referencing the individual M and K nodes correctly within the target block c("M[i]","K[i]"). I have tried a couple of approaches but get error messages such as " Problem accessing node or variable ... " or similar messages.
library(nimble)
rm(list = ls())
##------------------
# simulate restaurant customers and occupied tables
set.seed(123456)
S<-100
M <- K <- m <- vector(length=S) # containers for total customers and total occup tables
r <- 5
p <- 0.5
alpha <- 5
beta0 <-2
beta1 <--1
beta2<-1
covar1<-rnorm(S)
covar2<-rnorm(S)
lambda<-exp(beta0+beta1*covar1+beta2*covar2)
rlambda <- r/lambda # rate of the dgamma, scale would be mu/r
glambda <- rgamma(S, shape=r, rate=rlambda) # shape, rate parameterization
# populate M and K at each restaurant
for(i in 1:S){
M[i] <- rpois(1,glambda[i])
m[i] <- rbinom(1,M[i],p)
if(M[i]==0){
K[i]<-0
}
else{
z<-rCRP(1,size=M[i],conc=alpha)
K[i]<-max(z) # largest table assignment is total occupied tables
}
}
# poke holes in data
#M<-replace(M,sample(S,20),NA)
#K<-replace(K,sample(S,20),NA)
##-------------------
#helper functions and tables
## two-term log-sum-exp
logspace_add <- function(logx, logy) {
if (is.infinite(logx)) return(logy)
if (is.infinite(logy)) return(logx)
if (logy > logx) {
tmp <- logx
logx <- logy
logy <- tmp
}
logx + log1p(exp(logy - logx))
}
## unsigned Stirling numbers,first kind
## trianglular matrix with rows and columns from 0 to Nmax
build_logStirling1 <- function(Nmax) {
out <- matrix(-Inf, nrow = Nmax + 1, ncol = Nmax + 1)
# special case
out[1, 1] <- 0
## n = 1 is a special case: strirling number
out[2, 2] <- 0
## populate matrix
for (n in 2:Nmax) { # real n ≥ 2
## ---- k = 1 column: S₁(n,1) = (n-1)! ---------------------
out[n + 1, 2] <- lgamma(n)
## ---- k ≥ 2 -----------------------------------------------
for (k in 2:n) {
a <- out[n,k] # (n-1, k-1)
b <- log(n - 1) + out[n,k + 1] # (n-1)*first stirling of (n-1, k)
out[n + 1, k + 1] <- logspace_add(a, b)
}
}
out
}
## build
digits <- 3*max(M,na.rm=T) + 1 # upper limit on potential M
# Precompute logStirling numbers of 1st kind up to potential max M
logStirling1 <- build_logStirling1(digits)
## check
print(round(exp(logStirling1[1:5, 1:5])))
# make nimble data and constants lists
constants <- list(S=S,
digits = digits,
logStirling1=logStirling1,
covar1=covar1,
covar2=covar2
)
str(constants)
data <- list(ones_M = rep(1,S),
m=m)
str(data)
##---------------------------------
## nimble model
code <- nimbleCode({
# Priors\
beta0 ~ dnorm(0,sd=10)
beta1 ~ dnorm(0,sd=10)
beta2 ~ dnorm(0,sd=10)
alpha ~ dbeta(0.01,0.01)
r ~ dbeta(0.01,0.01)
p <- 0.5
# site loop for things that don't vary over time
for(s in 1:S){
log(lambda[s])<- beta0 + beta1 *covar1[s] + beta2 * covar2[s]
rlambda[s] <- r/lambda[s] # rate of the dgamma, scale would be mu/r
glambda[s] ~ dgamma(shape=r, rate=rlambda[s]) # shape, rate parameterization,
#problambda[s] <- r/(r+(lambda[s]*site_area[s]))
M[s] ~ dpois(glambda[s])
m[s] ~ dbinom(size=M[s],prob=p)
ones_M[s] ~ dconstraint(M[s]>=K[s] & M[s]<digits)
K[s] ~ dAntoniakCRP(M=M[s], alpha=alpha,logStirling1[1:digits,1:digits])
}
})
##------------housekeeping
deregisterDistributions(c("dAntoniakCRP"))
##-----------------------
# Antoniak (CRP table-count) pmf
dAntoniakCRP <- nimbleFunction(
run = function(x = integer(0), M = integer(0), alpha = double(0), logStirling1=double(2),log = integer(0, default=0)){
returnType(double(0))
# Special case: empty site
if (M == 0) {
if (x == 0) { # P(K=0 | M=0) = 1
if (log) return(0.0) else return(1.0)
} else {
if (log) return(-Inf) else return(0.0)
}
}
if(x<1|x>M) { if(log) return(-Inf) else return(0.0) }
# log S(M,x) at [M+1,x+1]
logS <- logStirling1[M+1, x+1]
logp<- logS + x*log(alpha) + lgamma(alpha) - lgamma(alpha+M)
if(log) return(logp) else return(exp(logp))
}
)
# registering necessary to use slice sampler on K
registerDistributions(list(
dAntoniakCRP = list(
BUGSdist = "dAntoniakCRP(M, alpha, logStirling1)",
types = c('value = integer(0)','M=integer(0)','alpha = double(0)', 'logStirling1=double(2)'),
discrete=T
)
))
##-----------------------------
## custom simultaneous sampler of M (total customsers) and K (occupied tables)
customMKsampler <- nimbleFunction(
contains = sampler_BASE,
setup = function(model, mvSaved, target, control) {
calcNodes <- model$getDependencies(target)
},
run = function(){
# initial model logProb
model_lp_initial <- getLogProb(model, calcNodes)
# current values for number of customers (M) and occupied tables (K) at the target restaurant
#Mi <- (target)[1]
#Ki <- (target)[2]
#current_M <- model[[Mi]]
#current_K <- model[[Ki]]
mNode<-model$getNodeNames(target[1])
kNode<-model$getNodeNames(target[2])
# create a random step up or down by one for K and M
Mstep<--1+rbinom(1,1,0.5)*2
Kstep<--1+rbinom(1,1,0.5)*2
if(model[[mNode]]==0){ # unstick from 0
proposed_K<-1
proposed_M<-1
}
if (model[[mNode]] + Mstep==0){ # if proposed M steps into 0, then K must also be 0
proposed_M<-0
proposed_K<-0
}
if (model[[kNode]]+Kstep==0){ #if proposed K steps into 0, then M must also become 0
proposed_M<-0
proposed_K<-0
}
if ((model[[kNode]]+Kstep)>(model[[mNode]]+Mstep)){ # if proposed K is bigger than proposed M, then set equal
proposed_M<-proposed_K<-current_M+Mstep
}
model[[target]] <<- c(proposed_M,proposed_K)
# proposal model logProb
model_lp_proposed <- model$calculate(calcNodes)
# log-Metropolis-Hastings ratio
log_MH_ratio <- model_lp_proposed - model_lp_initial
# Metropolis-Hastings step: determine whether or
# not to accept the newly proposed value
u <- runif(1, 0, 1)
if(u < exp(log_MH_ratio)) jump <- TRUE
else jump <- FALSE
# keep the model and mvSaved objects consistent
if(jump) copy(from = model, to = mvSaved, row = 1,
nodes = calcNodes, logProb = TRUE)
else copy(from = mvSaved, to = model, row = 1,
nodes = calcNodes, logProb = TRUE)
},
methods = list(reset = function(){})
)
##--------------------------
## initial values
## missing values for missing K (occupied tables) must be less than or equal to corresponding non-missing M (number of customers), unless M=1 or M=0 in which case K=1 and K=0, respectively.
Minits<-replace(replace(M,is.na(M),K[is.na(M)]),!is.na(M),NA) #replace missing M with K
Kinits<-replace(replace(K,is.na(K),M[is.na(K)]),!is.na(K),NA) # replace missing K with M
#handle cases where both M and K are missing
bothmissing <- is.na(M)&is.na(K)
Kinits[bothmissing]<-Minits[bothmissing]<-1
inits<-list(r = 5,
alpha = 5,
beta0 =2,
beta1 =-1,
beta2=1,
M=data$m+1,
K=data$m+1)
##--------------------
## build
model <- nimbleModel(code, constants, data, inits)
#model$initializeInfo()
#
conf <- configureMCMC(model, monitors = c(
"r","alpha","beta0","beta1","beta2",
"M","K"
))
cmodel<- compileNimble(model,resetFunctions = T)
conf <- configureMCMC(cmodel, monitors=c(
"r","alpha","beta0","beta1","beta2",
"M","K"
))
conf$printSamplers()
# replace independent slice sampler for each M and K pair
for (i in 1:constants$S) {
conf$removeSamplers(paste0("M[", i, "]"))
conf$removeSamplers(paste0("K[", i, "]"))
conf$addSampler(
target = c(paste0("M[", i, "]"), paste0("K[", i, "]")),
type = "customMKsampler"
)
}
conf$printSamplers()
cmcmc<- buildMCMC(conf)
cmcmc<- compileNimble(cmcmc, project=cmodel,showCompilerOutput = T)
samples <- runMCMC(cmcmc, niter=11000, nburnin=1000,thin=5)
library(MCMCvis)
MCMCsummary(samples, params =
"r","alpha","beta0","beta1","beta2",
"M","K")
To view this discussion visit https://groups.google.com/d/msgid/nimble-users/c82a7de4-d39b-4f30-a3aa-cf0bc2cd8f27n%40googlegroups.com.