mcmc.2sidetf <-
function(data,niter=2400,nburn=1200, nthin=5, M = 200, inits=inits,
swap=10,swap.tol=1,proppars=list(lam01=0.05,lam02=0.05,sigma=0.1,sx=0.2,sy=0.2),storeLatent=TRUE){
library(abind)
y.both<-data$both
y.left.obs<-data$left
y.right.obs<-data$right
if(length(dim(y.both))==3){
y.both=apply(y.both,c(1,2),sum)
}
if(length(dim(y.left.obs))==2){
stop("Must use 3D single side data with 2D trap file")
}
if(dim(y.right.obs)[1]>dim(y.left.obs)[1]){
storeL=y.left.obs
storeR=y.right.obs
dimL=dim(y.left.obs)
y.left.obs=array(0,dim=dim(y.right.obs))
y.right.obs=array(0,dim=dimL)
y.left.obs=storeR
y.right.obs=storeL
warning("Right side data set larger than left so I switched them for convenience")
}
if(!("tf"%in%names(data))){
stop("This function requires a 2D trap file. Tell Ben there is an error")
}
if(!is.matrix(data$tf)){
stop("This is the wrong function for a 2D trap file. Tell Ben something went wrong")
}
tf=data$tf
tf1=abind(tf,tf,along=0)
for(i in 3:M){
tf1=abind(tf1,tf,along=1)
}
tf2=rowSums(tf==2)
tf2=matrix(rep(tf2,M),nrow=M,byrow=TRUE)
X<-as.matrix(data$X)
J<-nrow(X)
K<- data$K
IDknown<- data$IDknown
Nfixed=length(IDknown)
nleft<-dim(y.left.obs)[1]-Nfixed
nright<-dim(y.right.obs)[1]-Nfixed
if("vertices"%in%names(data)){
vertices=data$vertices
useverts=TRUE
xlim=c(min(vertices[,1]),max(vertices[,1]))
ylim=c(min(vertices[,2]),max(vertices[,2]))
}else if("buff"%in%names(data)){
buff<- data$buff
xlim<- c(min(X[,1]),max(X[,1]))+c(-buff, buff)
ylim<- c(min(X[,2]),max(X[,2]))+c(-buff, buff)
vertices=rbind(xlim,ylim)
useverts=FALSE
}else{
stop("user must supply either 'buff' or 'vertices' in data object")
}
##pull out initial values
psi<- inits$psi
lam01<- inits$lam01
sigma<- inits$sigma
lam01<- inits$lam01
lam02<- inits$lam02
#Figure out what needs to be updated
uplam01=uplam02=upIDs=TRUE
if(lam01==0){
uplam01=FALSE
upIDs=FALSE
}
if(all(X[,3]==1)|lam02==0){
uplam02=FALSE
}
if(upIDs==TRUE&(nleft==0&nright==0)){ #not sure what will happen if we only have left only or right only
upIDs=FALSE
}
#augment 3 data sets
y.both<- abind(y.both,array(0, dim=c( M-dim(y.both)[1],J)), along=1)
y.left.obs<- abind(y.left.obs,array(0, dim=c( M-dim(y.left.obs)[1],J,K)), along=1)
y.right.obs<-abind(y.right.obs,array(0,dim=c( M-dim(y.right.obs)[1],J,K)), along=1)
#sort to minimize distance between initial matches. Skip if no single sides.
# if(nleft>0|nright>0){
if(nleft>0&nright>0){ #change 1/14/19
y.left.tmp=apply(y.left.obs,c(1,2),sum)
y.right.tmp=apply(y.right.obs,c(1,2),sum)
IDs<- LRmatch(M=M,left=y.left.tmp, nleft=nleft, right=y.right.tmp, nright=nright, X, Nfixed=Nfixed)
#Add unused augmented indivuals back in
notusedL<- (1:M)[is.na(match(1:M,IDs$ID_L))]
ID_L<-c(IDs$ID_L,notusedL)
notusedR<- (1:M)[is.na(match(1:M,IDs$ID_R))]
ID_R<-c(IDs$ID_R,notusedR)
}else{
ID_R=ID_L=1:M
}
#reoder left and right possibly true data sets
y.left.true<- y.left.obs[order(ID_L),,]
y.right.true<- y.right.obs[order(ID_R),,]
#Make initial complete data set
tmpdata<- y.both + apply(y.left.true+y.right.true,c(1,2),sum)
z=1*(apply(tmpdata,1,sum)>0)
z[sample(which(z==0),sum(z==0)*psi)]=1 #switch some uncaptured z's to 1.
#Optimize starting locations given where they are trapped.
s<- cbind(runif(M,xlim[1],xlim[2]), runif(M,ylim[1],ylim[2])) #assign random locations
idx=which(rowSums(tmpdata)>0) #switch for those actually caught
for(i in idx){
trps<- X[tmpdata[i,]>0,1:2]
trps<-matrix(trps,ncol=2,byrow=FALSE)
s[i,]<- c(mean(trps[,1]),mean(trps[,2]))
}
if(useverts==TRUE){
inside=rep(NA,nrow(s))
for(i in 1:nrow(s)){
inside[i]=inout(s[i,],vertices)
}
idx=which(inside==FALSE)
if(length(idx)>0){
for(i in 1:length(idx)){
while(inside[idx[i]]==FALSE){
s[idx[i],]=c(runif(1,xlim[1],xlim[2]), runif(1,ylim[1],ylim[2]))
inside[idx[i]]=inout(s[idx[i],],vertices)
}
}
}
}
known.vector<- c( rep(1,Nfixed), rep(0, M-Nfixed) )
# some objects to hold the MCMC simulation output
nstore=(niter-nburn)/nthin
if(nburn%%nthin!=0){
nstore=nstore+1
}
out<-matrix(NA,nrow=nstore,ncol=4)
dimnames(out)<-list(NULL,c("lam01","lam02","sigma","N"))
if(storeLatent){
sxout<- syout<- zout<- ID_Lout<- ID_Rout<-matrix(NA,nrow=nstore,ncol=M)
}
idx=1 #for storing output not recorded every iteration
D<- e2dist(s, X)
lamd1<- lam01*exp(-D*D/(2*sigma*sigma))
lamd2<- lam02*exp(-D*D/(2*sigma*sigma))
pd1=1-exp(-lamd1)
pd12=2*pd1-pd1*pd1
pd2=1-exp(-lamd2)
lamd1.cand=lamd1
lamd2.cand=lamd2
pd1.cand=pd1
pd2.cand=pd2
zero.guys<- apply(y.both,1,sum)+apply(y.left.true + y.right.true ,1,sum) == 0
ones=1*(tf1==1)
twos=1*(tf1==2)
sumones=apply(ones,c(1,2),sum)
sumtwos=apply(twos,c(1,2),sum)
ll.y.both=dbinom(y.both,tf2,z*pd2,log=TRUE)
ll.y.left=dbinom(y.left.true*ones,ones,z*pd1,log=TRUE)+
dbinom(y.left.true*twos,twos,z*pd12,log=TRUE)
ll.y.right=dbinom(y.right.true*ones,ones,z*pd1,log=TRUE)+
dbinom(y.right.true*twos,twos,z*pd12,log=TRUE)
if(!is.finite(sum(ll.y.both)))stop("Both side likelihood not finite. Make sure all camera stations recording both side captures have 2 cameras. Then try changing lam02 or sigma inits.")
if(!is.finite(sum(ll.y.left)))stop("Left side likelihood not finite. Try changing lam01 or sigma inits.")
if(!is.finite(sum(ll.y.right)))stop("right side likelihood not finite. Try changing lam01 or sigma inits.")
ll.y.both.cand=ll.y.both
ll.y.left.cand=ll.y.left
ll.y.right.cand=ll.y.right
for(iter in 1:niter){
#Update lam01
lly1sum=sum(ll.y.left)+sum(ll.y.right)
if(uplam01){
lam01.cand<- rnorm(1,lam01,proppars$lam01)
if(lam01.cand > 0){
lamd1.cand<- lam01.cand*exp(-D*D/(2*sigma*sigma))
pd1.cand=1-exp(-lamd1.cand)
pd12.cand=2*pd1.cand-pd1.cand*pd1.cand
ll.y.left.cand=dbinom(y.left.true*ones,ones,z*pd1.cand,log=TRUE)+
dbinom(y.left.true*twos,twos,z*pd12.cand,log=TRUE)
ll.y.right.cand=dbinom(y.right.true*ones,ones,z*pd1.cand,log=TRUE)+
dbinom(y.right.true*twos,twos,z*pd12.cand,log=TRUE)
lly1candsum=sum(ll.y.left.cand)+sum(ll.y.right.cand)
if(runif(1) < exp(lly1candsum - lly1sum)){
lam01=lam01.cand
lamd1=lamd1.cand
pd1=pd1.cand
pd12=pd12.cand
ll.y.left=ll.y.left.cand
ll.y.right=ll.y.right.cand
lly1sum=lly1candsum
}
}
}
#Update lam02
lly2sum=sum(ll.y.both)
if(uplam02){
lam02.cand<- rnorm(1,lam02,proppars$lam02)
if(lam02.cand > 0){
lamd2.cand<- lam02.cand*exp(-D*D/(2*sigma*sigma))
pd2.cand=1-exp(-lamd2.cand)
ll.y.both.cand <- dbinom(y.both,tf2,z*pd2.cand,log=TRUE)
lly2candsum=sum(ll.y.both.cand)
if(runif(1) < exp(lly2candsum-lly2sum)){
lam02=lam02.cand
lamd2=lamd2.cand
pd2=pd2.cand
ll.y.both=ll.y.both.cand
lly2sum=lly2candsum
}
}
}
#Update sigma
sigma.cand<- rnorm(1,sigma,proppars$sigma)
if(sigma.cand > 0){
lamd1.cand<- lam01*exp(-D*D/(2*sigma.cand*sigma.cand))
lamd2.cand<- lam02*exp(-D*D/(2*sigma.cand*sigma.cand))
pd1.cand=1-exp(-lamd1.cand)
pd2.cand=1-exp(-lamd2.cand)
pd12.cand=2*pd1.cand-pd1.cand*pd1.cand
ll.y.left.cand=dbinom(y.left.true*ones,ones,z*pd1.cand,log=TRUE)+
dbinom(y.left.true*twos,twos,z*pd12.cand,log=TRUE)
ll.y.right.cand=dbinom(y.right.true*ones,ones,z*pd1.cand,log=TRUE)+
dbinom(y.right.true*twos,twos,z*pd12.cand,log=TRUE)
lly1candsum=sum(ll.y.left.cand)+sum(ll.y.right.cand)
ll.y.both.cand <- dbinom(y.both,tf2,z*pd2.cand,log=TRUE)
lly2candsum=sum(ll.y.both.cand)
if(runif(1) < exp((lly1candsum+lly2candsum) -(lly1sum+lly2sum))){
sigma<- sigma.cand
lamd1=lamd1.cand
lamd2=lamd2.cand
pd1=pd1.cand
pd12=pd12.cand
pd2=pd2.cand
ll.y.both=ll.y.both.cand
ll.y.left=ll.y.left.cand
ll.y.right=ll.y.right.cand
}
}
## Update latent ID variables
## Candidate: swap IDs of one guy with some other guy. The two guys to be swapped are
## chosen randomly from the z=1 guys
if(any(z[!zero.guys]==0)){
cat("some z = 0!",fill=TRUE)
browser()
}
#Swap left guys first
if(nleft>0){
# User inputs how many swaps to make on each iteration my specifying "swap"
#map lefts to boths
#candmap used to remove disallowed candidates.NA any lefts that map back to z=0 indices and boths that are z=0 indices
map=cbind(1:M,ID_L)
candmap=map
candmap[1:Nfixed,]=NA #Don't swap out IDknown guys
candmap[z==0,1]=NA #Don't swap in z=0 guys.
candmap[candmap[,2]%in%which(z==0),2]=NA #Don't choose a guy1 that will make you swap in a z=0 guy
#These are the guys that can come out and go in
OUTcands=which(!is.na(candmap[,2]))
INcands=which(!is.na(candmap[,1]))
for(up in 1:swap){
### In this code here "guy1" and "guy2" are indexing "left-side encounter histories" whereas
### "s.swap.in" and "s.swap.out" are indexing (both-side guys, s, z)
guy1<- sample(OUTcands, 1)
s.swap.out<- map[guy1,2]
# to find candidates for swapping look in vicinity of it's current both side membership
dv<- sqrt( (s[s.swap.out,1]- s[INcands,1])^2 + (s[s.swap.out,2] - s[INcands,2])^2 )
## This is a list of both side activity centers that could be assinged to the right side guy
## under consideration based on how far away they are. swap.tol is the spatial tolerance
# if no one around, code swaps guy 1 with guy 1 (no swap, but does calculations)
possible<- INcands[dv < swap.tol]
jump.probability<- 1/length(possible) # h(theta*|theta)
# this is a particular value of s to swap for guy1.id
if(length(possible)>1){
s.swap.in <- sample( possible, 1)
}
if(length(possible) ==1){
s.swap.in <- possible
}
if(length(possible)==0) next #no guys close enough to swap
#compute h(theta|theta*)
trash<- sqrt( (s[s.swap.in,1]- s[INcands,1])^2 + (s[s.swap.in,2] - s[INcands,2])^2 )
trash<- INcands[trash < swap.tol]
jump.back<- 1/length(trash)
## Which left encounter history is currently associated with both guy s.swap.in?
guy2<- which(map[,2]==s.swap.in)
if(guy1==guy2) next #Same guy selected
newID<-ID_L
newID[guy1]<- s.swap.in
newID[guy2]<- s.swap.out
## recompute 'data' and compute likelihood components for swapped guys only
y.left.tmp<- y.left.obs[order(newID),,]#Reorder observed left side data set
swapped=c(s.swap.out,s.swap.in)
ll.y.left.tmp=dbinom(y.left.tmp[swapped,,]*ones[swapped,,],ones[swapped,,],pd1[swapped,],log=TRUE)+
dbinom(y.left.tmp[swapped,,]*twos[swapped,,],twos[swapped,,],pd12[swapped,],log=TRUE)
#MH step
if(runif(1)<exp(sum(ll.y.left.tmp)-sum(ll.y.left[swapped,,]))*(jump.back/jump.probability) ){
y.left.true=y.left.tmp #update left data
ll.y.left[swapped,,]=ll.y.left.tmp
ID_L<-newID #update data order
map[c(guy1,guy2),2]=c(s.swap.in,s.swap.out)
zero.guys<- apply(y.both,1,sum)+apply(y.left.true + y.right.true ,1,sum) == 0
if( sum(y.both[guy1,] + y.left.tmp[guy1,,] )>0 & z[guy1]==0){
cat("error on guy1",fill=TRUE)
browser()
}
if( sum(y.both[guy2,] + y.left.tmp[guy2,,] )>0 & z[guy2]==0){
cat("error on guy2",fill=TRUE)
browser()
}
}
}
#Do any captured guys have z==0?
if(any(z[!zero.guys]==0)){
cat("coming out of ID_L update: some z = 0!",fill=TRUE)
browser()
}
}
#Repeat for rights
if(nright>0){
#Reuse left side of maps
map[,2]=candmap[,2]=ID_R
candmap[1:Nfixed,2]=NA
candmap[candmap[,2]%in%which(z==0),2]=NA
OUTcands=which(!is.na(candmap[,2])) #INcands the same
for(up in 1:swap){
### In this code here "guy1" and "guy2" are indexing "right-side encounter histories" whereas
### "s.swap.in" and "s.swap.out" are indexing (both-side guys, s, z)
guy1<- sample(OUTcands, 1)
s.swap.out<- map[guy1,2]
# to find candidates for swapping look in vicinity of it's current both side membership
dv<- sqrt( (s[s.swap.out,1]- s[INcands,1])^2 + (s[s.swap.out,2] - s[INcands,2])^2 )
## This is a list of both side activity centers that could be assinged to the right side guy
## under consideration based on how far away they are. swap.tol is the spatial tolerance
possible<- INcands[dv < swap.tol]
jump.probability<- 1/length(possible) # h(theta*|theta)
# this is a particular value of s to swap for guy1.id
if(length(possible)>1){
s.swap.in <- sample( possible, 1)
}
if(length(possible) ==1){
s.swap.in <- possible
}
if(length(possible)==0) next #no guys close enough to swap
#compute h(theta|theta*)
trash<- sqrt( (s[s.swap.in,1]- s[INcands,1])^2 + (s[s.swap.in,2] - s[INcands,2])^2 )
trash<- INcands[trash < swap.tol]
jump.back<- 1/length(trash)
## Which right encounter history is currently associated with both guy s.swap.in?
guy2<- which(map[,2]==s.swap.in)
if(guy1==guy2) next #Same guy selected
newID<-ID_R
newID[guy1]<- s.swap.in
newID[guy2]<- s.swap.out
## recompute 'data' and compute likelihood components for swapped guys only
y.right.tmp<- y.right.obs[order(newID),,]#Reorder observed right side data set
swapped=c(s.swap.out,s.swap.in)
ll.y.right.tmp=dbinom(y.right.tmp[swapped,,]*ones[swapped,,],ones[swapped,,],pd1[swapped,],log=TRUE)+
dbinom(y.right.tmp[swapped,,]*twos[swapped,,],twos[swapped,,],pd12[swapped,],log=TRUE)
#MH step
if(runif(1)<exp(sum(ll.y.right.tmp)-sum(ll.y.right[swapped,,]))*(jump.back/jump.probability) ){
y.right.true=y.right.tmp #update right data
ll.y.right[swapped,,]=ll.y.right.tmp
ID_R<-newID #update data order
map[c(guy1,guy2),2]=c(s.swap.in,s.swap.out)
zero.guys<- apply(y.both,1,sum)+apply(y.left.true + y.right.true ,1,sum) == 0
if( sum(y.both[guy1,] + y.right.tmp[guy1,,] )>0 & z[guy1]==0){
cat("error on guy1",fill=TRUE)
browser()
}
if( sum(y.both[guy2,] + y.right.tmp[guy2,,] )>0 & z[guy2]==0){
cat("error on guy2",fill=TRUE)
browser()
}
}
}
#Do any captured guys have z==0?
if(any(z[!zero.guys]==0)){
cat("coming out of ID_R update: some z = 0!",fill=TRUE)
browser()
}
}
#Update psi gibbs
## probability of not being captured in a trap AT ALL
pbar1=(1-pd1)^(2*sumones)*(1-pd12)^(2*sumtwos) #can be a left or a right
pbar2=(1-pd2)^tf2
pbar0=pbar1*pbar2
prob0<- exp(rowSums(log(pbar0)))
fc<- prob0*psi/(prob0*psi + 1-psi)
z[zero.guys & known.vector==0]<- rbinom(sum(zero.guys & (known.vector ==0) ), 1, fc[zero.guys & (known.vector==0) ])
#update observation model ll
ll.y.both=dbinom(y.both,tf2,z*pd2,log=TRUE)
ll.y.left=dbinom(y.left.true*ones,ones,z*pd1,log=TRUE)+
dbinom(y.left.true*twos,twos,z*pd12,log=TRUE)
ll.y.right=dbinom(y.right.true*ones,ones,z*pd1,log=TRUE)+
dbinom(y.right.true*twos,twos,z*pd12,log=TRUE)
psi <- rbeta(1, 1 + sum(z), 1 + M - sum(z))
# ## Now we have to update the activity centers
for (i in 1:M) {
Scand <- c(rnorm(1, s[i, 1], proppars$sx), rnorm(1, s[i, 2], proppars$sy))
if(useverts==FALSE){
inbox <- Scand[1] < xlim[2] & Scand[1] > xlim[1] & Scand[2] < ylim[2] & Scand[2] > ylim[1]
}else{
inbox=inout(Scand,vertices)
}
if (inbox) {
dtmp <- sqrt((Scand[1] - X[, 1])^2 + (Scand[2] - X[, 2])^2)
lamd1.cand[i,]=lam01*exp(-dtmp*dtmp/(2*sigma*sigma))
lamd2.cand[i,]=lam02*exp(-dtmp*dtmp/(2*sigma*sigma))
pd1.cand[i,]=1-exp(-lamd1.cand[i,])
pd12.cand[i,]=2*pd1.cand[i,]-pd1.cand[i,]*pd1.cand[i,]
pd2.cand[i,]=1-exp(-lamd2.cand[i,])
ll.y.both.cand[i,]=dbinom(y.both[i,],tf2[i,],z[i]*pd2.cand[i,],log=TRUE)
ll.y.left.cand[i,,]=dbinom(y.left.true[i,,]*ones[i,,],ones[i,,],z[i]*pd1.cand[i,],log=TRUE)+
dbinom(y.left.true[i,,]*twos[i,,],twos[i,,],z[i]*pd12.cand[i,],log=TRUE)
ll.y.right.cand[i,,]=dbinom(y.right.true[i,,]*ones[i,,],ones[i,,],z[i]*pd1.cand[i,],log=TRUE)+
dbinom(y.right.true[i,,]*twos[i,,],twos[i,,],z[i]*pd12.cand[i,],log=TRUE)
llysum=(sum(ll.y.both[i,])+sum(ll.y.left[i,,])+sum(ll.y.right[i,,]))
llycandsum=(sum(ll.y.both.cand[i,])+sum(ll.y.left.cand[i,,])+sum(ll.y.right.cand[i,,]))
if (runif(1) < exp(llycandsum-llysum)) {
s[i, ]=Scand
D[i, ]=dtmp
lamd1[i, ]=lamd1.cand[i,]
lamd2[i, ]=lamd2.cand[i,]
pd1[i,]=pd1.cand[i,]
pd12[i,]=pd12.cand[i,]
pd2[i,]=pd2.cand[i,]
ll.y.both[i,]=ll.y.both.cand[i,]
ll.y.left[i,,]=ll.y.left.cand[i,,]
ll.y.right[i,,]=ll.y.right.cand[i,,]
}
}
}
#Do we record output on this iteration?
if(iter>nburn&iter%%nthin==0){
if(storeLatent){
sxout[idx,]<- s[,1]
syout[idx,]<- s[,2]
zout[idx,]<- z
ID_Lout[idx,]<-ID_L
ID_Rout[idx,]<-ID_R
}
out[idx,]<- c(lam01,lam02,sigma ,sum(z))
idx=idx+1
}
} # end of MCMC algorithm
if(storeLatent==TRUE){
list(out=out, sxout=sxout, syout=syout, zout=zout, ID_Lout=ID_Lout,ID_Rout=ID_Rout)
}else{
list(out=out)
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.