bridgeBIRTinf=function(object, niter,tol,silent){
fit=object$mcmc
z=object$z
model=object$model
z=as.matrix(z)
item.out=object$output
inflated=object$inflated

tau.samples=rstan::extract(fit,"theta")$theta
ti.samples=rstan::extract(fit,"beta")$beta
ln_phi.samples=log(rstan::extract(fit,"alpha")$alpha)
ln_sigma2.samples=log(rstan::extract(fit,"phi")$phi)
if(inflated=="zero" | inflated=="both") b0.samples=rstan::extract(fit,"gamma0")$gamma0 else b0.samples=NULL
if(inflated=="one" | inflated=="both") b1.samples=rstan::extract(fit,"gamma1")$gamma1 else b1.samples=NULL

N=nrow(z)
nit=ncol(z)
no_iter=nrow(tau.samples)


if(inflated=="zero" | inflated=="both"){
  if(inflated=="zero"){
    one_mask=rep(0,nit)
    one_mask_matrix=diag(0,nit)
  }
  zero_mask=1*(is.finite(item.out[,"gamma0"]))
  zero_mask_matrix=matrix(0,sum(zero_mask),nit)
  for(i in 1:nit){
    if(zero_mask[i]==1) zero_mask_matrix[sum(zero_mask[1:i]),i]=1
    if(zero_mask[i]==0) zero_mask_matrix[sum(zero_mask[1:i]),i]=0
  }
}

if(inflated=="one" | inflated=="both"){
  if(inflated=="one"){
    zero_mask=rep(0,nit)
    zero_mask_matrix=diag(0,nit)
  }
  one_mask=1*(is.finite(item.out[,"gamma1"]))
  one_mask_matrix=matrix(0,sum(one_mask),nit)
  for(i in 1:nit){
    if(one_mask[i]==1) one_mask_matrix[sum(one_mask[1:i]),i]=1
    if(one_mask[i]==0) one_mask_matrix[sum(one_mask[1:i]),i]=0
  }
}


tau.est=apply(tau.samples,2,mean)
ti.est=apply(ti.samples,2,mean)
ln_phi.est=apply(ln_phi.samples,2,mean)
ln_sigma2.est=apply(ln_sigma2.samples,2,mean)
if(inflated=="zero" | inflated=="both") b0.est=apply(b0.samples,2,mean)%*%zero_mask_matrix else b0.est=NULL
if(inflated=="one" | inflated=="both") b1.est=apply(b1.samples,2,mean)%*%one_mask_matrix else b1.est=NULL

b0.est[zero_mask==0]=-Inf
b1.est[one_mask==0]=Inf






###
n1=n2=floor(no_iter/2)

full.samples=cbind(tau.samples,ti.samples,ln_phi.samples,ln_sigma2.samples,b0.samples,b1.samples)
tau.ind=1:N
ti.ind=1:nit+N
ln_phi.ind=1:nit+N+nit
ln_sigma2.ind=1:nit+N+nit*2
if(inflated=="one") b0.ind=NULL else b0.ind=1:sum(zero_mask) + nit+N+nit*2
if(inflated=="zero") b1.ind=NULL else b1.ind=1:sum(one_mask) + nit+N+nit*2 + sum(zero_mask)

n_par=3*nit+sum(zero_mask)+sum(one_mask)

post.batch1=full.samples[1:n1,]
post.batch2=full.samples[(n1+1):(2*n1),]

propos.me.p=apply(post.batch1[,tau.ind],2,mean)
propos.me.i=apply(post.batch1[,(N+1):(max(c(b0.ind,b1.ind)))],2,mean)

propos.cov.p=diag(diag(stats::cov(post.batch1[,tau.ind])))
propos.cov.i=stats::cov(post.batch1[,(N+1):(max(c(b0.ind,b1.ind)))])

propos.samples.p=MASS::mvrnorm(n2,propos.me.p,propos.cov.p)
propos.samples.i=MASS::mvrnorm(n2,propos.me.i,propos.cov.i)

if(inflated=="both"){
  tmp_x=propos.samples.i[,b0.ind-N]%*%zero_mask_matrix
  tmp_x[,zero_mask==0]=-Inf
  tmp_y=propos.samples.i[,b1.ind-N]%*%one_mask_matrix
  tmp_y[,one_mask==0]=Inf

  error=which((tmp_y - tmp_x)<=0,arr.ind=T)[,1]
while(length(error>0)){
 propos.samples.i[error,]=MASS::mvrnorm(length(error),propos.me.i,propos.cov.i)
 tmp_x=propos.samples.i[,b1.ind-N]%*%zero_mask_matrix
 tmp_x[,zero_mask==0]=-Inf
 tmp_y=propos.samples.i[,b0.ind-N]%*%one_mask_matrix
 tmp_y[,one_mask==0]=Inf

 error=which((tmp_y - tmp_x)<=0,arr.ind=T)[,1]
}
}

propos.samples=cbind(propos.samples.p,propos.samples.i)

propos.me=c(propos.me.p,propos.me.i)
propos.cov=rbind(cbind(propos.cov.p,matrix(0,N,n_par)),cbind(matrix(0,n_par,N),propos.cov.i))

debug1=matrix(,n1,5)

dsimplex=function (y, m, s2){  #from rmutil by Swihart & Lindsey (2022) but with minor adjustment
  tmp <- -((y - m)/(m * (1 - m)))^2/(2 * y * (1 - y) * s2) -
    (log(2 * pi * s2) + 3 * (log(y) + log(1 - y)))/2
  return(exp(tmp))
}

log.l2=c()
if(!silent) cat("Stage 1/2:\n")
for(i in 1:n2){
  if(!silent) cat("processing proposal sample",i,"\r")
  tau.tmp2=propos.samples[i,tau.ind]
  ti.tmp2=propos.samples[i,ti.ind]
  ln_phi.tmp2=propos.samples[i,ln_phi.ind]
  ln_sigma2.tmp2=propos.samples[i,ln_sigma2.ind]
  if(inflated=="zero"|inflated=="both") b0.tmp2=propos.samples[i,b0.ind]%*%zero_mask_matrix else b0.tmp2=NULL
  if(inflated=="one"|inflated=="both") b1.tmp2=propos.samples[i,b1.ind]%*%one_mask_matrix else b1.tmp2=NULL

  b0.tmp2[zero_mask==0]=-Inf
  b1.tmp2[one_mask==0]=Inf

  ou5=ou1=ou2=ou3=ou4=c()
  for(p in 1:N){
    ind=which(z[p,]<1 & z[p,]>0 & z[p,]!=-999)
    tmp=c()
    if(model=="beta")
    tmp[ind] = stats::dbeta(z[p,ind],exp(.5*(exp(ln_phi.tmp2[ind])*tau.tmp2[p]+ti.tmp2[ind]+ln_sigma2.tmp2[ind])),exp(.5*(-exp(ln_phi.tmp2[ind])*tau.tmp2[p]-ti.tmp2[ind]+ln_sigma2.tmp2[ind])),log=T)
    if(model=="simplex")
    tmp[ind] = log(dsimplex(z[p,ind],m=1/(1+exp(-(ti.tmp2[ind]+exp(ln_phi.tmp2[ind])*tau.tmp2[p]))),s=exp(ln_sigma2.tmp2[ind])))
    if(model=="samejima")
    tmp[ind] = -log(z[p,ind])-log(1-z[p,ind])+stats::dnorm(stats::qlogis(z[p,ind]),ti.tmp2[ind]+exp(ln_phi.tmp2[ind])*tau.tmp2[p],exp(.5*ln_sigma2.tmp2[ind]),log=T)
    if(model=="normal")
    tmp[ind] = stats::dnorm(z[p,ind],ti.tmp2[ind]+exp(ln_phi.tmp2[ind])*tau.tmp2[p],exp(.5*ln_sigma2.tmp2[ind]),log=T)

    tmp[ind]=tmp[ind]+ log(  stats::plogis(b1.tmp2[ind]-exp(ln_phi.tmp2[ind])*tau.tmp2[p]) -  stats::plogis(b0.tmp2[ind]-exp(ln_phi.tmp2[ind])*tau.tmp2[p]))
    if(inflated=="zero"|inflated=="both"){
      ind=which(z[p,]==0)
      tmp[ind] =log( stats::plogis(b0.tmp2[ind]-exp(ln_phi.tmp2[ind])*tau.tmp2[p]))
    }
    if(inflated=="one"|inflated=="both"){
      ind=which(z[p,]==1)
      tmp[ind] =log( 1-stats::plogis(b1.tmp2[ind]-exp(ln_phi.tmp2[ind])*tau.tmp2[p]))
    }
    ou1[p]=sum(tmp[is.finite(tmp)],na.rm=T)
    ou4[p]=stats::dnorm(tau.tmp2[p],log=T)
  }
  ou2=sum(log(stats::dnorm(ln_phi.tmp2,0,10))+log(stats::dnorm(ln_sigma2.tmp2,0,10))+log(stats::dnorm(ti.tmp2,0,10))) + sum(log(stats::dnorm(b0.tmp2[zero_mask==1],0,10)))+sum(log(stats::dnorm(b1.tmp2[one_mask==1],0,10)/stats::pnorm(b0.tmp2[one_mask==1],0,10,low=F)))
  ou3=mvtnorm::dmvnorm(c(ti.tmp2,ln_phi.tmp2,ln_sigma2.tmp2,b0.tmp2[zero_mask==1],b1.tmp2[one_mask==1]),propos.me[-(1:N)][1:n_par],propos.cov[-(1:N),-(1:N)][1:(n_par),1:(n_par)],log=T)
  ou5=mvtnorm::dmvnorm(tau.tmp2,propos.me[1:N],propos.cov[(1:N),(1:N)],log=T)

  log.l2[i]=sum(ou1)+sum(ou4)+ou2 - (ou5+ou3)
  debug1[i,1:5]=c(sum(ou1),sum((ou4)),ou2, (ou5), (ou3))
}

log.l1=mll1=c()
llb=matrix(,N,n1)
if(!silent) cat("\nStage 2/2:\n")
for(i in 1:n1){
  if(!silent) cat("processing posterior sample",i,"\r")
  tau.tmp1=post.batch2[i,tau.ind]
  ti.tmp1=post.batch2[i,ti.ind]
  ln_phi.tmp1=post.batch2[i,ln_phi.ind]
  ln_sigma2.tmp1=post.batch2[i,ln_sigma2.ind]
  if(inflated=="zero"|inflated=="both") b0.tmp1=post.batch2[i,b0.ind]%*%zero_mask_matrix else b0.tmp1=NULL
  if(inflated=="one"|inflated=="both") b1.tmp1=post.batch2[i,b1.ind]%*%one_mask_matrix else b1.tmp1=NULL

  b0.tmp1[zero_mask==0]=-Inf
  b1.tmp1[one_mask==0]=Inf

  ou5=ou1=ou2=ou3=ou4=c()
   for(p in 1:N){
      ind=which(z[p,]<1 & z[p,]>0 & z[p,]!=-999)
      tmp=c()
      if(model=="beta")
      tmp[ind] = stats::dbeta(z[p,ind],exp(.5*(exp(ln_phi.tmp1[ind])*tau.tmp1[p]+ti.tmp1[ind]+ln_sigma2.tmp1[ind])),exp(.5*(-exp(ln_phi.tmp1[ind])*tau.tmp1[p]-ti.tmp1[ind]+ln_sigma2.tmp1[ind])),log=T)
      if(model=="simplex")
      tmp[ind] = log(dsimplex(z[p,ind],m=1/(1+exp(-(ti.tmp1[ind]+exp(ln_phi.tmp1[ind])*tau.tmp1[p]))),s=exp(ln_sigma2.tmp1[ind])))
      if(model=="samejima")
      tmp[ind] = -log(z[p,ind])-log(1-z[p,ind])+stats::dnorm(stats::qlogis(z[p,ind]),ti.tmp1[ind]+exp(ln_phi.tmp1[ind])*tau.tmp1[p],exp(.5*ln_sigma2.tmp1[ind]),log=T)
      if(model=="normal")
      tmp[ind] = stats::dnorm(z[p,ind],ti.tmp1[ind]+exp(ln_phi.tmp1[ind])*tau.tmp1[p],exp(.5*ln_sigma2.tmp1[ind]),log=T)

      tmp[ind]=tmp[ind]+ log(  stats::plogis(b1.tmp1[ind]-exp(ln_phi.tmp1[ind])*tau.tmp1[p]) -  stats::plogis(b0.tmp1[ind]-exp(ln_phi.tmp1[ind])*tau.tmp1[p]))
      if(inflated=="zero"|inflated=="both"){
        ind=which(z[p,]==0)
        tmp[ind] =log( stats::plogis(b0.tmp1[ind]-exp(ln_phi.tmp1[ind])*tau.tmp1[p]))
      }
      if(inflated=="one"|inflated=="both"){
        ind=which(z[p,]==1)
        tmp[ind] =log( 1-stats::plogis(b1.tmp1[ind]-exp(ln_phi.tmp1[ind])*tau.tmp1[p]))
      }
      ou1[p]=sum(tmp[is.finite(tmp)],na.rm=T)
      ou4[p]=stats::dnorm(tau.tmp1[p],log=T)
      llb[p,i]=ou1[p]
    }
    ou2=sum(log(stats::dnorm(ln_phi.tmp1,0,10)))+sum(log(stats::dnorm(ln_sigma2.tmp1,0,10))+log(stats::dnorm(ti.tmp1,0,10))) +sum(log(stats::dnorm(b0.tmp1[zero_mask==1],0,10)))+sum(log(stats::dnorm(b1.tmp1[one_mask==1],0,10)/stats::pnorm(b0.tmp1[one_mask==1],0,10,low=F)))
    ou3=mvtnorm::dmvnorm(c(ti.tmp1,ln_phi.tmp1,ln_sigma2.tmp1,b0.tmp1[zero_mask==1],b1.tmp1[one_mask==1]),propos.me[-(1:N)][1:(n_par)],propos.cov[-(1:N),-(1:N)][1:n_par,1:n_par],log=T)
    ou5=mvtnorm::dmvnorm(tau.tmp1,propos.me[1:N],propos.cov[(1:N),(1:N)],log=T)

  log.l1[i]=sum(ou1) + sum(ou4)+ou2 - (ou5+ou3)
  mll1[i]= sum(ou1) + sum(ou4)
}

r0=.2
r1=c()
r1[1]=0.1
l_star1=stats::median(log.l1)
it=1
while(abs(log(rev(r1)[1])-log(r0))>tol & it<niter){
  r1[it+1]= mean(exp(log.l2-l_star1) / (.5 * exp(log.l2-l_star1) + .5 * r1[it])) /  mean(1 / (.5 * exp(log.l1-l_star1) + .5 * r1[it]))
  r0=r1[it]
  it=it+1
}
if(it==niter) stop("Iterative scheme did not converge, increase niter or tol")

# This code can be used to calculate the conditional DIC and WAIC. However, it is generally not recommended to use these for latent variable
# models like those in boundIRT. See ?loglikBIRT for alternatives (marginal WAIC and LOOIC)
#
# ###########
# #DEVIANCE #
# ###########
# if(!silent) cat("\nStage 3/3 (DIC and WAIC):\n")
#
# lla=matrix(,N,n1)
# for(i in 1:n1){
#   if(!silent) cat("processing sample: ",i,"\r")
#   tau.tmp1=post.batch1[i,tau.ind]
#   ti.tmp1=post.batch1[i,ti.ind]
#   ln_phi.tmp1=post.batch1[i,ln_phi.ind]
#   ln_sigma2.tmp1=post.batch1[i,ln_sigma2.ind]
#   if(inflated=="zero"|inflated=="both") b0.tmp1=post.batch1[i,b0.ind]%*%zero_mask_matrix else b0.tmp1=NULL
#   if(inflated=="one"|inflated=="both") b1.tmp1=post.batch1[i,b1.ind]%*%one_mask_matrix else b1.tmp1=NULL
#
#   b0.tmp1[zero_mask==0]=-Inf
#   b1.tmp1[one_mask==0]=Inf
#
#   ou5=ou1=ou2=ou3=ou4=c()
#   for(p in 1:N){
#      ind=which(z[p,]<1 & z[p,]>0 & z[p,]!=-999)
#      tmp=c()
#      if(model=="beta")
#      tmp[ind] = stats::dbeta(z[p,ind],exp(.5*(exp(ln_phi.tmp1[ind])*tau.tmp1[p]+ti.tmp1[ind]+ln_sigma2.tmp1[ind])),exp(.5*(-exp(ln_phi.tmp1[ind])*tau.tmp1[p]-ti.tmp1[ind]+ln_sigma2.tmp1[ind])),log=T)
#      if(model=="simplex")
#      tmp[ind] = log(dsimplex(z[p,ind],m=1/(1+exp(-(ti.tmp1[ind]+exp(ln_phi.tmp1[ind])*tau.tmp1[p]))),s=exp(ln_sigma2.tmp1[ind])))
#      if(model=="samejima")
#      tmp[ind] = -log(z[p,ind])-log(1-z[p,ind])+stats::dnorm(stats::qlogis(z[p,ind]),ti.tmp1[ind]+exp(ln_phi.tmp1[ind])*tau.tmp1[p],exp(.5*ln_sigma2.tmp1[ind]),log=T)
#      if(model=="normal")
#      tmp[ind] = stats::dnorm(z[p,ind],ti.tmp1[ind]+exp(ln_phi.tmp1[ind])*tau.tmp1[p],exp(.5*ln_sigma2.tmp1[ind]),log=T)
#
#      tmp[ind]=tmp[ind]+ log(  stats::plogis(b1.tmp1[ind]-exp(ln_phi.tmp1[ind])*tau.tmp1[p]) -  stats::plogis(b0.tmp1[ind]-exp(ln_phi.tmp1[ind])*tau.tmp1[p]))
#      if(inflated=="zero"|inflated=="both"){
#        ind=which(z[p,]==0)
#        tmp[ind] =log( stats::plogis(b0.tmp1[ind]-exp(ln_phi.tmp1[ind])*tau.tmp1[p]))
#      }
#      if(inflated=="one"|inflated=="both"){
#        ind=which(z[p,]==1)
#        tmp[ind] =log( 1-stats::plogis(b1.tmp1[ind]-exp(ln_phi.tmp1[ind])*tau.tmp1[p]))
#      }
#      ou1[p]=sum(tmp[is.finite(tmp)],na.rm=T)
#      lla[p,i]=ou1[p]
#    }
# }
# dev.mean=c()
#   for(p in 1:N){
#      ind=which(z[p,]<1 & z[p,]>0 & z[p,]!=-999)
#      tmp=c()
#      if(model=="beta")
#      tmp[ind] = stats::dbeta(z[p,ind],exp(.5*(exp(ln_phi.est[ind])*tau.est[p]+ti.est[ind]+ln_sigma2.est[ind])),exp(.5*(-exp(ln_phi.est[ind])*tau.est[p]-ti.est[ind]+ln_sigma2.est[ind])),log=T)
#      if(model=="simplex")
#      tmp[ind] = log(dsimplex(z[p,ind],m=1/(1+exp(-(ti.est[ind]+exp(ln_phi.est[ind])*tau.est[p]))),s=exp(ln_sigma2.est[ind])))
#      if(model=="samejima")
#      tmp[ind] = -log(z[p,ind])-log(1-z[p,ind])+stats::dnorm(stats::qlogis(z[p,ind]),ti.est[ind]+exp(ln_phi.est[ind])*tau.est[p],exp(.5*ln_sigma2.est[ind]),log=T)
#      if(model=="normal")
#      tmp[ind] = stats::dnorm(z[p,ind],ti.est[ind]+exp(ln_phi.est[ind])*tau.est[p],exp(.5*ln_sigma2.est[ind]),log=T)
#
#      tmp[ind]=tmp[ind]+ log(  stats::plogis(b1.est[ind]-exp(ln_phi.est[ind])*tau.est[p]) -  stats::plogis(b0.est[ind]-exp(ln_phi.est[ind])*tau.est[p]))
#      if(inflated=="zero"|inflated=="both"){
#       ind=which(z[p,]==0)
#       tmp[ind] =log( stats::plogis(b0.est[ind]-exp(ln_phi.est[ind])*tau.est[p]))
#      }
#      if(inflated=="one"|inflated=="both"){
#       ind=which(z[p,]==1)
#       tmp[ind] =log( 1-stats::plogis(b1.est[ind]-exp(ln_phi.est[ind])*tau.est[p]))
#      }
#
#      dev.mean[p]=sum(tmp[is.finite(tmp)],na.rm=T)
#  }
 if(!silent) cat("\n")
# ll=cbind(lla,llb)
# DIC=2*mean(-2*apply(ll,2,sum))-sum(-2*dev.mean)
# WAIC = -2*sum(log(apply(exp(ll),1,mean))) + 2 * sum(apply(ll,1,stats::var))
return(list(r1=rev(r1)[1],l_star=l_star1))
}

