#############################################
# Make batch file with different index
# idx1: causal percent, look at Parameters.r for
#       Causal_percent.A <- c(0.05, 0.10, 0.15)
#       Causal_percent   <- Causal_percent.A[idx1]
# So: idx1 = 1 implies causal percent = 0.05
#     idx1 = 2 implies causal percent = 0.10
#     idx1 = 3 implies causal percent = 0.15
############################################
# idx2 : region size,  look at Parameters.r for
# Range.A  <- c(3000, 6000, 9000, 12000, 15000, 18000, 21000, 24000, 27000, 30000)
# Region_L <- Range.A[idx2]
# So: idx2 = 1 implies Region_L = 3k
###########################################
# idx3 : sample size, in loop
#######################################################
# idx4 : % of negative betas, look at Parameters.r for
# Beta1.Sign.A <- c(0, 0.2, 0.5)  # % of betas with negative sign
# Beta1.Sign <- Beta1.Sign.A[idx4]
# So: idx4 = 1 implies Beta1.Sign = 0
#     idx4 = 2 implies Beta1.Sign = 0.2
#     idx4 = 3 implies Beta1.Sign = 0.5
###################################################################
# idx5: upper limit of rare variant freq, look at Parameters.r for
#    CutOff.A <- c(0.03, 0.04, 0.05, 0.06)
#    CutOff   <- CutOff.A [idx5]
# So idx5 = 1 implies CutOff = 0.03 used in the papers of Lin et al.
#    idx5 = 2 implies CutOff = 0.04
#    idx5 = 3 implies CutOff = 0.05
#    idx5 = 4 implies CutOff = 0.06
####################################################################

Beta1.Sign.A <- c(0, 0.2, 0.5)  # % of betas with negative sign
CutOff.A     <- c(0.03, 0.04, 0.05, 0.06)

Causal_percent.A <- c(0.05, 0.10, 0.15)
Range.A          <- c(3000, 6000, 9000, 12000, 15000, 18000, 21000, 24000, 27000, 30000)
#N.Sample.A       <- c(250, 500, 1000)
Is.null.a        <- c(0, 1)
Beta1.IDX        <- 2
CutOff           <- 0.03

#Causal_percent <- Causal_percent.A[idx1]

#Region_L   <- Range.A[idx2]   # Region length, total 4
#Beta1.Sign <- Beta1.Sign.A[idx4]
Is.null    <- 0

Weight_Type <- 1 # beta weights

###############################
# Beta function

Get_LogRR_MAF <- function(MAF, p_min = 0.15, theta_max =4 ,s=4)
   {
   re <- 1 + (theta_max -1) * exp( -s*MAF/p_min)

   return(log(re))
   }

Generate_Covariates <- function(n)
   {
	 X1 <- rnorm(n)
	 X2 <- rbinom(n,1,0.5)

	 return(cbind(X1,X2))
   }

Get_Alpha0_C <- function(X)
   {
	 n  <- dim(X)[1]
	 re <- X[,1] * 0.5 / sqrt(2) + Beta0 /2

   return(re)
   }

Get_Alpha0_Q <- function(X)
   {
	 re <- X[,1] * 0.5 + X[,2] * 0.5
	 return(re)
   }

Get_Weights <- function(MAF, IDX)
   {
	 if(IDX == 1)
      {
		  re <- dbeta(MAF, shape1 = 1, shape2 = 25)
	    }
      else if (IDX == 2)
         {
		     re <- 1/sqrt(MAF*(1 - MAF))
         }

	 return(re)
   }

Get_Beta_Q_MAF <- function(MAF)
   {
	 re <- abs(0.5 * log10(MAF))
	 return(re)
   }

Get_BETA_Q<-function( IDX, MAF)
   {
	 n <- length(MAF)

	 if(IDX == 1)
      {
		  re<-Get_Beta_Q_MAF(MAF) * log(7)
	    }
      else if (IDX == 2)
         {
		     re <- Get_Beta_Q_MAF(MAF) * log(5)
	       }
         else if (IDX == 3)
            {
		        re <- Get_Beta_Q_MAF(MAF) * log(2.0)
	          }

	 return(re)
   }

Get_BETA_C<-function(idx1, idx2, MAF)
   {
	 n <- length(MAF)
   if (idx2 == 1)
      {
	    if (idx1 == 1)
         {
		     re <- Get_Beta_Q_MAF(MAF) * log(90)
	       } else if (idx1 == 2)
            {
		        re <- Get_Beta_Q_MAF(MAF) * log(70)
            } else if (idx1 == 3)
               {
		           re <- Get_Beta_Q_MAF(MAF) * log(50)
	             }
	    } else if (idx2 == 2)
         {
	       if (idx1 == 1)
            {
		        re <- Get_Beta_Q_MAF(MAF) * log(90)/1.25
	          } else if (idx1 == 2)
               {
		           re <- Get_Beta_Q_MAF(MAF) * log(70)/1.25
               } else if (idx1 == 3)
                  {
		              re <- Get_Beta_Q_MAF(MAF) * log(50)/1.25
	                }
	       } else if (idx2 == 3)
            {
	          if (idx1 == 1)
               {
		           re <- Get_Beta_Q_MAF(MAF) * log(90)/1.5
	             } else if (idx1 == 2)
                  {
		              re <- Get_Beta_Q_MAF(MAF) * log(70)/1.5
                  } else if (idx1 == 3)
                     {
		                 re <- Get_Beta_Q_MAF(MAF) * log(50)/1.5
	                   }
	          } else if (idx2 == 4)
               {
	             if (idx1 == 1)
                  {
		              re <- Get_Beta_Q_MAF(MAF) * log(90)/1.75
	                } else if (idx1 == 2)
                     {
		                 re <- Get_Beta_Q_MAF(MAF) * log(70)/1.75
                     } else if (idx1 == 3)
                        {
		                    re <- Get_Beta_Q_MAF(MAF) * log(50)/1.75
	                      }
	             } else if (idx2 == 5)
                  {
	                if (idx1 == 1)
                     {
		                 re <- Get_Beta_Q_MAF(MAF) * log(90)/2.0
	                   } else if (idx1 == 2)
                        {
		                    re <- Get_Beta_Q_MAF(MAF) * log(70)/2.0
                        } else if (idx1 == 3)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(50)/2.0
	                         }
	                } else if (idx2 == 6)
                     {
	                   if (idx1 == 1)
                        {
		                    re <- Get_Beta_Q_MAF(MAF) * log(90)/2.25
	                      } else if (idx1 == 2)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(70)/2.25
                           } else if (idx1 == 3)
                              {
		                          re <- Get_Beta_Q_MAF(MAF) * log(50)/2.25
                              }
                     } else if (idx2 == 7)
                        {
	                      if (idx1 == 1)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(90)/2.5
	                         } else if (idx1 == 2)
                              {
                              re <- Get_Beta_Q_MAF(MAF) * log(70)/2.5
                              } else if (idx1 == 3)
                                 {
		                             re <- Get_Beta_Q_MAF(MAF) * log(50)/2.5
                                 }
                            } else if (idx2 == 8)
                        {
	                      if (idx1 == 1)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(90)/2.75
	                         } else if (idx1 == 2)
                              {
                              re <- Get_Beta_Q_MAF(MAF) * log(70)/2.75
                              } else if (idx1 == 3)
                                 {
		                             re <- Get_Beta_Q_MAF(MAF) * log(50)/2.75
                                 }
                                  }else if (idx2 == 9)
                        {
	                      if (idx1 == 1)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(90)/3
	                         } else if (idx1 == 2)
                              {
                              re <- Get_Beta_Q_MAF(MAF) * log(70)/3
                              } else if (idx1 == 3)
                                 {
		                             re <- Get_Beta_Q_MAF(MAF) * log(50)/3
                                 }
                                 }else if (idx2 == 10)
                        {
	                      if (idx1 == 1)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(90)/3.25
	                         } else if (idx1 == 2)
                              {
                              re <- Get_Beta_Q_MAF(MAF) * log(70)/3.25
                              } else if (idx1 == 3)
                                 {
		                             re <- Get_Beta_Q_MAF(MAF) * log(50)/3.25
                                 }
                        }else { }
   return(re)
   }

###
Get_BETA_C_Delta<-function(idx1, idx2, MAF, Delta)
   {
	 n <- length(MAF)
   if (idx2 == 1)
      {
	    if (idx1 == 1)
         {
		     re <- Get_Beta_Q_MAF(MAF) * log(90)/(1.0 + Delta)
	       } else if (idx1 == 2)
            {
		        re <- Get_Beta_Q_MAF(MAF) * log(70) /(1.0 + Delta)
            } else if (idx1 == 3)
               {
		           re <- Get_Beta_Q_MAF(MAF) * log(50) /(1.0 + Delta)
	             }
	    } else if (idx2 == 2)
         {
	       if (idx1 == 1)
            {
		        re <- Get_Beta_Q_MAF(MAF) * log(90)/(1.25 + Delta)
	          } else if (idx1 == 2)
               {
		           re <- Get_Beta_Q_MAF(MAF) * log(70)/(1.25 + Delta)
               } else if (idx1 == 3)
                  {
		              re <- Get_Beta_Q_MAF(MAF) * log(50)/(1.25 + Delta)
	                }
	       } else if (idx2 == 3)
            {
	          if (idx1 == 1)
               {
		           re <- Get_Beta_Q_MAF(MAF) * log(90)/(1.5 + Delta)
	             } else if (idx1 == 2)
                  {
		              re <- Get_Beta_Q_MAF(MAF) * log(70)/(1.5 + Delta)
                  } else if (idx1 == 3)
                     {
		                 re <- Get_Beta_Q_MAF(MAF) * log(50)/(1.5 + Delta)
	                   }
	          } else if (idx2 == 4)
               {
	             if (idx1 == 1)
                  {
		              re <- Get_Beta_Q_MAF(MAF) * log(90)/(1.75 + Delta)
	                } else if (idx1 == 2)
                     {
		                 re <- Get_Beta_Q_MAF(MAF) * log(70)/(1.75 + Delta)
                     } else if (idx1 == 3)
                        {
		                    re <- Get_Beta_Q_MAF(MAF) * log(50)/(1.75 + Delta)
	                      }
	             } else if (idx2 == 5)
                  {
	                if (idx1 == 1)
                     {
		                 re <- Get_Beta_Q_MAF(MAF) * log(90)/(2.0 + Delta)
	                   } else if (idx1 == 2)
                        {
		                    re <- Get_Beta_Q_MAF(MAF) * log(70)/(2.0 + Delta)
                        } else if (idx1 == 3)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(50)/(2.0 + Delta)
	                         }
	                } else if (idx2 == 6)
                     {
	                   if (idx1 == 1)
                        {
		                    re <- Get_Beta_Q_MAF(MAF) * log(90)/(2.25 + Delta)
	                      } else if (idx1 == 2)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(70)/(2.25 + Delta)
                           } else if (idx1 == 3)
                              {
		                          re <- Get_Beta_Q_MAF(MAF) * log(50)/(2.25 + Delta)
                              }
                     } else if (idx2 == 7)
                        {
	                      if (idx1 == 1)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(90)/(2.5 + Delta)
	                         } else if (idx1 == 2)
                              {
                              re <- Get_Beta_Q_MAF(MAF) * log(70)/(2.5 + Delta)
                              } else if (idx1 == 3)
                                 {
		                             re <- Get_Beta_Q_MAF(MAF) * log(50)/(2.5 + Delta)
                                 }
                            } else if (idx2 == 8)
                        {
	                      if (idx1 == 1)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(90)/(2.75 + Delta)
	                         } else if (idx1 == 2)
                              {
                              re <- Get_Beta_Q_MAF(MAF) * log(70)/(2.75 + Delta)
                              } else if (idx1 == 3)
                                 {
		                             re <- Get_Beta_Q_MAF(MAF) * log(50)/(2.75 + Delta)
                                 }
                                  }else if (idx2 == 9)
                        {
	                      if (idx1 == 1)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(90)/(3 + Delta)
	                         } else if (idx1 == 2)
                              {
                              re <- Get_Beta_Q_MAF(MAF) * log(70)/(3 + Delta)
                              } else if (idx1 == 3)
                                 {
		                             re <- Get_Beta_Q_MAF(MAF) * log(50)/(3 + Delta)
                                 }
                                 }else if (idx2 == 10)
                        {
	                      if (idx1 == 1)
                           {
		                       re <- Get_Beta_Q_MAF(MAF) * log(90)/(3.25 + Delta)
	                         } else if (idx1 == 2)
                              {
                              re <- Get_Beta_Q_MAF(MAF) * log(70)/(3.25 + Delta)
                              } else if (idx1 == 3)
                                 {
		                             re <- Get_Beta_Q_MAF(MAF) * log(50)/(3.25 + Delta)
                                 }
                        }else { }
   return(re)
   }


convertThetaIter  <- function(theta, thetabar)
{
    dtheta  <- theta - thetabar
    theta[dtheta > .5*pi]  <-  theta[dtheta > .5*pi] - pi
    theta[dtheta < -.5*pi]  <- pi + theta[dtheta < -.5*pi]
    if ( any(abs(dtheta) > .5*pi) )
    {
        theta <- convertThetaIter(theta, thetabar)
    }
    return(theta)
}

## convertThetaNew  <- function(theta, thetabar)
## {
##     dtheta  <- theta - thetabar
##     if ( any(abs(dtheta) > pi ) )
##     {
##         cat("something wrong with theta!\n")
##         exit()
##     }
##     theta[dtheta > .5*pi]  <-  theta[dtheta > .5*pi] - pi
##     theta[dtheta < -.5*pi]  <- pi + theta[dtheta < -.5*pi]
##     if ( any(abs(dtheta) > pi) )
##     {
##         cat("something wrong with theta 2!\n")
##         exit()
##     }
##     return(theta)
## }

## convertTheta  <- function(theta)
## {
##     if ( any(abs(theta) > pi ) )
##     {
##         cat("something wrong with theta!\n")
##         exit()
##     }
##     theta[theta > .5*pi]  <-  theta[theta > .5*pi] - pi
##     theta[theta < -.5*pi]  <- pi + theta[theta < -.5*pi]
##     if ( any(abs(theta) > pi) )
##     {
##         cat("something wrong with theta 2!\n")
##         exit()
##     }
##     return(theta)
## }

simu  <- function(lambda2, k1, k2, alpha, ec, A, index)
{
    dt <- 0.01
    a0 <- 0.01
    e0 <- 1.0
    lambda1 <- 1
    Ncell <- 50
    Nstep <- 40000
    v <- a0*A
    DispWindow  <- seq(28000, 40000)
    ##Selection  <- 28000 + 2400*seq(5)
    Selection  <- 28000 + 100*seq(120)

    nt <- Ncell
    lt <- 1
    output1 <- NULL

    e <- seq(1.2, 1.2, length.out=Ncell)
    theta <- runif(Ncell, -pi/2, pi/2)
    thetabar <- 0
    S <- 0

    ## ############### model I
    for ( i in seq(Nstep) )
    {
        if ( i %% 20 == 0 )
        {
            n <- cbind(cos(theta), sin(theta))
            Q <- cbind(n[,1]*n[,1]-0.5, n[,1]*n[,2], n[,2]*n[,1], n[,2]*n[,2]-0.5)
            Q <- colSums((e-1)*Q)/sum((e-1))
            M <- matrix(Q, nrow=2, ncol=2, byrow=TRUE)
            ##M <- matrix(colMeans(Q), nrow=2, ncol=2, byrow=TRUE)
            eigenvec <- eigen(M)$vectors[,1]
            S <- 2.0*eigen(M)$values[1]
            if(eigenvec[1] < 0)
            {
                eigenvec  <- -eigenvec
            }
            thetabar <- sign(eigenvec[2])*atan(abs(eigenvec[2])/pmax(0.000001, abs(eigenvec[1])))
        }
        Lt <- exp(v*dt*i)
        Force <- max(0, alpha*(Lt-lt))
        e <- e + dt*(Force*abs(cos(theta)) - lambda1*(e-1)) + k1*sqrt(dt)*rnorm(nt, mean=0, sd=1)
        e <- pmax(e, 1)
        theta <- theta - dt*lambda2*S*(e-1)*(theta-thetabar) + k2*sqrt(dt)*rnorm(nt, mean=0, sd=1)
        ##theta <- theta - dt*lambda2*S*(theta-thetabar) + k2*sqrt(dt)*rnorm(nt, mean=0, sd=1)
        theta <- convertThetaIter(theta, thetabar)
        ##theta <- atan2(sin(theta), cos(theta))

        theta1 <- atan(abs(sin(theta))/pmax(0.000001, abs(cos(theta))))
        ndiv=rbinom(1, nt, dt*a0)
        divtheta <- sample(theta1, ndiv)
        lt<-lt*(1+sum(cos(divtheta))/nt)
        nt<-nt+ndiv
        theta<-c(theta, runif(ndiv, -pi/2, pi/2))
        e<-c(e, rep(e0, ndiv))
        A1 <- mean(cos(theta1))
        A2 <- mean(cos(theta1)) - mean(sin(theta1))

        output1 <- rbind(output1, c(Lt, lt, A1, A2, Force, nt, thetabar, S))
    }

    eModelI <- e
    thetaModelI <- theta

################################ model II
    output2 <- NULL
    nt=Ncell
    lt=1
    e <- seq(1.2, 1.2, length.out=Ncell)
    theta <- runif(Ncell, -pi/2, pi/2)

    for ( i in seq(Nstep) )
    {
        if ( i %% 20 == 0 )
        {
            n <- cbind(cos(theta), sin(theta))
            Q <- cbind(n[,1]*n[,1]-0.5, n[,1]*n[,2], n[,2]*n[,1], n[,2]*n[,2]-0.5)
            Q <- colSums((e-1)*Q)/sum((e-1))
            M <- matrix(Q, nrow=2, ncol=2, byrow=TRUE)
            ##M <- matrix(colMeans(Q), nrow=2, ncol=2, byrow=TRUE)
            eigenvec <- eigen(M)$vectors[,1]
            S <- 2.0*eigen(M)$values[1]
            if(eigenvec[1] < 0)
            {
                eigenvec  <- -eigenvec
            }
            thetabar <- sign(eigenvec[2])*atan(abs(eigenvec[2])/pmax(0.000001, abs(eigenvec[1])))
        }
        Lt <- exp(v*dt*i)
        Force <- max(0, alpha*(Lt-lt))
        e <- e + dt*(Force*abs(cos(theta)) - lambda1*(e-1)) + k1*sqrt(dt)*rnorm(nt, mean=0, sd=1)
        e <- pmax(e, 1)
        theta <- theta - dt*lambda2*S*(e-1)*(theta-thetabar) + k2*sqrt(dt)*rnorm(nt, mean=0, sd=1)
        ##theta <- theta - dt*lambda2*S*(theta-thetabar) + k2*sqrt(dt)*rnorm(nt, mean=0, sd=1)
        theta <- convertThetaIter(theta, thetabar)
        ##theta <- atan2(sin(theta), cos(theta))

        theta1 <- atan(abs(sin(theta))/pmax(0.000001, abs(cos(theta))))
        ecut <- e < ec
        theta2 <- theta1 * (1 - ecut) + ecut * runif(nt, 0, pi/2)

        ndiv=rbinom(1, nt, dt*a0)

        divtheta <- sample(theta2, ndiv)
        lt<-lt*(1+sum(cos(divtheta))/nt)
        nt<-nt+ndiv
        theta<-c(theta, runif(ndiv, -pi/2, pi/2))
        e<-c(e, rep(e0, ndiv))
        A1 <- mean(cos(theta1))
        A2 <- mean(cos(theta1)) - mean(sin(theta1))

        output2<-rbind(output2, c(Lt, lt, A1, A2, Force, nt, thetabar, S))
    }

    ##if ( index <= 3 )
    {
        png(paste("plotlt", "_A_", A, "_alpha_", alpha,
                  "_lambda2_", lambda2,
                  "_k1_", k1, "_k2_", k2,
                  "_", index, ".png", sep=''),
            width=1200, height=600)
        par(mfrow=c(2,5))
        plot(eModelI, thetaModelI*180/pi, ylim=c(-90,90))
        abline(h=c(-30,30))
        plot(output1[DispWindow, 1]-output1[DispWindow, 2],
             col = 'blue', ylab="L(t)-l(t)",
             ylim=c(-1,1),
             xlab="timesteps", cex=0.5
             )##, ylim=c(-1,1), cex=0.5)
        abline(h=0, lwd = 2, col='grey')
        plot(output1[DispWindow,5], cex=0.25)
        plot(output1[DispWindow, 3], col='blue', ylim=c(-1, 1))
        lines(output1[DispWindow, 4], col='red')
        lines(output2[DispWindow, 7], col='green', pch=5, type='p')
        abline(h=c(-0.3))
        plot(output1[DispWindow, 8], col='blue', ylim=c(0, 1))

        plot(e, theta*180/pi, ylim=c(-90,90))
        abline(h=c(-30,30))
        plot(output2[DispWindow, 1]-output2[DispWindow, 2],
             col = 'blue', ylab="L(t)-l(t)",
             ylim=c(-1,1),
             xlab="timesteps", cex=0.5
             )
        abline(h=0, lwd = 2, col='grey')
        plot(output2[DispWindow,5], cex=0.25)
        plot(output2[DispWindow, 3], col='blue', ylim=c(-1, 1))
        lines(output2[DispWindow, 4], col='red')
        lines(output2[DispWindow, 7], col='green', pch=5, type='p')
        abline(h=c(-0.3))
        plot(output2[DispWindow, 8], col='blue', ylim=c(0, 1))

        dev.off()
    }

    simu <- NULL
    simu$model1 <- output1[Selection, 1] - output1[Selection, 2]
    simu$model2 <- output2[Selection, 1] - output2[Selection, 2]
    return(simu)
}

baseModels  <- function(lambda2, k1, k2, ec, index, Force)
{
    dt <- 0.01
    a0 <- 0.01
    e0 <- 1.0
    lambda1 <- 1
    Ncell <- 2000
    Nstep <- 10000

    nt <- Ncell
    e <- seq(1.2, 1.2, length.out=Ncell)
    theta <- runif(Ncell, -pi/2, pi/2)
    thetabar <- 0.0
    S  <- 0

    ## ############### model I
    for ( i in seq(Nstep) )
    {
        if ( i %% 20 == 0 )
        {
            n <- cbind(cos(theta), sin(theta))
            Q <- cbind(n[,1]*n[,1]-0.5, n[,1]*n[,2], n[,2]*n[,1], n[,2]*n[,2]-0.5)
            Q <- colSums((e-1)*Q)/sum((e-1))
            M <- matrix(Q, nrow=2, ncol=2, byrow=TRUE)
            eigenvec <- eigen(M)$vectors[,1]
            S <- 2.0*eigen(M)$values[1]
            if(eigenvec[1] < 0)
            {
                eigenvec  <- -eigenvec
            }
            if (abs(eigenvec[1]) < 0.000001)
            {
                thetabar <- sign(eigenvec[2])*pi/2
            }
            else
            {
                thetabar <- sign(eigenvec[2])*atan(abs(eigenvec[2])/pmax(0.000001, abs(eigenvec[1])))
            }
            ##cat(S, thetabar, '\n')
        }
        e <- e + dt*(Force*abs(cos(theta)) - lambda1*(e-1)) + k1*sqrt(dt)*rnorm(nt, mean=0, sd=1)
        e <- pmax(e, 1)
        theta <- theta - dt*lambda2*S*(e-1)*(theta-thetabar) + k2*sqrt(dt)*rnorm(nt, mean=0, sd=1)
        theta <- convertThetaIter(theta, thetabar)
    }

    theta1 <- atan(abs(sin(theta))/pmax(0.000001, abs(cos(theta))))
    ecut <- e < ec
    theta2 <- theta1 * (1 - ecut) + ecut * runif(nt, 0, pi/2)
    A1 <- mean(cos(theta1))
    A2 <- mean(cos(theta1)) - mean(sin(theta1))
    B1 <- mean(cos(theta2))
    B2 <- mean(cos(theta2)) - mean(sin(theta2))

    output <- NULL
    output$values <- c(A1, A2, B1, B2, S, thetabar)
    output$e <- e
    output$theta <- theta

    baseModels  <- output
    return(baseModels)
}

library(foreach)
library(doParallel)

lambda2 <- 0.25
k1 <- 0.1
k2 <- 0.15
alpha <- 2
ec <- 1.6
A  <- 0.8

Alist <- seq(0.6, 1, 0.05)
lambda2list <- seq(0.1, 3, 0.2)
eclist <- seq(1.1, 2, 0.1)
alphalist <- c(0.1, 0.2, 0.3, 0.5, 1, 1.5, 2, 5, 10, 20, 40, 60, 100)
k1list <- seq(0.1, 2, 0.2)
k2list <- seq(0.1, 2, 0.2)

singleRun <- function(Nsample)
{
    resAll <- NULL
    for ( i in seq(Nsample))
    {
        cat(i, '\n')
        res <- simu(lambda2, k1, k2, alpha, ec, A, i)
        resAll$model1 <- c(resAll$model1, res$model1)
        resAll$model2 <- c(resAll$model2, res$model2)
    }
    singleRun <- c(sd(resAll$model1), sd(resAll$model2))
    return(singleRun)
}

paraRun <- function(Nsample)
{
    paraRun <- foreach ( i=seq(Nsample), .export=c("convertTheta", "simu", "lambda2", "k1", "k2", "alpha", "ec", "A"), .combine = list, .multicombine = TRUE ) %dopar%
        simu(lambda2, k1, k2, alpha, ec, A, i)
    return(paraRun)
}

computeSDpara  <- function(nthreads, Nsample)
{
    zz <- file("sd.txt", "w")
    close(zz)

    cl<-makeCluster(nthreads)
    registerDoParallel(cl)
    ##for ( k1 in k1list )
    {
        ##for ( k2 in k2list )
        {
            res <- paraRun(Nsample)
            sd1 <- sd(unlist(lapply(res, "[[", 1)))
            sd2 <- sd(unlist(lapply(res, "[[", 2)))
            cat(lambda2, k1, k2, alpha, ec, A, sd1, sd2, '\n',
                file="sd.txt", sep=',', append=TRUE)
        }
    }
    stopCluster(cl)
}

figure4 <- function(Nsample)
{
    mycol = c("#99CCFF","darkgrey","#FFCCCC","#FF99FF","#99FFCC")
    ##mycol = c("#6666FF","darkgrey","#FFCC99","#FF99FF","#99FFCC")
    mylty = c(1, 1, 1, 1, 1)
    mypch = c(0,1,5,16,2)

    pdf("figure4A.pdf", height=7, width=9)
    par(mar=c(4,6,4,5))
    plot(0, 0, type='n',
         col = 'blue', ylab="L(t)-l(t)",
         ylim=c(-.75,.75),
         xlim=c(0, 120),
         xlab="t", cex.lab=2, cex.axis=1.5
         )
    for ( i in seq(Nsample))
    {
        cat(i, '\n')
        res <- simu(lambda2, k1, k2, alpha, ec, A, i)
        lines(res$model1, pch=mypch[i], lty=mylty[i], col=mycol[i], type='o', lwd=1.5, cex=0.6)
    }
    dev.off()

    pdf("figure4B.pdf", height=7, width=9)
    par(mar=c(4,6,4,5))
    plot(0, 0, type='n',
         col = 'blue', ylab="L(t)-l(t)",
         ylim=c(-.75,.75),
         xlim=c(0, 120),
         xlab="t", cex.lab=2, cex.axis=1.5
         )
    for ( i in seq(Nsample))
    {
        cat(i, '\n')
        res <- simu(lambda2, k1, k2, alpha, ec, A, i)
        lines(res$model2, pch=mypch[i], lty=mylty[i], col=mycol[i], type='o', lwd=1.5, cex=0.6)
    }
    dev.off()
}

figure3 <- function(nthreads, Nsample)
{
    Force <- 0.5
    ForceList <- seq(0, 1.5, 0.05)
    Astat  <- NULL
    Bstat  <- NULL
    Amean <- NULL
    Asd <- NULL
    Bmean <- NULL
    Bsd <- NULL
    cl<-makeCluster(nthreads)
    registerDoParallel(cl)
    for (Force in ForceList )
    {
        cat(Force, '\n')
        res <- foreach ( i=seq(Nsample),
                        .export=c("convertThetaIter", "baseModels", "lambda2", "k1", "k2", "ec"),
                        .combine = list, .multicombine = TRUE ) %dopar%
            baseModels(lambda2, k1, k2, ec, i, Force)
        Astat <- unlist(lapply(lapply(res, "[[", 1), "[[", 2))
        Bstat <- unlist(lapply(lapply(res, "[[", 1), "[[", 4))
        ##sd2 <- sd(unlist(lapply(res, "[[", 2)))
        ##res <- baseModels(lambda2, k1, k2, ec, i, Force)
        ##Astat  <- c(Astat, res$values[2])
        ##Bstat  <- c(Bstat, res$values[4])
        ##cat(res$values, '\n')
        Amean <- c(Amean, mean(Astat))
        Asd <- c(Asd, sd(Astat))
        Bmean <- c(Bmean, mean(Bstat))
        Bsd <- c(Bsd, sd(Bstat))
    }
    stopCluster(cl)
    pdf("figure3.pdf", height=7, width=8)
    par(mar=c(4,6,4,4))
    plot(ForceList, Amean, lwd=3,
         xlab="F", ylab="A",
         lty=2,
         cex.lab=1.5, cex.axis=1.5,
         cex=0.5,
         type='o', ylim=c(-0.1,1))
    ##abline(v=0, lty=4, lwd=2)
    legend("bottomright", c("one population", "two populations"),
           lty=c(2, 1), lwd=2, cex=1.5)
    arrows(ForceList, Amean-3*Asd, ForceList, Amean+3*Asd, lty=1, code=3, angle=90, length=0.05)
    lines(ForceList, Bmean, lwd=3,
          type='o', lty=1, cex=0.5)
    arrows(ForceList, Bmean-3*Bsd, ForceList, Bmean+3*Bsd, lty=1, code=3, angle=90, length=0.05)
    dev.off()
}

figure3(nthreads=20, Nsample=100)
figure4(5)

##computeSDpara(2, 2)

##system("cat run.r > sd.txt")

##z = baseModels(lambda2, k1, k2, ec, i, -0.1)
##cat(z$values, '\n')


model_canopytemperature <- function (minTair = 0.7,
         maxTair = 7.2,
         cropHeatFlux = 447.912,
         conductance = 598.685,
         lambdaV = 2.454,
         rhoDensityAir = 1.225,
         specificHeatCapacityAir = 0.00101){
    #'- Name: CanopyTemperature -Version: 1.0, -Time step: 1
    #'- Description:
    #'            * Title: CanopyTemperature Model
    #'            * Author: Pierre Martre
    #'            * Reference: Modelling energy balance in the wheat crop model SiriusQuality2:
    #'            Evapotranspiration and canopy and soil temperature calculations
    #'            * Institution: INRA/LEPSE Montpellier
    #'            * Abstract: It is calculated from the crop heat flux and the boundary layer conductance
    #'- inputs:
    #'            * name: minTair
    #'                          ** description : minimum air temperature
    #'                          ** datatype : DOUBLE
    #'                          ** variablecategory : auxiliary
    #'                          ** min : -30
    #'                          ** max : 45
    #'                          ** default : 0.7
    #'                          ** unit : degC
    #'                          ** uri : http://www1.clermont.inra.fr/siriusquality/?page_id=547
    #'                          ** inputtype : variable
    #'            * name: maxTair
    #'                          ** description : maximum air Temperature
    #'                          ** datatype : DOUBLE
    #'                          ** variablecategory : auxiliary
    #'                          ** min : -30
    #'                          ** max : 45
    #'                          ** default : 7.2
    #'                          ** unit : degC
    #'                          ** uri : http://www1.clermont.inra.fr/siriusquality/?page_id=547
    #'                          ** inputtype : variable
    #'            * name: cropHeatFlux
    #'                          ** description : Crop heat flux
    #'                          ** variablecategory : rate
    #'                          ** inputtype : variable
    #'                          ** datatype : DOUBLE
    #'                          ** min : 0
    #'                          ** max : 10000
    #'                          ** default : 447.912
    #'                          ** unit : g/m**2/d
    #'                          ** uri : http://www1.clermont.inra.fr/siriusquality/?page_id=547
    #'            * name: conductance
    #'                          ** description : the boundary layer conductance
    #'                          ** variablecategory : state
    #'                          ** inputtype : variable
    #'                          ** datatype : DOUBLE
    #'                          ** min : 0
    #'                          ** max : 10000
    #'                          ** default : 598.685
    #'                          ** unit : m/d
    #'                          ** uri : http://www1.clermont.inra.fr/siriusquality/?page_id=547
    #'            * name: lambdaV
    #'                          ** description : latent heat of vaporization of water
    #'                          ** parametercategory : constant
    #'                          ** datatype : DOUBLE
    #'                          ** default : 2.454
    #'                          ** min : 0
    #'                          ** max : 10
    #'                          ** unit : MJ/kg
    #'                          ** uri : http://www1.clermont.inra.fr/siriusquality/?page_id=547
    #'                          ** inputtype : parameter
    #'            * name: rhoDensityAir
    #'                          ** description : Density of air
    #'                          ** parametercategory : constant
    #'                          ** datatype : DOUBLE
    #'                          ** default : 1.225
    #'                          ** unit : kg/m**3
    #'                          ** uri : http://www1.clermont.inra.fr/siriusquality/?page_id=547
    #'                          ** inputtype : parameter
    #'            * name: specificHeatCapacityAir
    #'                          ** description : Specific heat capacity of dry air
    #'                          ** parametercategory : constant
    #'                          ** datatype : DOUBLE
    #'                          ** default : 0.00101
    #'                          ** unit : MJ/kg/degC
    #'                          ** uri : http://www1.clermont.inra.fr/siriusquality/?page_id=547
    #'                          ** inputtype : parameter
    #'- outputs:
    #'            * name: minCanopyTemperature
    #'                          ** description : minimal Canopy Temperature
    #'                          ** datatype : DOUBLE
    #'                          ** variablecategory : state
    #'                          ** min : -30
    #'                          ** max : 45
    #'                          ** unit : degC
    #'                          ** uri : http://www1.clermont.inra.fr/siriusquality/?page_id=547
    #'            * name: maxCanopyTemperature
    #'                          ** description : maximal Canopy Temperature
    #'                          ** datatype : DOUBLE
    #'                          ** variablecategory : state
    #'                          ** min : -30
    #'                          ** max : 45
    #'                          ** unit : degC
    #'                          ** uri : http://www1.clermont.inra.fr/siriusquality/?page_id=547
    minCanopyTemperature <- minTair + (cropHeatFlux / (rhoDensityAir * specificHeatCapacityAir * conductance / lambdaV * 1000.0))
    maxCanopyTemperature <- maxTair + (cropHeatFlux / (rhoDensityAir * specificHeatCapacityAir * conductance / lambdaV * 1000.0))
    return (list ("minCanopyTemperature" = minCanopyTemperature,"maxCanopyTemperature" = maxCanopyTemperature))
}


# Copy of the levinson() function from the signals package with
# a correction to remove deprecation warnings.
#
levnsn <- function (x, p = NULL)
{
  fit <- function(acf, p) {
    ref <- numeric(p)
    g <- -acf[2]/acf[1]
    a <- g
    v <- Re((1 - g * Conj(g)) * acf[1])
    ref[1] <- g
    for (t in 2:p) {
      g <- -(acf[t + 1] + a %*% acf[seq(t, 2, by = -1)])/v
      a <- c((a + as.vector(g) * Conj(a[seq(t - 1, 1, -1)])), g)
      v <- v * (1 - Re(g * Conj(g)))
      ref[t] <- g
    }
    a <- c(1, a)
    return(list(a = a, v = v, ref = ref))
  }
  if ((!is.null(p) && (p != as.integer(p))) || (p < 2))
    stop("p must be integer >= 2.")
  if (is.numeric(x) && is.null(dim(x))) {
    lx <- length(x)
    if (is.null(p) || p >= lx)
      p <- lx - 1
    r <- fit(x, p)
  }
  else {
    if (is.numeric(x) && !(is.null(dim(x)))) {
      lx <- dim(x)
      if (is.null(p) || p >= lx[1])
        p <- lx[1] - 1
      zr <- apply(x, 2, function(y) fit(y, p))
      zr <- matrix(unlist(zr), nrow = lx[2], byrow = TRUE)
      a <- zr[, 1:(p + 1), drop = FALSE]
      v <- zr[, p + 2]
      ref <- t(zr[, -(1:(p + 2)), drop = FALSE])
      r <- list(a = a, v = v, ref = ref)
    }
    else {
      stop("x must be a numeric vector or matrix.")
    }
  }
  return(r)
}


###############################################################################
# package: package source
#   By puglisij Copyright (C) 2015, All rights reserved.
#
###############################################################################

#' linked_list
#'
#' @return function list
linked_list <- function() {
  head <- list(0)
  length <- 0

  methods <- list()

  methods$add <- function(val) {
    length <<- length + 1
    head <<- list(head, val)
  }

  methods$as.list <- function() {
    b <- vector('list', length)
    h <- head
    for (i in length:1) {
      b[[i]] <- head[[2]]
      head <- head[[1]]
    }
    return(b)
  }
  methods
}

#' @title Golden Ratio
#' @description Determine a local minimum of a continuous real function f
#'
#' @param f function
#' @param a numeric
#' @param b numeric > a
#' @param eps numeric (default 1e-16)
#' @param maxiter  maximum number of iterations
#' @return  list containing approximation of local minimum,
#'   value at local minimum and some control data
#' @export
golden_ratio <- function(f,
                         a,
                         b,
                         eps = 1e-16,
                         maxiter = 100) {
  stopifnot(
    is.numeric(a) & is.finite(a),
    is.numeric(b) & is.finite(b),
    b > a,
    is.numeric(eps) & is.finite(eps) & eps > 0,
    is.numeric(maxiter) & is.finite(maxiter) & maxiter > 0
  )

  phi <- (sqrt(5) - 1) / 2
  convergence <- 1

  for (i in 1:maxiter) {
    # Update xl, xp
    xl <- b - phi * (b - a)
    xp <- a + phi * (b - a)
    if (f(xl) > f(xp)) {
      a <- xl
    } else {
      b <- xp
    }

    # Check if method converged
    if (abs(b - a) < eps) {
      convergence <- 0
      break
    }
  }

  if (convergence == 1)
    warning("Method didn't converge")

  list(
    par = (a + b) / 2,
    value = f((a + b) / 2),
    counts = i,
    convergence = convergence,
    message = NULL
  )
}

#' @title  Elliot wave - puglisij
#' @description  Criteria must match as follows: Climb in instrument begins as wave 1, followed by a retracement
#' which is wave 2, followed by another climb wave 3, followed by a retracement wave 4, and
#' then followed by the final climb, wave 5.
#'
#' @param v  vector of instrument price data
#' @param eps  numeric
#' @param maxiter  maximum number of iterations
#' @param fib  vector of fibonacci ratios
#' @param time_restrictive boolean each wave is restricted to its individual time interval
#' @return list containing entries and golden ratio computed position scaled
#' @author puglisij
#' @export
#'
elliot_wave <- function(v,
                        eps = 1e-16,
                        maxiter = 10000,
                        fib = c(0.236, 0.382, 0.5, 0.618),
                        time_restrictive = TRUE) {
  stopifnot(is.vector(v) && is.vector(fiblevel))

  x <- vector(numeric, length = length(v))
  j <- as.vector(v)
  z <- vector(mode = "complex", length = 0)

  peaks_valleys <- cbind(x, z)
  entrys <- linked_list()

  for (i in 2:length(v) - 1) {
    if (v(i) <= v(i + 1) &&
        v(i - 1) >= v(i) || v(i) >= v(i + 1) && v(i - 1) <= v(i)) {
      x = c(x, v(i))
      z = c(z, j(i))

      x = x[1, diff(x) != 0]
      z = z[1, diff(x) != 0]
      peaks_valleys = c(x, z)
    }
  }

  entry <-
    function(fib_ratio,
             instrument_vector,
             index)
      ((0.999 * instrument_vector(index + 3)) - ((
        instrument_vector(index - 1) - ((
          instrument_vector(index - 1) - instrument_vector(index - 2)
        ) * fib_ratio)
      ) * 1.001)) / ((instrument_vector(index - 1) - ((instrument_vector(index -
                                                                           1) - instrument_vector(index - 2)) * fib_ratio
      )) * 1.001)

  for (n in 3:length(x) - 1) {
    if (x(n) < x(n - 1) &&
        x(n) >= x(n - 2) &&
        x(n + 1) > x(n - 1) && x(n + 2) > x(n - 1)) {
      if (x(n + 1) - x(n) >= x(n - 1) - x(n - 2) || x(n + 1) - x(n) >= x
          (n + 3) - x(n + 2)) {
        if (time_restrictive ==  TRUE) {
          if (z(n) - z(n - 1) <= (0.382 * (z(n - 1) - z(n - 2))) &&
              z(n + 1) - z(n) <= (1.618 * (z(n - 1) - z(n - 2))) &&
              z(n + 2) - z(n + 1) <= (0.382 * (z(n + 1) - z(n))) &&
              z(n + 3) - z(n + 2) <= (1.618 * (z(n + 1) - z(n)))) {

          } else {
            next
          }
        }
        for (fr in fib) {
          if (x(n) <= (x(n - 1) - ((x(n - 1) - x(n - 2)) * fr)) * 1.001 &&
              x(n) >= (x(n - 1) - ((x(n - 1) - x(n - 2)) * fr)) * 0.999) {
            e <- entry(
              fib_ratio = fr,
              instrument_vector = x,
              index = n
            )

            gr <-
              golden_ratio(
                function(x)
                  x * cos(0.1 * exp(x)) * sin(0.1 * exp(x)),
                a = e,
                b = x(n - 1),
                maxiter = maxiter
              )

            entrys$add(e, gr, n, x(n))
          }
        }

      }
    }
  }

  entrys
}


#' mb2mmHG
#'
#' Conversion from Millibar [hPa] to mmHG.
#'
#' @param numeric mb Air pressure in Millibar [hPa]
#' @return
#'
#'
#' @author  Istituto di Biometeorologia Firenze Italy  Alfonso Crisci \email{a.crisci@@ibimet.cnr.it}
#' @keywords  mbtommHG
#'
#' @export
#'
#'
#'
#'
mb2mmHg<-function(mb)
{
  return (mb* 0.750062);
}


library(tensorflow)

sess = tf$Session()

hello <- tf$constant('Hello, TensorFlow!')
sess$run(hello)

a <- tf$constant(10L)
b <- tf$constant(32L)
sess$run(a + b)

#OR gate input data
trainin = rbind(c(1,1), c(1,-1), c(-1,1), c(-1,-1));
#OR gate output data
trainout = rbind(1, 1, 1, 0);
#Combined OR gate data
ORdat=cbind(trainout,trainin)

# fit neural network with no hidden layers
set.seed(2)
NN = neuralnet(ORdat[,1]~., ORdat[,-1], hidden = 0 , threshold = 0.001,
stepmax = 1e+05, linear.output = FALSE)
#visualise the NN
plot(NN)

NN$weights

testin= rbind(c(1,1))
predict_testNN = compute(NN, testin)

predict_out = as.numeric(predict_testNN$net.result>0.5)
print(predict_out)

#set up the input sequence
testin=rbind(c(1,1),c(1,-1),c(-1,1), c(-1,-1))
predict_testNN = compute(NN, testin)
predict_testNN$neurons
predict_testNN$net.result
predict_out = as.numeric(predict_testNN$net.result>0.5)
predict_out

#XOR gate input data
trainin = rbind(c(1,1), c(1,-1), c(-1,1), c(-1,-1));
#XOR gate output data
trainout = rbind(0, 1, 1, 0);
#Combined XOR gate data
XORdat=cbind(trainout,trainin)
#train a neural network on the XOR data
set.seed(2)
NN = neuralnet(XORdat[,1]~., XORdat[,-1], hidden = c(3,3) , threshold =
0.001, stepmax = 1e+05, linear.output = FALSE)

testin = rbind(c(1,1), c(1,-1), c(-1,1), c(-1,-1));
testout=rbind(0,1,1,0)
predict_testNN = compute(NN, testin)
predict_testNN$neurons
predict_testNN$net.result
predict_out = as.numeric(predict_testNN$net.result>0.5)
predict_out


# Tempering algorithm.

if (TRUE) {
  .libPaths("~/Rlib")
  setwd("~/Code/ising_model/scripts")
  source("algorithms.r")
  source("tools.r")
}

tempering <- function(A, beta_vector, init_matrix,
                      n_exchange, n_mc_iter, B = 0,
                      f1, f2 = f1,
                      which_sampler = rep(1, length(beta_vector)),
                      n_states = 2,
                      is_potts = FALSE) {
  # Returns samples for graph A, across all temperatures
  # specified by the beta_vector. Uses tempering (or exchange)
  # Monte Carlo to improve sampling at high betas, i.e. cold temperatures.
  #
  # A: graph
  # beta_vector: betas for each replica
  # init_matrix: inits for each replica
  # n_exchange: number of exchanges.
  # n_mc_iter: number of sampling iterations between exchanges.
  # B: exterior magnetic field
  # f1: function for first sampler. Should accept A, beta, B,
  #     an init vector, and n_mc_iter as arguments.
  # f2: function for second sampler. Same as above.
  # which_sampler: which sampler to use for each replica. This
  #                should be a vector with the same length as
  #                beta_vector with entries 1 and 2.
  #
  n_replica <- length(beta_vector)
  n_iter <- n_exchange * n_mc_iter
  n_particles <- nrow(A)

  X <- array(NA, dim = c(n_replica, n_iter, n_particles))

  current_init <- init_matrix

  exchange_rate <- rep(0, n_replica - 1)

  for (i in 1:n_exchange) {
    first_index <- (i - 1) * n_mc_iter + 1
    last_index <- i * n_mc_iter
    for (b in 1:n_replica) {
      if (which_sampler[b] == 1) {
        X[b, first_index:last_index, ] <-
          f1(A, beta_vector[b], B, current_init[b, ],
             n_mc_iter)
      } else {
        X[b, first_index:last_index, ] <-
          f2(A, beta_vector[b], B, current_init[b, ],
             n_mc_iter)
      }
    }

    # exchange step
    # NOTE: pass 1 instead of beta to ising kernel to not double-count beta.
    for (b in 1:(n_replica - 1)) {
      if (b == 1) {
        if (!is_potts) {
          E_low = - ising_kernel(1, A, X[b, last_index, ], B, T)
        } else {
          E_low = - 0.5 * potts_log_kernel(1, A, X[b, last_index, ],
                                           n_states = n_states)
        }
      } else {
        E_low = E_high
      }

      if (!is_potts) {
        E_high = - ising_kernel(1, A, X[b + 1, last_index, ], B, T)
      } else {
        E_high = - 0.5 * potts_log_kernel(1, A, X[b + 1, last_index, ],
                                          n_states = n_states)
      }

      delta = (beta_vector[b + 1] - beta_vector[b]) * (E_high - E_low)

      if (runif(1) < exp(delta)) {
        saved_state = X[b + 1, last_index, ]
        X[b + 1, last_index, ] = X[b, last_index, ]
        X[b, last_index, ] = saved_state

        E_high = E_low  # update energy before next exchange

        exchange_rate[b] <- exchange_rate[b] + 1
      }

      current_init[b, ] = X[b, last_index, ]    }

    current_init[n_replica, ] = X[n_replica, last_index, ]
  }
  print(exchange_rate / n_exchange)

  X
}

###############################################################################
## Unit test
unit_test <- FALSE
# WARNING: unit tests have not been updated with latest signature
# from tempering (with which_sampler argument)
if (unit_test) {
  n_part <- 64
  A <- adjacency_graph(n_part, type = "gaussian")
  beta_vector <- c(0.5, 1.8, 2.3, 2.6, 3.0, 3.25, 3.5, 3.70, 3.90, 4.0)
    # c(seq(from = 0.5, to = 4, by = 0.35))
    # c(1.0, 1.0, 1.5, 2.0, 2.5)  # c(0.5, 0.75, 1.0, 1.25)
  B <- 0

  n_replica <- length(beta_vector)
  init_matrix <- matrix(sample(c(-1, 1), n_part * n_replica, replace = T),
                        nrow = n_replica, ncol = n_part)

  n_mc_iter <- 5e3
  n_exchange <- 40

  f1 <- sumit_sampler
  f2 <- function(A, beta, B, init, n_iter) {
    hb_sampler(A, beta, B, init, n_iter,
               sub_sample = ceiling(nrow(A) / 10))
  }
  threshold = 4.1

  sample <- tempering(A, beta_vector, init_matrix,
                      n_exchange, n_mc_iter, B = 0,
                      f1, f2, threshold)

  temp_estimates <- monte_carlo_estimate(sample[, -(1:1000), ])

  threshold = 0
  sample_hb <- tempering(A, beta_vector, init_matrix,
                         n_exchange, n_mc_iter, B, f1, f2, threshold)

  temp_hb_estimates <- monte_carlo_estimate(sample_hb[, -(1:1000), ])

  ## Benchmark against sumit's sampler without tempering
  n_iter <- n_mc_iter * n_exchange
  sample_const <- array(NA, c(n_replica, n_iter, n_part))
  for (i in 1:n_replica) {
    sample_const[i, , ] <- sumit_sampler(A, beta_vector[i], n_iter = n_iter,
                                       init = init_matrix[i, ])
  }

  const_estimates <-
    monte_carlo_estimate(sample_const[, -(1:1000), ])

  temp_estimates
  temp_hb_estimates

  const_estimates
}


# 加载库
library(WGCNA);

# 读取文件
# The following setting is important, do not omit.
# 如果没有显式地指定“stringsAsFactors=FALSE”,默认会将所有的字符串转换为因子,导致数据处理速度较慢
options(stringsAsFactors = FALSE)
# Read in the female liver data set 读取135个雌性小鼠的数据
femData = read.csv("./data/LiverFemale3600.csv")
# Take a quick look at what is in the data set:
# 查看数据的维度
dim(femData)
# 预览数据
head(femData)

#  删除冗余数据-c(1:8)删除前8列数据，t()转置数据
datExpr0 = as.data.frame(t(femData[, -c(1:8)]));
head(datExpr0)

# 将原数据的行列名复制过来
names(datExpr0) = femData$substanceBXH;
rownames(datExpr0) = names(femData)[-c(1:8)];
head(datExpr0)

gsg = goodSamplesGenes(datExpr0, verbose = 3)
gsg$allOK;

if (!gsg$allOK)
{
    # Optionally, print the gene and sample names that were removed:
    # 打印删除的基因和样本名称
    if (sum(!gsg$goodGenes)>0)
        printFlush(paste("Removing genes:", paste(names(datExpr0)[!gsg$goodGenes], collapse = ", ")));
    if (sum(!gsg$goodSamples)>0)
        printFlush(paste("Removing samples:", paste(rownames(datExpr0)[!gsg$goodSamples], collapse = ", ")));
    # Remove the offending genes and samples from the data:
    # 从数据中删除有问题的基因和样本
    datExpr0 = datExpr0[gsg$goodSamples, gsg$goodGenes]
}

# hclusts聚类算法, dist计算基因之间的距离
sampleTree = hclust(dist(datExpr0), method = "average");
# Plot the sample tree: Open a graphic output window of size 12 by 9 inches
# The user should change the dimensions if the window is too large or too small.
# 绘制聚类树，sizeGrWindow设置绘图窗口大小
# sizeGrWindow(16,9)
pdf(file = "./plot/sampleClustering.pdf", width = 12, height = 9);
# 设置文字大小
par(cex = 0.5);
# 设置图像边距c(bottom, left, top, right)
# par(mar = c(0,4,2,0))
# 画图 main标题，sub子标题，xlab x轴标题，cex.lab标题字体大小，cex.axis坐标轴刻度大小，cex.main主标题字体
plot(sampleTree, main = "Sample clustering to detect outliers", sub="", xlab="", cex.lab = 1.5, cex.axis = 1.5, cex.main = 2)
dev.off()

# Plot a line to show the cut
# 设置文字大小
par(cex = 0.5);
plot(sampleTree, main = "Sample clustering to detect outliers", sub="", xlab="", cex.lab = 1.5, cex.axis = 1.5, cex.main = 2)
# 在上图上画红线
abline(h = 15, col = "red");
# Determine cluster under the line
# 剪枝算法，cutHeight 修剪树枝的高度 minSize集群最小数
clust = cutreeStatic(sampleTree, cutHeight = 15, minSize = 10)
# 剪枝结果
table(clust)
# clust 1 contains the samples we want to keep
keepSamples = (clust==1)
# 符合要求的数据
datExpr = datExpr0[keepSamples, ]
# 提取行
nSamples = nrow(datExpr)
# 提取列
nGenes = ncol(datExpr)

traitData = read.csv("./data/ClinicalTraits.csv");
dim(traitData)
#names(traitData)
# remove columns that hold information we do not need.
# 删除不需要的列
allTraits = traitData[, -c(31, 16)];
allTraits = allTraits[, c(2, 11:36) ];
dim(allTraits)
head(allTraits)
# names(allTraits)

# 形成一个类似于表达数据的数据框架，以保存临床特征
# 提取行名
femaleSamples = rownames(datExpr)
# 数据匹配 返回匹配行
traitRows = match(femaleSamples, allTraits$Mice);
# 提取指定要求行
datTraits = allTraits[traitRows, -1];
# 提取行名
rownames(datTraits) = allTraits[traitRows, 1];
# 垃圾回收
collectGarbage();

# Re-cluster samples
# 画聚类图
sampleTree2 = hclust(dist(datExpr), method = "average")
# Convert traits to a color representation: white means low, red means high, grey means missing entry
# 画表型的热图
# 将特征转换为颜色表示：白色表示低，红色表示高，灰色表示缺少条目
# 如果signed为true 以绿色开头代表最大负值，以白色开头代表零附近的值，然后变为红色代表正值
traitColors = numbers2colors(datTraits, signed =FALSE);
# Plot the sample dendrogram and the colors underneath.
# 绘制出树状图和下面的颜色
plotDendroAndColors(sampleTree2, traitColors,groupLabels = names(datTraits),main = "Sample dendrogram and trait heatmap")

# Choose a set of soft-thresholding powers
# 给出候选的β值，c(1:10)表示1到10；seq(from = 12, to=20, by=2)表示从12开始间隔两个数到20
powers = c(c(1:10), seq(from = 12, to=20, by=2))
powers
# Call the network topology analysis function 调用网络拓扑分析函数
# verbose表示输出结果详细程度
sft = pickSoftThreshold(datExpr, powerVector = powers, verbose = 0);

# sft这中保存了每个powers值计算出来的网络特征,其中powerEstimate就是最佳power值，fitIndices保存了每个power对应的网络的特征。
str(sft)

# Plot the results 结果绘图
# 设置窗格大小
#sizeGrWindow(9, 5)
# 设置图的显示一行两列
# par(mfrow = c(1,2));
cex1 = 0.9;
# Scale-free topology fit index as a function of the soft-thresholding power
# 生成阈值和网络的特征之间的关系函数
plot(sft$fitIndices[,1], -sign(sft$fitIndices[,3])*sft$fitIndices[,2],
xlab="Soft Threshold (power)",ylab="Scale Free Topology Model Fit,signed R^2",type="n",
main = paste("Scale independence"))
text(sft$fitIndices[,1], -sign(sft$fitIndices[,3])*sft$fitIndices[,2],
labels=powers,cex=cex1,col="red");
# this line corresponds to using an R^2 cut-off of h
abline(h=0.90,col="red")

# sft$fitIndices 保存了每个power构建的相关性网络中的连接度的统计值，k就是连接度值，每个power值提供了max, median, max3种连接度的统计量
# 对连接度的均值进行可视化
# Mean connectivity as a function of the soft-thresholding power
plot(sft$fitIndices[,1], sft$fitIndices[,5],
xlab="Soft Threshold (power)",ylab="Mean Connectivity", type="n",
main = paste("Mean connectivity"))
text(sft$fitIndices[,1], sft$fitIndices[,5], labels=powers, cex=cex1,col="red")

# datExpr表达数据，TOMType拓扑重叠矩阵计算方式，minModuleSize用于模块检测的最小模块尺寸,
# reassignThreshold 是否在模块之间重新分配基因的p值比率阈值，mergeCutHeight 树状图切割高度
# numericLabels 返回的模块应该用颜色（FALSE）还是数字（TRUE）标记,pamRespectsDendro树状图相关参数
# saveTOMs 字符串的向量，saveTOMFileBase 包含包含共识拓扑重叠文件的文件名库的字符串
net = blockwiseModules(datExpr, power = sft$powerEstimate,TOMType = "unsigned", minModuleSize = 30,reassignThreshold = 0,
                       mergeCutHeight = 0.25,numericLabels = TRUE, pamRespectsDendro = FALSE,saveTOMs = TRUE,
                       saveTOMFileBase = "femaleMouseTOM",verbose = 3)

 table(net$colors)

# open a graphics window
# sizeGrWindow(12, 9)
# Convert labels to colors for plotting
# 将标签转化为绘图颜色
mergedColors = labels2colors(net$colors)
# Plot the dendrogram and the module colors underneath
# 绘制树状图和下面的模块颜色
# dendroLabels树状图标签。设置为FALSE完全禁用树状图标签；设置为NULL使用的行标签datExpr
# addGuide是否应在树状图中添加垂直的“指导线”？线条使识别单个样本的颜色代码更加容易。
plotDendroAndColors(net$dendrograms[[1]], mergedColors[net$blockGenes[[1]]],"Module colors",
                    dendroLabels = FALSE, hang = 0.03,addGuide = TRUE, guideHang = 0.05)

moduleLabels = net$colors
moduleColors = labels2colors(net$colors)
MEs = net$MEs;
geneTree = net$dendrograms[[1]];
save(MEs, moduleLabels, moduleColors, geneTree,
file = "FemaleLiver-02-networkConstruction-auto.RData")

# Define numbers of genes and samples
# 获得基因数和样本数
nGenes = ncol(datExpr);
nSamples = nrow(datExpr);

# Recalculate MEs with color labels
# 用彩色标签重新计算MEs
# 在给定的单个数据集中计算模块的模块本征基因
MEs0 = moduleEigengenes(datExpr, moduleColors)$eigengenes
# 对给定的（特征）向量进行重新排序，以使相似的向量（通过相关性度量）彼此相邻
MEs = orderMEs(MEs0)

# 计算module的ME值与表型的相关系数
moduleTraitCor = cor(MEs, datTraits, use = "p");
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples);

names(MEs)

# sizeGrWindow(10,6)
# 显示相关性及其p值
textMatrix = paste(signif(moduleTraitCor, 2), "\n(",signif(moduleTraitPvalue, 1), ")", sep = "");
dim(textMatrix) = dim(moduleTraitCor)
par(mar = c(6, 8.5, 3, 3));
# Display the correlation values within a heatmap plot\
# ySymbols 当ylabels使用时所使用的其他标签； colorLabels 应该使用颜色标签吗
# colors 颜色； textMatrix 单元格名字
labeledHeatmap(Matrix = moduleTraitCor,xLabels = names(datTraits),yLabels = names(MEs),ySymbols = names(MEs),
               colorLabels = FALSE,colors = greenWhiteRed(50),textMatrix = textMatrix,setStdMargins = FALSE,
               cex.text = 0.4,zlim = c(-1,1),
main = paste("Module-trait relationships"))

sizeGrWindow(10,6)
# Will display correlations and their p-values

dim(textMatrix) = dim(moduleTraitCor)
par(mar = c(6, 8.5, 3, 3));
# Display the correlation values within a heatmap plot
labeledHeatmap(Matrix = moduleTraitCor,
xLabels = names(datTraits),
yLabels = names(MEs),
ySymbols = names(MEs),
colorLabels = FALSE,
colors = greenWhiteRed(50),
textMatrix = textMatrix,
setStdMargins = FALSE,
cex.text = 0.5,
zlim = c(-1,1),
main = paste("Module-trait relationships"))

# Define variable weight containing the weight column of datTrait
# 定义包含数据特征权重列的变量权重
weight = as.data.frame(datTraits$weight_g);
names(weight) = "weight"
geneModuleMembership = as.data.frame(cor(datExpr, MEs, use = "p"));
# 模块的名称(颜色) substring提取文本从第3个字母开始
modNames = substring(names(MEs), 3)
# 基因和模块的相关系数
geneModuleMembership = as.data.frame(cor(datExpr, MEs, use = "p"));
MMPvalue = as.data.frame(corPvalueStudent(as.matrix(geneModuleMembership), nSamples));
names(geneModuleMembership) = paste("MM", modNames, sep="");
names(MMPvalue) = paste("p.MM", modNames, sep="");

#gene和性状的关系
geneTraitSignificance = as.data.frame(cor(datExpr, weight, use = "p"));
GSPvalue = as.data.frame(corPvalueStudent(as.matrix(geneTraitSignificance), nSamples));
names(geneTraitSignificance) = paste("GS.", names(weight), sep="");
names(GSPvalue) = paste("p.GS.", names(weight), sep="");

# 模型颜色
module = "brown"
# 匹配列
column = match(module, modNames);
moduleGenes = moduleColors==module;
#sizeGrWindow(7, 7);
par(mfrow = c(1,1));
# 画散点图
verboseScatterplot(abs(geneModuleMembership[moduleGenes, column]),
                    abs(geneTraitSignificance[moduleGenes, 1]),
                    xlab = paste("Module Membership in", module, "module"),
                    ylab = "Gene significance for body weight",
                    main = paste("Module membership vs. gene significance\n"),
                    cex.main = 1.2, cex.lab = 1.2, cex.axis = 1.2, col = module)

# 提取表带数据样本名称
# names(datExpr);
# 指定颜色数据名称
# names(datExpr)[moduleColors=="brown"]

# 基因注释数据
annot = read.csv(file = "./data/GeneAnnotation.csv");
dim(annot)
names(annot)
probes = names(datExpr)
probes2annot = match(probes, annot$substanceBXH)
# The following is the number or probes without annotation:
sum(is.na(probes2annot))

# Create the starting data frame
geneInfo0 = data.frame(substanceBXH = probes,
geneSymbol = annot$gene_symbol[probes2annot],
LocusLinkID = annot$LocusLinkID[probes2annot],
moduleColor = moduleColors,
geneTraitSignificance,
GSPvalue)
# Order modules by their significance for weight
modOrder = order(-abs(cor(MEs, weight, use = "p")));
# Add module membership information in the chosen order
for (mod in 1:ncol(geneModuleMembership))
{
    oldNames = names(geneInfo0)
    geneInfo0 = data.frame(geneInfo0, geneModuleMembership[, modOrder[mod]],
    MMPvalue[, modOrder[mod]]);
    names(geneInfo0) = c(oldNames, paste("MM.", modNames[modOrder[mod]], sep=""),
    paste("p.MM.", modNames[modOrder[mod]], sep=""))
}
# Order the genes in the geneInfo variable first by module color, then by geneTraitSignificance
geneOrder = order(geneInfo0$moduleColor, -abs(geneInfo0$GS.weight));
geneInfo = geneInfo0[geneOrder, ]
write.csv(geneInfo, file = "geneInfo.csv")

# Calculate topological overlap anew: this could be done more efficiently by saving the TOM
# calculated during module detection, but let us do it again here.
# 重新计算拓扑重叠：通过保存TOM可以更有效地完成此操作
# 是在模块检测期间计算的，但让我们在这里再次进行。
dissTOM = 1-TOMsimilarityFromExpr(datExpr, power = 6);
# Transform dissTOM with a power to make moderately strong connections more visible in the heatmap
# 变换dissTOM
plotTOM = dissTOM^7;
# Set diagonal to NA for a nicer plot
diag(plotTOM) = NA;
# Call the plot function
# sizeGrWindow(9,9)
# 基因的聚类树聚类时的距离为1-TOM值结合基因间的距离，即1-TOM值，用热图展示
# TOMplot(plotTOM, geneTree, moduleColors, main = "Network heatmap plot, all genes")

nSelect = 400
# For reproducibility, we set the random seed
set.seed(10);
select = sample(nGenes, size = nSelect);
selectTOM = dissTOM[select, select];
# There’s no simple way of restricting a clustering tree to a subset of genes, so we must re-cluster.
# 重新画聚类图
selectTree = hclust(as.dist(selectTOM), method = "average")
selectColors = moduleColors[select];
# Open a graphical window
# sizeGrWindow(9,9)
# Taking the dissimilarity to a power, say 10, makes the plot more informative by effectively changing
# the color palette; setting the diagonal to NA also improves the clarity of the plot
plotDiss = selectTOM^7;
diag(plotDiss) = NA;
TOMplot(plotDiss, selectTree, selectColors, main = "Network heatmap plot, selected genes")

# Recalculate module eigengenes
# 重新计算基因特征值
MEs = moduleEigengenes(datExpr, moduleColors)$eigengenes
# Isolate weight from the clinical traits
weight = as.data.frame(datTraits$weight_g);
names(weight) = "weight"
# Add the weight to existing module eigengenes
MET = orderMEs(cbind(MEs, weight))
# Plot the relationships among the eigengenes and the trait
#sizeGrWindow(5,7.5);
par(cex = 0.9)
# 画树形图
# marDendro给出树状图的边距设置，marHeatmap热图边距设置
plotEigengeneNetworks(MET, "", marDendro = c(0,4,1,2), marHeatmap = c(3,4,1,2), cex.lab = 0.8, xLabelsAngle= 90)

# Plot the dendrogram
# sizeGrWindow(6,6);
par(cex = 1.0)
plotEigengeneNetworks(MET, "Eigengene dendrogram", marDendro = c(0,4,2,0),
plotHeatmaps = FALSE)
# Plot the heatmap matrix (note: this plot will overwrite the dendrogram plot)
par(cex = 1.0)
plotEigengeneNetworks(MET, "Eigengene adjacency heatmap", marHeatmap = c(3,4,2,2),plotDendrograms = FALSE, xLabelsAngle = 90)


# Analyze Data

# Requires loading/entering/computing
#   MOD
#     -the model specification matrix
#     -based on RAM specification in "sem" package
#     -create mod from path diagram (see below)
#   Data
#     -the covariance matrix of the observed variables
#     -variable order should be consistent with MOD

###########################
##Load Required Packages ##
###########################

require('MASS') #Multivariate Normal Distributions
require('matrixcalc') #Special Matrices
require('numDeriv') #Needed to estimate SEs
source('scvm_functions.r') #Custom functions to fit CV models

#######################
## LOAD DATA & MODEL ##
#######################

#Enter data file name here:
Y = read.table('cv_sample_data.dat', header=TRUE)

#Specify MOD file here:
MOD <- read.delim("MOD.dat") ## Read in model here

################################
## Transform and Check Inputs ##
################################

Y = as.matrix(Y)
head(Y)
head(MOD)

###################################
## Count and Selection Variables ##
###################################

#sample size
N = nrow(Y)

#total number of variables
p = max(c(MOD$from,MOD$to))
cat(paste('Total Number of Variables: ',p))
# ***Assumes no unused variables

#number of observed variables
pOBS = ncol(Y)
cat(paste('Number of Observed Variables: ', pOBS))
# ***Assumes variables 1:pOBS are all observed and included in model

#Number of unique covariances
pSTAR = pOBS*(pOBS+1)/2
cat(paste('Number of Unique Covariance Terms: ', pSTAR))

#Select/Identify Paths and Vars
sel.ip  <- (MOD$code == 1)#paths from ivs
sel.dp  <- (MOD$code == 2)#paths between dvs
sel.cov <- (MOD$code == 3)#vars and covs of ivs

#Identify and count (strict) IVs
listIV = unique(MOD$from[sel.ip])
pIV = length(listIV) #includes errors
cat(paste('Number of Strictly Independent Variables: ', pIV))

#Identify and count (all) DVs
listDV = unique(MOD$to[MOD$code != 3])
pDV = length(listDV)
cat(paste('Number of Dependent Variables: ', pDV))

#Select/Identify Free Parameters
sel.fixed <- (MOD$index == 0)
sel.free <- !(sel.fixed)

#number of parameters
qTOT = nrow(MOD)
qFREE = sum(sel.free)
cat(paste('Number of Free Parameter: ', qFREE))
# *** Assumes no constraints on parameters

#df for chi-squared
df = pSTAR - qFREE
cat(paste('Number of Degrees of Freedom: ', df))

############################
## Some Useful Statistics ##
############################

#The mean
M = colMeans(Y)
#Warning: This doesn't return a transposable vector!
DmInv = diag(1/M)
cat('Sample Means:')
print(M)

#Sample Covariance Matrix
S = var(Y)
cat('Sample Covariance Matrix:')
print(S)

#Sample CV Matrix
PsyHat = DmInv %*% S %*% DmInv
cat('Sample Coefficient of Variation (CV) Matrix:')
print(PsyHat)

##########################
## Compute Start Values ##
##########################
MOD = getstart(MOD,S)

#############################################
## Define Matrices for Bentler-Weeks Model ##
#############################################

#Get Matrix G to Select Observed Variables
  G = matrix(0,pOBS,p)
  G[cbind(1:pOBS,1:pOBS)] <- 1
  # ***Assumes variables 1:pOBS are observed and included

#Get Matrix B to relate DVs with DVs (contains "beta and known 0s")
  B = matrix(0,p,p)
  B[cbind(MOD$to[sel.dp],MOD$from[sel.dp])]=MOD$value[sel.dp]

#Define Reindex Function
  #function to recode IVs for Gam, Phi
  reindex <- function(x) {
    #initialize
    xnew = x
    #get ordered list of unique xvals
    sux = sort(unique(x))
    #loop through x
    for(i in 1:length(x)) {
      #loop over unique values
      for(k in 1:length(sux)) {
        if(x[i] == sux[k])
          xnew[i] = k
      }
    }
    xnew
  }

#Get Matrix Gamma to relate IVs with DVs
  #Initialize
    Gam = matrix(0,p,pIV)
  #List IVs with New Unique Indices
    ivfrom = reindex(MOD$from[sel.ip])
  #Calculate Gamma
    Gam[cbind(MOD$to[sel.ip],ivfrom)] = MOD$value[sel.ip]
    Gam[cbind(MOD$from[sel.ip],ivfrom)] = MOD$value[sel.ip]

#Get CovMat Phi containing covs of IVs
  #Initialize
    Phi = diag(1,pIV,pIV)
  #Find Covariances
    these = c(unique(MOD$from[sel.ip]),MOD$to[sel.cov],MOD$from[sel.cov])
  #List Covariances with New Unique Indices
    Cindex = reindex(these)
    Cindex = Cindex[-(1:pIV)]
    Cindex = matrix(Cindex,ncol=2,byrow=F)
  #Put Covariances into Phi Matrix
    Phi[Cindex] = MOD$value[sel.cov]
    Phi = Phi + t(Phi) - diag(diag(Phi))

###########################################
## Get Sampling Variances for ADF Method ##
###########################################

#################
## SigmaHatPsy ##
#################

#Get SigmaPsyHat for CV-SEM Method
  #Identity
    Ip = diag(pOBS)
  #Kronecker Product of CV and Ip
    PsyHatI = kronecker(PsyHat,Ip)
  #Duplication and Elimination Matrices
    Dp = D.matrix(pOBS)
    Hp = solve(t(Dp) %*% Dp) %*% t(Dp)
  #Np (Funky Product of Dup Matrices)
    Np = Dp %*% solve( t(Dp) %*% Dp ) %*% t(Dp)
  #Lp
    Lp=matrix(0,pOBS^2,pOBS)
    for(i in 1:pOBS) {
      Lp = Lp + kronecker(Ip[,i],Ip[,i]) %*% t(Ip[,i])
    }
  #Transform Means Vector
    kronDmInv = kronecker(DmInv,DmInv)
  #Estimate Omegas [Prospectus (3.11) and (3.12)]
    #Get Sums of Products for OmegaHat12 and OmegaHat22
    sumthing12 = matrix(0,pOBS,pOBS^2)
    sumthing22 = matrix(0,pOBS^2,pOBS^2)
      for(i in 1:N) {
        #Precursors for Omega12
        ui = kronecker(Y[i,]-M,Y[i,] - M)
        prodthing12 = (Y[i,] - M) %*% t(ui)
        sumthing12 = sumthing12 + prodthing12
        #Precursors for Omega22
        prodthing22 = ui %*% t(ui)
        sumthing22 = sumthing22 + prodthing22
      }
    #Get OmegaHat12
      OmegaHat12 = N/((N-1)*(N-2))* sumthing12
      OmegaHat12str =DmInv %*% OmegaHat12 %*% kronDmInv
    #Get OmegaHat22
      OmegaHat22 = (sumthing22 - (N-2)*vec(S)%*%t(vec(S)) )/(N-pSTAR-1)
      OmegaHat22str = kronDmInv %*% OmegaHat22 %*% kronDmInv
  #Variance of CV Sampling Distribution [Prospectus (3.15)]
    SigmaHatPsy = (2*Np) %*% PsyHatI %*% Lp %*% PsyHat %*% t(Lp) %*%
      PsyHatI %*% (2*Np) +
      -t(OmegaHat12str) %*% t(Lp) %*% PsyHatI %*% (2*Np) +
      -(2*Np) %*% PsyHatI %*% Lp %*% OmegaHat12str + OmegaHat22str
    SHPinv = solve(Hp %*% SigmaHatPsy %*% t(Hp))
  #Variance of CV Sampling Distribution w/Normality [Prospectus (3.16)]
    SigmaHatPsyN = 2*Np %*% PsyHatI %*% Lp %*% PsyHat %*% t(Lp) %*%
      PsyHatI %*% (2*Np) +
      2*Np %*% kronecker(PsyHat,PsyHat)
    SHPNinv = solve(Hp %*% SigmaHatPsyN %*% t(Hp))

#########################################
## Fit CV Models and Examine Estimates ##
#########################################

#########################
## ADF - CV (Arbitrary)##
#########################

METH = 'ADF Estimation with Arbitrary Distribution'
#Fit Model Using ADFcv procedure
  theta = MOD$value[sel.free]
  rADFcv = plzcon(theta,fADFcv)
  rADFcv$METH = METH
#SEs of ADFcv Estimates
  DeltaADFcv = getDelta(rADFcv,SHPinv)
  rADFcv$SEs = sqrt(diag(DeltaADFcv)/N)
  rADFcv=compsings(rADFcv)
#Results
  printRES(rADFcv)
  cat('Sample CV Matrix:')
  print(PsyHat)
  cat('Reproduced CV Mat:')
  print(SIGMAof(rADFcv$pars))
  cat('Covariance Residuals:')
  sdres_ADF = (vech(PsyHat) - vech(SIGMAof(rADFcv$pars)))/sd(vech(PsyHat))
  print(PsyHat - SIGMAof(rADFcv$pars))
  cat('Covariance Residuals as Percent Difference:')
  print((PsyHat - SIGMAof(rADFcv$pars))*100/PsyHat)

#####################
## ADF - CV Normal ##
#####################

METH = 'ADF Estimation with Normal Distribution'
#Fit Model Using ADFcvn procedure
  theta = MOD$value[sel.free]
  rADFcvn = plzcon(theta,fADFcvn)
  rADFcvn$METH = METH
#SEs of ADF Estimates
  DeltaADFcvn = getDelta(rADFcvn,SHPNinv)
  rADFcvn$SEs = sqrt(diag(DeltaADFcvn)/N)
  rADFcvn=compsings(rADFcvn)
#Results
  printRES(rADFcvn)
  cat('Sample CV Matrix:')
  print(PsyHat)
  cat('Reproduced CV Mat:')
  print(SIGMAof(rADFcvn$pars))
  cat('Covariance Residuals:')
  sdres_ADFN = (vech(PsyHat) - vech(SIGMAof(rADFcvn$pars)))/sd(vech(PsyHat))
  print(PsyHat - SIGMAof(rADFcvn$pars))
  cat('Covariance Residuals as Percent Difference:')
  print((PsyHat - SIGMAof(rADFcvn$pars))*100/PsyHat)

##############
## GLS - CV ##
##############

METH = 'GLS Estimation'
#Fit Model Using GLS procedure
  theta = MOD$value[sel.free]
  rGLScv = plzcon(theta,fGLScv)
  rGLScv$METH = METH
#SEs of GLS Estimates
  DeltaGLScv = getDelta(rGLScv,solve(PsyHat))
  rGLScv$SEs = sqrt(diag(DeltaGLScv)/N)
  rGLScv=compsings(rGLScv)
#Results
  printRES(rGLScv)
  cat('Sample CV Mat:')
  print(PsyHat)
  cat('Reproduced CV Mat:')
  print(SIGMAof(rGLScv$pars))
  cat('Covariance Residuals:')
  sdres_GLS = (vech(PsyHat) - vech(SIGMAof(rGLScv$pars)))/sd(vech(PsyHat))
  print(PsyHat - SIGMAof(rGLScv$pars))
  cat('Covariance Residuals as Percent Difference:')
  print((PsyHat - SIGMAof(rGLScv$pars))*100/PsyHat)

#############
## ML - CV ##
#############

METH = 'Maximum Likelihood Estimation'
#Fit Model Using ML procedure
  theta = MOD$value[sel.free]
  rMLcv = plzcon(theta,fMLcv)
  rMLcv$METH = METH
#SEs of ML Estimates
  DeltaMLcv = getDelta(rMLcv,solve(SIGMAof(rMLcv$pars)))
  rMLcv$SEs = sqrt(diag(DeltaMLcv)/N)
  rMLcv=compsings(rMLcv)
#Result
  printRES(rMLcv)
  cat('Sample CV Mat:')
  print(PsyHat)
  cat('Reproduced CV Mat:')
  print(SIGMAof(rMLcv$pars))
  cat('Covariance Residuals:')
  sdres_ML = (vech(PsyHat) - vech(SIGMAof(rMLcv$pars)))/sd(vech(PsyHat))
  print(PsyHat - SIGMAof(rMLcv$pars))
  cat('Covariance Residuals as Percent Difference:')
  print((PsyHat - SIGMAof(rMLcv$pars))*100/PsyHat)

#Plot Histograms of Standardized Residuals
par(mfrow = c(2,2),
    mar=c(3, 4, 1.5, 1.5)+0.1,
    cex=0.9)
xtitle = "Standardized Residual"
hist(sdres_ADF,
     ylab=NULL,xlab=NULL,main=NULL,
     ylim=c(0,8),xlim=c(-0.5,0.5),
     col="gray")
mtext("AGLS",3,line=-1.5,cex=0.9)
mtext(xtitle,1,line=2,cex=0.9)
mtext("Frequency",2,line=2,cex=0.9)

hist(sdres_ADFN,
     ylab=NULL,xlab=NULL,main=NULL,
     ylim=c(0,8),xlim=c(-0.5,0.5),
     col="gray")
mtext("NGLS",3,line=-1.5,cex=0.9)
mtext(xtitle,1,line=2,cex=0.9)
mtext("Frequency",2,line=2,cex=0.9)

hist(sdres_GLS,
     ylab=NULL,xlab=NULL,main=NULL,
     ylim=c(0,8),xlim=c(-0.5,0.5),
     col="gray")
mtext("MGLS",3,line=-1.5,cex=0.9)
mtext(xtitle,1,line=2,cex=0.9)
mtext("Frequency",2,line=2,cex=0.9)

hist(sdres_ML,
     ylab=NULL,xlab=NULL,main=NULL,
     ylim=c(0,8),xlim=c(-0.5,0.5),
     col="gray")
mtext("MRLS",3,line=-1.5,cex=0.9)
mtext(xtitle,1,line=2,cex=0.9)
mtext("Frequency",2,line=2,cex=0.9)

Parameter_Table = rbind(rADFcv$pars, rADFcv$SEs,
                  rADFcvn$pars,rADFcvn$SEs,
                  rGLScv$pars, rGLScv$SEs,
                  rMLcv$pars,  rMLcv$SEs)
row.names(Parameter_Table) <- c('ADF Param Est',
                                'ADF SEs',
                                'Normal ADF Param Est',
                                'Normal ADF SEs',
                                'GLS Param Est',
                                'GLS SEs',
                                'ML Param Est',
                                'ML SEs')
View(Parameter_Table)

CV_Matrix_Table = t(cbind(vech(PsyHat),
                  vech(SIGMAof(rADFcv$pars)),
                  vech(SIGMAof(rADFcvn$pars)),
                  vech(SIGMAof(rGLScv$pars)),
                  vech(SIGMAof(rMLcv$pars))))
row.names(CV_Matrix_Table) = c(
                        'Sample CV Matrix',
                        'ADF Modeled CV Matrix',
                        'Normal ADF Modeled CV Matrix',
                        'GLS Modeled CV Matrix',
                        'ML Modeled CV Matrix')
View(CV_Matrix_Table)


#' all the below code is cannibalized from aRbor

#' this code attempts to detect whether data is discrete or continuous for use in calculating phylogenetic signal
#' it uses a rather heuristic method to determine if something is discrete, so be careful!

detectCharacterType<-function(dat) {
	if(is.factor(dat)) {
			charType<-"discrete"
	} else if(nlevels(as.factor(dat))/length(dat) < 0.1) {
			warning("Guessing that this is a discrete character based on repeated values")
			charType<-"discrete"
	} else {
			charType<-"continuous"
	}
	return(charType)
}	# needless to say, this is not yet robust

#' Function for calculating phylogenetic signal of discrete and continuous traits
#'
#' This function allows testing either Blomberg (for continuous), Pagel lambda (for both), or "garbage test" (for discrete)

physigArbor<-function(phy, dat, charType="fromData", signalTest="pagelLambda", discreteModelType="ER") {
	ctype = match.arg(charType, c("fromData", "discrete", "continuous"))

	if(ctype=="fromData") # then try to figure it out
		ctype<-detectCharacterType(dat)

	signalTest = match.arg(signalTest, c("pagelLambda", "Blomberg", "garbageTest"))
	discreteModelType = match.arg(discreteModelType, c("ER", "SYM", "ARD"))

	if(ctype=="discrete") {
		# this changes the discrete data to 1:n and remembers the original charStates
		dat<-as.factor(dat)
		charStates<-levels(dat)
		k<-nlevels(dat)

		ndat<-as.numeric(dat)
		names(ndat)<-names(dat)

		if(signalTest=="pagelLambda") {
			res<-discreteLambdaTest(phy, ndat, k, discreteModelType)
		} else if(signalTest=="garbageTest") {
			res<-discreteGarbageTest(phy, ndat, k, discreteModelType)
		} else if(signalTest=="Blomberg") {
			stop("Blomberg K should not be used for discrete characters")
		}
	}

	if(ctype=="continuous") {
		if(signalTest=="pagelLambda") {
			res<-continuousLambdaTest(phy, dat)
		} else if(signalTest=="garbageTest") {
			res<-continuousGarbageTest(phy, dat)
		} else if(signalTest=="Blomberg") {
			res<-continuousBlombergTest(phy, dat)
		}
	}

	return(res)

}

discreteLambdaTest<-function(phy, ndat, k, discreteModelType) {
	m1<-fitDiscrete(phy, ndat, model=discreteModelType)
	m2<-fitDiscrete(phy, ndat, model=discreteModelType, transform="lambda")

	chisqTestStat <- 2 * (m2$opt$lnL-m1$opt$lnL)
	chisqPVal <- pchisq(chisqTestStat, 1, lower.tail=F)

	aicScores<-c(m1$opt$aicc, m2$opt$aicc)
	names(aicScores)<-c("Mk", "Mk+lambda")

	res<-list(chisqTestStat= chisqTestStat, chisqPVal= chisqPVal, aicScores= aicScores)
	return(res)
}

discreteGarbageTest<-function(phy, ndat, k, discreteModelType) {
	m1<-fitDiscrete(phy, ndat, model=discreteModelType)
	m2<-fitDiscreteGarbageModel(phy, ndat)

	aiccScores<-c(m1$opt$aicc, m2$aicc)
	names(aiccScores)<-c("Mk", "Garbage")

	res<-list(aiccScores= aiccScores)
	return(res)
}

fitDiscreteGarbageModel<-function(phy, ndat) {
	tt <- table(ndat)
	prob <- tt/sum(tt)
	lnL <- sum(tt * log(prob))
	k <- length(tt)-1
	n <- length(ndat)
	aic <- -2 * lnL + 2 * k
	aicc <- aic + 2 * k * (k+1) / (n - k - 1)
	res<-list(prob=prob, lnL=lnL, k=k, aic=aic, aicc=aicc)
	return(res)
}

continuousLambdaTest<-function(phy, dat) {
	m1<-fitContinuous(phy, dat, model="BM")
	m2<-fitContinuous(phy, dat, model="lambda")

	chisqTestStat <- 2 * (m2$opt$lnL-m1$opt$lnL)
	chisqPVal <- pchisq(chisqTestStat, 1, lower.tail=F)

	aicScores<-c(m1$opt$aicc, m2$opt$aicc)
	names(aicScores)<-c("BM", "BM+lambda")

	res<-list(chisqTestStat= chisqTestStat, chisqPVal= chisqPVal, aicScores= aicScores)
	return(res)
}

continuousGarbageTest<-function(phy, dat) {
	m1<-fitContinuous(phy, dat)
	m2<-fitContinuous(phy, dat, model="white")

	aiccScores<-c(m1$opt$aicc, m2$opt$aicc)
	names(aiccScores)<-c("Mk", "WhiteNoise")

	res<-list(aiccScores= aiccScores)
	return(res)
}

continuousBlombergTest<-function(phy, dat) {
	res<-phylosignal(dat, phy)
	return(res)
}


## * Utilities

upper1st <- function(x) {
    if (is.factor(x))
        x0 <- levels(x) else x0 <- as.character(x)
    nc <- nchar(x0)
    x0[nc > 1] <- sprintf('%s%s', toupper(substr(x0[nc > 1], 1, 1)), substr(x0[nc > 1], 2, nchar(x0[nc > 1])))
    x0[nc == 1] <- toupper(x0[nc == 1])
    if (is.factor(x))
        levels(x) <- x0 else x <- x0
    return(x)
}

slugify <- function(x) {
    gsub(' +', '_', gsub('\'', '', tolower(x)))
}

## * Statistical

estBetaParams <- function(mu, var) {
    ## Estimate alpha and beta of beta distribution from mean and variance
    ## from http://stats.stackexchange.com/questions/12232/calculating-the-parameters-of-a-beta-distribution-using-the-mean-and-variance
    alpha <- ((1 - mu) / var - 1 / mu) * mu ^ 2
    beta <- alpha * (1 / mu - 1)
    return(params = list(alpha = alpha, beta = beta))
}

## * For PST

## ** Rmax formula from Niel & Lebreton 2008
funNL<- function(x,a,s) (exp((a+s/(x-s))^-1)-x)^2
lmax_nl <- function(a,s) return(optimise(funNL, c(1,2), a=a, s=s, tol=1e-10)$minimum)
Lmax_nl <- function(a,s,usemc=F) {
    if (usemc) {
        library(parallel)
        return(mcmapply(lmax_nl, a, s))
    } else return(mapply(lmax_nl, a, s))
}
Rmax_NL <- function(s,a,...) return(Lmax_nl(a,s,...)-1)

## * For PST

## formula from Neil & Lebreton 2008
funNL<- function(x,a,s) (exp((a+s/(x-s))^-1)-x)^2
lmax_nl <- function(a,s) return(optimise(funNL, c(1,2), a=a, s=s, tol=1e-10)$minimum)
Lmax_nl <- function(a,s,usemc=F) {
    if (usemc) {
        library(parallel)
        return(mcmapply(lmax_nl, a, s))
    } else return(mapply(lmax_nl, a, s))
}
Rmax_NL <- function(s,a,...) return(Lmax_nl(a,s,...)-1)

 ## Survival variation
surv_var_norm_mean_se <- function(n=1000, smean, sse)
    {
    se_beta <- sse/(smean*(1-smean)) ## calculate se(beta(S)) from se(S), uses delta method
    logit_s <- rnorm(n=n, mean=log(smean/(1-smean)), sd=se_beta) ## apply normal variation to logit(s)
    surv <- exp(logit_s)/(1+exp(logit_s)) ## back-transform
    return(surv)
    }
## surv_var_norm_mean_se1 <- Vectorize(surv_var_norm_mean_se0, SIMPLIFY=F)
## surv_var_norm_mean_se <- function(n=1000, smean, sse)
##   do.call('rbind', surv_var_norm_mean_se1(n=1000, smean, sse))

surv_ci0 <- function(smean, sse)
    {
    se_beta <- sse/(smean*(1-smean)) ## calculate se(beta(S)) from se(S)
    logit_s <- log(smean/(1-smean))
    ll <- logit_s-1.96*se_beta
    ul <- logit_s+1.96*se_beta
    ll <- exp(ll) / (1 + exp(ll))
    ul <- exp(ul) / (1 + exp(ul))
    return(data.frame(ll=ll, ul=ul))
    }
surv_ci1 <- Vectorize(surv_ci0, SIMPLIFY=F)
surv_ci <- function(smean, sse)  do.call('rbind', surv_ci1(smean, sse))

surv_meansd_from_ci0 <- function(lcl, ucl)
    {
    logitlcl <- log(lcl/(1-lcl))
    logitucl <- log(ucl/(1-ucl))
    sdlogit <- (logitucl-logitlcl) / (2*1.96)
    meanlogit <- mean(c(logitlcl,logitucl))
    mean <- exp(meanlogit)/(1+exp(meanlogit))
    sd <- sdlogit*(mean*(1-mean))
    return(data.frame(mean=mean, sd=sd))
    }
surv_meansd_from_ci1 <- Vectorize(surv_meansd_from_ci0, SIMPLIFY=F)
surv_meansd_from_ci <- function(lcl, ucl)  do.call('rbind', surv_meansd_from_ci1(lcl, ucl))

ntot2 <- function(Nadtot, surv, afr, nsims=4000) {
    if (length(Nadtot)==1 | is.null(names(Nadtot))) {
        n <- Nadtot
    } else { ## point estimate or vector of samples
	if (all(names(Nadtot)==c('mean','se'))) { ## mean-se
	    n <- surv_var_norm_mean_se(nsims, smean=Nadtot['mean'], sse=Nadtot['se'])
        } else {
            if (prod(names(Nadtot)==c('min','max'))) { ## min-max
                n <- runif(nsims, min=Nadtot['min'], max=Nadtot['max'])
            }
        }
    }
    if (length(surv)==1 | is.null(names(surv))) {
        s <- surv
    } else {
	if (prod(names(surv)==c('mean','se'))) {
	    s <- surv_var_norm_mean_se(nsims, smean=surv['mean'], sse=surv['se'])
        } else {
            if (prod(names(surv)==c('min','max'))) {
                s <- runif(nsims, min=surv['min'], max=surv['max'])
            }
        }
    }
    if (length(afr)==1 | is.null(names(afr))) {
        a <- afr
    } else {
	if (prod(names(afr)==c('mean','se'))) {
	    a <- rnorm(nsims, mean=afr['mean'], sd=afr['se'])
        } else {
            if (prod(names(afr)==c('min','max'))) {
                a <- runif(nsims, min=afr['min'], max=afr['max'])
            }
        }
    }

    ## maximum age
    m=1+log(0.02)/log(s)

    ## Indiv/adult ratio
    r = s^(1-a)

    ## Total population
    ntot = n*r

    if (min(ntot)<0)
    print('===================================>>>  WARNING!!! Minimum of Ntot is negative!')

    return(list(all=ntot, min=quantile(ntot,0.2), s=s, a=a, r=r, m=m))
    ## for min: take the lower 60 percentile, following Wade
}

## * South Pole-centered map of grid values

map_grid_values <- function(grid_values, legend.title='', colourscale.trans='log1p', zeros_to_na=T,
                            leg.pos = c(0.95, 0.15),
                            pal=c("#E3F2FD","#BBDEFB","#90CAF9","#64B5F6","#42A5F5","#2196F3","#1E88E5","#1976D2","#1565C0","#0D47A1"),
                            bg.col = 'grey95', graticule.col = '#B0B0B0',
                            highlighted.lat = NA, highlighted.lat.col = 'grey', min0=T, grid = grid_noland, ...) {

    suppressPackageStartupMessages({
        library(data.table)
        library(ggplot2)
        library(colorspace)
        library(sf)
    })
    if (ncol(grid_values) != 2)
        stop('`grid_values` needs to have two columns only: grid ids and values')

    if (any(duplicated(grid_values$grid_id)))
        stop('Duplicated `grid_id` values')

    grid_values <- copy(grid_values)
    setDT(grid_values)
    setnames(grid_values, c('grid_id', 'value'))

    values <- grid_values[match(grid$grid_id, grid_id), value]
    if (zeros_to_na) {
        values[values == 0] <- NA
    }
    grid$value <- values

    logtrans <- grepl('log', colourscale.trans)
    if (logtrans) {

        mx <- max(pretty(c(0, max(grid$value, na.rm=T))))
        z <- round(mx / (10^(-10:10)))
        z <- (-10:10)[min(which(z > 0 & nchar(z) == 1))]
        brks <- c(1, 3) * rep(10^((z-1):z), each=2)

    } else {
        brks <- pretty(grid$value)
    }
    if (min0) {
        brks <- unique(c(0, brks))
    }

    bb <- st_bbox(grid)
    world <- suppressMessages(st_crop(oneworld, bb))
    world <- st_segmentize(world, 100000)

    g <- ggplot() +
        geom_sf(data=grid, aes(fill = value), colour = graticule.col, size = 0.1) +
        scale_fill_gradientn(colours = pal, name = legend.title,
                             na.value='white', limits = c(0, max(brks)),
                             trans = colourscale.trans, breaks = brks)

    if (!is.na(highlighted.lat)) {
        hlat <- st_as_sf(as(SpatialLines(list(Lines(list(Line(cbind(x = seq(0, 360, 1),
                                                                    y = rep(highlighted.lat, 361)))), ID=1)),
                               proj4string=CRS("+init=epsg:4326 +over")), 'SpatialLines'))
        g <- g + geom_sf(dat = hlat, colour = 'grey')
    }

    g <- g +
        ## ** world
        geom_sf(data = world, fill = '#AAAAAA', colour = NA, size = 0.1) +
        theme_void() +
        theme(plot.margin = unit(rep(3, 4), 'mm'),
              legend.position=leg.pos,
              legend.margin = margin(5, 2, 2, 2, unit='mm'),
              legend.background=element_rect(fill = '#FFFFFF44'),
              legend.title.align = 0,
              legend.text.align = 0,
              legend.key.width = unit(0.5, 'cm'),
              plot.background = element_rect(fill = bg.col)) +
        coord_sf(crs="+proj=ortho +y_0=0 +lon_0=178 +lat_0=-90.0", expand=F, datum=NA)

    return(g)
}


pGumbel <- function (q, mu = 0, sigma = 1){
  stopifnot(sigma > 0)
  exp(-exp(-((q - mu)/sigma)))
}

#' Take a random draw from a variable variable
#' @param obj Model object of class `lm`, `glm`, `polr` or `multinom`
#' @param data Data frame giving variables used to estimate model
#' @param ret For return a draw from the variable or return the probabilities.
#' @param incl_b_var Logical indicating whether the sampling variable of
#' the coefficients should be incorporated into the simulation.
#' @param ... Other arguments to be passed down, currently not implemented.
#'
#' @importFrom MASS mvrnorm
#' @importFrom stats model.matrix coef vcov rmultinom rbinom rnorm plogis family formula pcauchy pnorm
#' @export
draw_val <- function(obj,
                     data,
                     ret=c("draw", "expected"),
                     incl_b_var = TRUE,
                     ...){
  ret <- match.arg(ret)
  X <- model.matrix(formula(obj), data)
  if(inherits(obj, "multinom")){
    b <- c(t(coef(obj)))
    if(incl_b_var){
      B <- mvrnorm(1, b, vcov(obj))
      B <- cbind(0, matrix(B, ncol=(length(obj$lev)-1)))
    }else{
      B <- cbind(0, t(coef(obj)))
    }
    xb <- X %*% B
    prob <- prop.table(exp(xb), 1)
    tmp <- sapply(1:nrow(prob), function(i)rmultinom(1, 1, prob[i,])  )
    out <- factor(apply(tmp, 2, which.max),
                  levels=1:length(obj$lev),
                  labels=obj$lev)

  }
  if(inherits(obj, "polr")){
    cdf <- switch(obj$method,
                  logistic = plogis,
                  probit = pnorm,
                  cloglog = pGumbel,
                  cauchit = pcauchy)

    X <- X[,-1]
    b <- c(coef(obj), obj$zeta)
    if(incl_b_var){
      B <- mvrnorm(1, b, vcov(obj))
      Z <- B[grep("\\|", names(B))]
      B <- B[-grep("\\|", names(B))]
    }else{
      B <- coef(obj)
      Z <- obj$zeta
    }
    xb <- X %*% B
    Z <- c(-Inf, Z, Inf)
    qs <- sapply(Z, function(z)cdf(z-xb))
    prob <- sapply(2:ncol(qs), function(i)qs[,i] - qs[,(i-1)])
    tmp <- sapply(1:nrow(prob), function(i)rmultinom(1, 1, prob[i,])  )
    out <- factor(apply(tmp, 2, which.max),
                  levels=1:length(obj$lev),
                  labels=obj$lev)
  }
  if(inherits(obj, "glm")){
    if(family(obj)$family == "binomial"){
      if(incl_b_var){
        b <- mvrnorm(1, coef(obj),vcov(obj))
      }else{
        b <- coef(obj)
      }
      prob <- family(obj)$linkinv(X %*% b)
      out <- rbinom(length(prob), 1, prob)
    }else{
      stop(paste0("GLM family ", family(obj)$family, " not currently supported.\n"))
    }
  }
  if(inherits(obj, "lm") & !inherits(obj, "glm")){
    if(incl_b_var){
      b <- mvrnorm(1, coef(obj),vcov(obj))
    }else{
      b <- coef(obj)
    }
    prob <- X %*% b
    out <- rnorm(nrow(X), prob, summary(obj)$sigma)
  }
  if(ret == "draw"){
    out
  }else{
    prob
  }
}

#' Find type of variable
#'
#' Find the variable type to identify the appropriate model for the variable
#'
#' @param x a vector of values to be evaluated
#' @param ... other arguments to be passed down, currently not implemented.
#'
#' @importFrom stats na.omit
#' @export
find_type <- function(x, ...){
  if(is.numeric(x) & length(unique(na.omit(x))) > 2){
    type <- "lm"
  }
  if(length(unique(na.omit(x))) == 2 & !is.character(x)){
    type <- "glm"
  }
  if(is.factor(x)){
    if(is.ordered(x)){
      type <- "polr"
    }else{
      type <- "multinom"
    }
  }
  type
}

#' Specify a Vote Path Analysis
#'
#' The vote path model estimates independent models that would otherwise use a block-recursive
#' structure.  Each model in each block is fit independently using the appropriate error distribution.
#'
#' @param blocks A list in which each element contains a vector of variable names for variables that will represent
#' that block's effects.  The list may be named or not.
#' @param models If `NULL`, the algorithm will use `find_type()` to find the appropriate model.  This assumes that variables
#' that should be estimated using ordinal regression models are ordered factors.  Otherwise, models can be a named vector of
#' model types for some or all of the variables included in the model.
#' @param data A data frame containing all of the variables in the `blocks` list.
#' @param ... Other arguments to be passed down.
#'
#' @importFrom stats lm glm family binomial reformulate
#' @importFrom MASS polr
#' @importFrom nnet multinom
#'
#' @export
vote_path <- function(blocks,
                      models = NULL,
                      data, ...){

  types <- sapply(c(unlist(blocks)), function(nm)find_type(data[[nm]]))
  allvars <- c(unlist(blocks))
  dv <- allvars[length(allvars)]
  if(!is.null(models)){
    types[match(names(models), names(types))] <- models
  }
  res <- vector(mode="list", length=length(blocks)-1)
  for(i in 2:(length(blocks)-1)){
    mlist <- vector(mode="list", length=length(blocks[[i]]))
    for(j in 1:length(blocks[[i]])){
      form <- reformulate(blocks[[(i-1)]], response=blocks[[i]][j])
      arglist <- list(formula = form, data=data)
      if(types[blocks[[i]][j]] %in% c("polr", "multinom")){
        arglist$Hess <- TRUE
      }
      if(types[blocks[[i]][j]] == "multinom"){
        arglist$maxit <- 250
      }
      if(types[blocks[[i]][j]] == "glm"){
        arglist$family <- binomial
      }
      mlist[[j]] <- do.call(types[blocks[[i]][j]], arglist)
      }
    res[[(i-1)]] <- mlist
  }
  fullform <- reformulate(allvars[-length(allvars)],
                          response=dv)
  arglist <- list(formula = fullform,
                  data=data)
  if(types[dv] %in% c("polr", "multinom")){
    arglist$Hess <- TRUE
  }
  if(types[dv] == "multinom"){
    arglist$maxit <- 250
  }
  if(types[dv] == "glm"){
    arglist$family <- binomial
  }
  res[[(length(blocks)-1)]] <- do.call(types[dv], arglist)
  out <- list(models = res, blocks = blocks)
  class(out) <- "votepath"
  out
}

#' Simulate Variable Effect
#'
#' Simulate a variable's effect in a vote path analysis.
#'
#' @param obj An object of class `votepath`
#' @param data A data frame that contains all of the variables form the analysis.
#' @param varname The name of a variable whose effect will be evaluated.
#' @param diffchange The amount to change `varname`.  Changes will be `x-.5*diffchange` and `x+.5*diffchange`.
#' For categorical variables, the first and last categories will be chosen.  The `diffchange` parameter
#' defines the change so long as `vals=NULL`.  If `vals` is not `NULL`, then those values will be used for everyone.
#' @param vals A vector of length 2 giving the values that will be used to evaluate the effect size.  This will override
#' `diffchange`.  The values must be of the same class as the variable being changed.  For example, if the variable being
#' changed is a factor, the `vals` vector also has to be a factor with the same levels as the variable in `varname`.
#' @param b_var Logical indicating whether sampling variability on the coefficients should be incorporated in the simulation.
#' @param R Number of simulations to be conducted.
#' @param lastMod Should the prediction from the last model be a draw or a the expected value?
#' @param ... Other arguments to be passed down.
#'
#' @importFrom progress progress_bar
#' @importFrom stats sd
#' @export
#'
#'
#'
sim_effect <- function(obj,
                       data,
                       varname,
                       diffchange=c("unit", "sd"),
                       vals=NULL,
                       b_var = TRUE,
                       R=100,
                       lastMod = c("expected", "draw"),
                       ...){
  mods <- obj$models
  blocks <- obj$blocks
  lastMod <- match.arg(lastMod)
  dv <- blocks[[length(blocks)]]
  out_i <- out_d <- out_t <- out_br <-  NULL
  pb <- progress_bar$new(total = R)
  if(!is.null(vals) & length(vals) != 2)stop("vals must be a vector of length 2\n")
  if(!is.null(vals) & inherits(data[[varname]], "factor") & !inherits(vals, "factor"))stop("vals must have the same class as varname\n")
  which_block <- min(which(sapply(blocks, function(x)max(varname == x)) == 1))
  if(is.factor(data[[varname]]) & is.null(vals)){
    levs <- levels(data[[varname]])
    vals <- factor(c(1,length(levs)),
                   levels=1:length(levs),
                   labels=levs)
  }
  med <- vector(mode="list", length=length((which_block+1):(length(blocks)-1)))
  brvars <- c(unlist(blocks[1:which_block]))
  br_form <- reformulate(brvars, response=dv)
  dv_type <- find_type(data[[dv]])
  br_args <- list(formula = br_form, data=data)
  if(dv_type %in% c("polr", "multinom")){
    br_args$Hess <- TRUE
  }
  if(dv_type == "multinom"){
    br_args$maxit <- 250
  }
  if(dv_type == "glm"){
    br_args$family <- binomial
  }
  br_mod <- do.call(dv_type, br_args)

  for(r in 1:R){
  new_0 <- new_1 <- br_0 <- br_1 <- data
  if(is.null(vals)){
    delta <- ifelse(diffchange == "sd", sd(data[[varname]], na.rm=TRUE), 1)
    new_0[[varname]] <- br_0[[varname]] <- new_0[[varname]] - .5*delta
    new_1[[varname]] <- br_1[[varname]] <- new_1[[varname]] + .5*delta
  }else{
    new_0[[varname]] <- br_0[[varname]] <-vals[1]
    new_1[[varname]] <- br_1[[varname]] <-vals[2]
  }
  md0 <- md1 <- data
  k <- 1
  for(i in (which_block+1):(length(blocks)-1)){
    for(j in 1:length(blocks[[i]])){
      new_0[[blocks[[i]][j]]] <- md0[[blocks[[i]][j]]] <- draw_val(mods[[(i-1)]][[j]], new_0, incl_b_var = b_var)
      new_1[[blocks[[i]][j]]] <- md1[[blocks[[i]][j]]] <- draw_val(mods[[(i-1)]][[j]], new_1, incl_b_var = b_var)
    }
    tmp0 <- draw_val(mods[[length(mods)]], md0, ret=lastMod, incl_b_var = b_var)
    tmp1 <- draw_val(mods[[length(mods)]], md1, ret=lastMod, incl_b_var = b_var)
    if(!is.matrix(tmp0))tmp0 <- matrix(tmp0, ncol=1)
    if(!is.matrix(tmp1))tmp1 <- matrix(tmp1, ncol=1)
    med[[k]] <- rbind(med[[k]], colMeans(tmp1-tmp0))
    k <- k+1
  }

  res0 <- draw_val(mods[[length(mods)]], new_0, ret=lastMod, incl_b_var = b_var)
  res1 <- draw_val(mods[[length(mods)]], new_1, ret=lastMod, incl_b_var = b_var)
  if(!is.matrix(res0))res0 <- matrix(res0, ncol=1)
  if(!is.matrix(res1))res1 <- matrix(res1, ncol=1)
  total_effect <- res1-res0

  d0 <- draw_val(mods[[length(mods)]], br_0, ret=lastMod, incl_b_var = b_var)
  d1 <- draw_val(mods[[length(mods)]], br_1, ret=lastMod, incl_b_var = b_var)
  if(!is.matrix(d0))d0 <- matrix(d0, ncol=1)
  if(!is.matrix(d1))d1 <- matrix(d1, ncol=1)

  direct_effect <- d1-d0

  indirect_effect <- total_effect - direct_effect

  be0 <- draw_val(br_mod, br_0, ret=lastMod, incl_b_var = b_var)
  be1 <- draw_val(br_mod, br_1, ret=lastMod, incl_b_var = b_var)
  if(!is.matrix(be0))be0 <- matrix(be0, ncol=1)
  if(!is.matrix(be1))be1 <- matrix(be1, ncol=1)

  out_br <- rbind(out_br, colMeans(be1-be0))

  out_t <- rbind(out_t, colMeans(total_effect))
  out_d <- rbind(out_d, colMeans(direct_effect))
  out_i <- rbind(out_i, colMeans(indirect_effect))
  pb$tick()
  }
  res <- list(total = out_t, direct= out_d, indirect=out_i, br = out_br, mediated=med)
}


######################### SCRIPT 0: SUPPORTING FUNCTIONS #########################

runModel = function(indexu,indexk,NITERATION)
{
  dataset=list(
    N=dim(data0)[1],
    Kk=length(indexk),
    nk=data0[,indexk],
    Ku=length(indexu),
    nu=data0[,indexu],
    Sk=knownpop$real_data[indexk],
    Su=rep(NA,length(indexu)))

  initialisation=list(lambda=0.1)
  jagmod=jags.model(textConnection(model1),data=dataset,inits=initialisation,n.chains=2)
  update(jagmod, n.iter=5000, progress.bar="text")
  posterior = coda.samples(jagmod, c("alpha","lambda","tau","Su"),n.iter=NITERATION,progress.bar="text",thin=10)
  dicsamples = dic.samples(jagmod,type = "pD",n.iter=20000,thin=10)
  results = list(indexk=indexk,indexu=indexu,dataset = dataset,posterior=posterior,dicsamples=dicsamples)
  return(results)
}

runModel_te = function(indexu,indexk,NITERATION,x)
{
  dataset=list(
    N=dim(data0)[1],
    Kk=length(indexk),
    nk=data0[,indexk],
    Ku=length(indexu),
    nu=data0[,indexu],
    Sk=knownpop$real_data[indexk],
    Su=rep(NA,length(indexu)),
    x=x)

  initialisation=list(lambda=0.1)
  jagmod=jags.model(textConnection(model2),data=dataset,inits=initialisation,n.chains=2)
  update(jagmod, n.iter=5000, progress.bar="text")
  posterior = coda.samples(jagmod, c("alpha","lambda",'beta','sigma',"tau","Su"),n.iter=NITERATION,progress.bar="text",thin=10)
  dicsamples = dic.samples(jagmod,type = "pD",n.iter=20000,thin=10)

  results = list(indexk=indexk,indexu=indexu,dataset = dataset,posterior=posterior,dicsamples=dicsamples)

  return(results)
}

runModel_te_be = function(indexu,indexk,NITERATION,x)
{
  dataset=list(
    N=dim(data0)[1],
    Kk=length(indexk),
    nk=data0[,indexk],
    Ku=length(indexu),
    nu=data0[,indexu],
    Sk=knownpop$real_data[indexk],
    Su=rep(NA,length(indexu)),
    x=x,
    age=demo$age-40.5,
    sex=demo$sex-0.49,
    malay=demo$malay-0.15,
    indian=demo$indian-0.07)

  initialisation=list(lambda=0.1)
  jagmod=jags.model(textConnection(model3),data=dataset,inits=initialisation,n.chains=2)
  update(jagmod, n.iter=5000, progress.bar="text")
  posterior = coda.samples(jagmod, c("alpha","lambda",'beta','sigma','sigmab',"tau","Su","b1u","b2u","b3u",'b4u',"b1k","b2k",'b3k','b4k'),n.iter=NITERATION,progress.bar="text",thin=10)
  dicsamples = dic.samples(jagmod,type = "pD",n.iter=20000,thin=10)

  results = list(indexk=indexk,indexu=indexu,dataset = dataset,posterior=posterior,dicsamples=dicsamples)
  return(results)
}

### Models

model1 = 'model {

for(i in 1:N)

{

  for(k in 1:Ku)

  {

  nu[i,k] ~ dpois(lambda*alpha[i]*Su[k])

  }

  for(k in 1:Kk)

  {

  nk[i,k] ~ dpois(lambda*alpha[i]*Sk[k])

  }

  alpha[i]~dlnorm(0,tau)

}

for(k in 1:Ku)

{

  Su[k]~dunif(0,2500000)

}

for(k in 1:Kk)

{

  Sk[k]~dunif(0,2500000)

}

lambda ~ dunif(0,10)

tau ~ dunif(0,10)

}
'

model2 ='model {

for(i in 1:N)

{

  for(k in 1:Ku)

  {

  nu[i,k] ~ dpois(lambda*alpha[i]*exp(beta[k]*x[i,k])*Su[k])

  }

  for(k in 1:Kk)

  {

  nk[i,k] ~ dpois(lambda*alpha[i]*Sk[k])

  }

  alpha[i]~dlnorm(0,tau)

}

for(k in 1:Ku)

{

  Su[k]~dunif(0,2500000)

}

for(k in 1:Kk)

{

  Sk[k]~dunif(0,2500000)

}

for(k in 1:Ku)

{

  beta[k]~dnorm(0,(1/sigma)^2)

}

lambda ~ dunif(0,10)

tau ~ dunif(0,10)

sigma ~ dgamma(1,0.01)
}
'

model3 = 'model {

for(i in 1:N)

{

  for(k in 1:Ku)

  {

  nu[i,k] ~ dpois(lambda*alpha[i]*exp(beta[k]*x[i,k])*exp(b1u[k]*age[i])*exp(b2u[k]*sex[i])*exp(b3u[k]*malay[i])*exp(b4u[k]*indian[i])*Su[k])

  }

  for(k in 1:Kk)

  {

  nk[i,k] ~ dpois(lambda*alpha[i]*exp(b1k[k]*age[i])*exp(b2k[k]*sex[i])*exp(b3k[k]*malay[i])*exp(b4k[k]*indian[i])*Sk[k])

  }

  alpha[i]~dlnorm(0,tau)

}

for(k in 1:Ku)

{

  Su[k]~dunif(0,2500000)

}

for(k in 1:Kk)

{

  Sk[k]~dunif(0,2500000)
  b1k[k]~dnorm(0,(1/sigmab)^2)
  b2k[k]~dnorm(0,(1/sigmab)^2)
  b3k[k]~dnorm(0,(1/sigmab)^2)
  b4k[k]~dnorm(0,(1/sigmab)^2)
}

for(k in 1:Ku)

{

  beta[k]~dnorm(0,(1/sigma)^2)
  b1u[k]~dnorm(0,(1/sigmab)^2)
  b2u[k]~dnorm(0,(1/sigmab)^2)
  b3u[k]~dnorm(0,(1/sigmab)^2)
  b4u[k]~dnorm(0,(1/sigmab)^2)
}

lambda ~ dunif(0,10)

tau ~ dunif(0,10)

sigma ~ dgamma(1,0.01)
sigmab ~ dgamma(1,0.01)
}
'


#
# Secure Digitalisation Monte Carlo Simulation Script
#
# This script runs a Monto Carlo simulation using breach likelihood and cost
# figures derived from the Cyber Security Breaches Survey 2020 (CSBS).
#	This script is an unfinished prototype, and has since been superseded by
# `montecarlo.py`.
#
# Acknowledgements: Dr Dan Prince & Dr Chris Sherlock
#

masses = c(0.54, 0.1058, 0.1012, 0.0966, 0.069, 0.0368, 0.0414)
boundaries = c(1, 2, 8, 18, 80, 400, 8000)

Fs = cumsum(masses)
plot(log(boundaries), log(1 - Fs))

xs = log(boundaries)
ys = log(1 - Fs)
fit = lm(ys ~ xs)
summary(fit)

alogb = fit$coeff[1]
a = -fit$coeff[2]
b = exp(alogb/a)
print(a)
print(b)

n = 10000

us = runif(n)
xs = b / (1 - us)^(1 / a)
print()
p0 = mean(xs < boundaries[1])
p1 = mean(xs < boundaries[2]) - p0
p2 = mean(xs < boundaries[3]) - p0 - p1
p3 = mean(xs < boundaries[4]) - p0 - p1 - p2
p4 = mean(xs < boundaries[5]) - p0 - p1 - p2 - p3
p5 = mean(xs < boundaries[6]) - p0 - p1 - p2 - p3 - p4
ps = c(p0, p1, p2, p3, p4, p5, 1 - (p0 + p1 + p2 + p3 + p4 + p5))

print(ps)
print(masses)

nattacks = floor(xs)
hist(log10(nattacks),
     main = "Histogram of Number of Attacks/Breaches Over 12 Months",
     xlab = expression("Number of Attacks (log"[10]*")"),
     ylab = "Frequency",
     breaks = 0:12)

# Plots the distribution for the average cost of breach(es) over 12 months

mean = 3230
median = 274

logstd = sqrt(2 * (log(mean) - if (median == 0) 0 else log(median)))
std = exp(1)^logstd

curve(dlnorm(x, log(mean), log(std)), from=1, to=5000,
      main = "Average annual breach cost distribution",
      xlab = 'Cost (£)',
      ylab = 'Density',
      lwd = 2)

# Runs the MonteCarlo simulation

simulateCosts <- function(n) {
  return(if (n >= 1) sum(rlnorm(n, loc, shape)) else 0)
}

n = 10000

loc <- log(mean^2 / sqrt(std^2 + mean^2))
shape <- sqrt(log(1 + (std^2 / mean^2)))

numAttacks <- sample(log10(nattacks), n)
results <- sapply(numAttacks, simulateCosts)

hist(results,
     main = "Histogram of Total Costs Over 12 Months (Monte Carlo sim)",
     xlab = "Total cost (£)")

d <- density(results)
plot(d,
     main="Density of Total Costs Over 12 Months (Monte Carlo sim)",
     xlab=expression("Total Cost (£)"),
     ylab="Density")

# Get loss exceedance
# TODO: needs to be prettier, but `evaluate::loss_exceedance_curve()` is broken

maxValue = 2500
numOver <- length(results[results > maxValue])
risk = numOver/n

plot(d,
     main="Loss Exceedance (Monte Carlo sim)",
     xlab=expression("Total Cost (£)"),
     ylab="Density")

abline(v = maxValue, col="red", lwd=3, lty=2)
text(3000, 4e-04, labels=paste(floor(risk*100), "% chance of ≥£", maxValue, " losses"), adj=c(0, 0.5))