#' @export
#'
#' @title checkConvergence - Check the convergence of a mcmc.list object
#'
#' @description Run various diagnostic procedures in the \code{coda} package
#' to check convergence of a set of mcmc chains.
#'
#' @param obj An mcmc.list object from the \code{rjags} package.  These are output
#' by the \code{coda.samples} function. This mcmc.list must contain 2 or more chains.
#'
#' @param quiet Whether to print any output on screen.
#'
#' @details This routine runs the Gelman and Rubin (1992) diagnostic for
#' a set of MCMC chains by calling \code{gelman.diag} in the \code{coda} package.
#'
#' @return A list with the following components
#' \itemize{
#'   \item converged: If the uppper limits of the  'potential scale
#'   reduction factors' associated with all parameters are less than
#'   \code{criterion}, the chain is declared converged and this is TRUE.
#'   Otherwise, this component of the returns is FALSE.
#'   \item Rhats: the 'potential scale reduction factors' or Rhats
#'   associated with all parameters.
#'  }
#'
#' @author Trent McDonald
#'
#' @references
#' Gelman, A and Rubin, DB (1992) Inference from iterative simulation
#' using multiple sequences, Statistical Science, 7, 457-511.
#'
#' @seealso \code{\link{gelman.diag}}, \code{\link{checkIsConverged}}
#'
#' @examples
#' \dontrun{
#' jags = jags.model(file="someJAGSFile.txt",
#'    data=someJAGS.data, inits=someJAGS.inits,
#'    n.chains=3,n.adapt=100)
#' update(jags, n.iter=1000)
#' out = coda.samples(jags,
#'    variable.names=c("someParameter"),
#'    n.iter=1000,
#'    thin=2)
#'
#' conf <- chechIsConverged(out)
#' }

checkIsConverged <- function(obj, criterion=1.1, quiet=FALSE){

  Rhats <- gelman.diag(obj)
  if(!quiet){
    cat(paste0(paste(rep("-",4),collapse="")," Checking convergence:\n"))
    print(Rhats)
  }
  vnames <- dimnames(Rhats$psrf)[[1]]
  Rhats <- Rhats$psrf[,"Upper C.I."]
  names(Rhats) <- vnames
  if( any(Rhats > criterion, na.rm=TRUE) ){
    if(!quiet){
      cat("The following coefficients probably did not converge (Rhat > 1.1):\n")
      print(names(Rhats)[Rhats > criterion])
      cat("Try increasing nburns and/or nthins or informing the coefficient's priors.\n")
    }
    ans <- FALSE
  } else {
    if(!quiet){
      cat("The model converged. All Rhats < 1.1\n")
    }
    ans <- TRUE
  }

  ans <- list(converged=ans, Rhats=Rhats)

}


#!/usr/local/bin/Rexec
########### set arguments list ###############################
args<-commandArgs();
args_start=grep("--args",args)+1;
if  (length(args_start)>0 && args_start < length(args) ) {
  args<-args[args_start:length(args)]
} else {
  args=c()
}
#############################################################
rm(list=ls())

mwpp<-function(tau1,tau2,k)
{
  r=tau2/tau1;
  s1=exp((r+1)/r);
  deltat = 0;

  if(tau1>=tau2)
  {
    dw     = -k^2*(2*r-2*r*exp(r+1)+r^2-1)/(tau1*exp(r+1)*(r+1)^3)
  } else if(tau1<tau2)
  {
    dw     = -k^2*(2*r-2*r*s1-r^2+1)/(tau1*s1*(r+1)^3)
  }
  return(c(deltat,dw))
}

mwnp<-function(tau1,tau2,k)
{
  r=tau2/tau1;
  s1=exp(r+1);

  deltat = tau1* ( 3*r*s1 -r  +r^2*s1 -r^2 +2 )/( (r*s1 + 1)*(r+1));
  dw     = k^2*(r*s1+1)*exp(-(r+4*r*s1+3*r^2*s1+r^3*s1+3)/((r*s1+1)*(r+1)))/(tau1*(r+1)^2);

  return(c(deltat,dw))
}

mwnn<-function(tau1,tau2,k)
{
  r=tau2/tau1;

  deltat=0;
  dw=0;

  if(tau1>=tau2)
  {
    deltat = -tau1*(r^2+r-2)/(r+1)
    dw     = k^2*exp(-(r+3)/(r+1))/(tau1*(r+1)^2)
  } else
  {
    deltat = tau1*(-2*r^2+r+1)/(r+1)
    dw     = k^2*(3*r-1)*exp(-(2*r^2+3*r-1)/(r*(r+1)))/(tau1*(r+1)^3)
  }

  return(c(deltat,dw))
}

mwpn<-function(tau1,tau2,k)
{
  r=tau2/tau1;
  s1=exp((r+1)/r)

  deltat = -(r*tau1*( s1 -r +3*r*s1 +2*r^2 -1 ))/( (r + s1)*(r+1));
  dw     = k^2*(r+s1)*exp(-(s1+3*r*s1+4*r^2*s1+r^2+3*r^3)/(r*(r+s1)*(r+1)))/(tau1*(r+1)^2);

  return(c(deltat,dw));
}

mwps<-function(tau1,tau2,k)
{
  r=tau2/tau1;
  s1=exp((r+1)/r);

  deltat = r*tau1* ( 2*r -2*r*s1 -r^2 +1 )/( (r+s1)*(r+1));
  dw     = k^2*r*(r+s1)*exp(-( s1+2*r*s1+3*r^2*s1+2*r^3 ) /(r*(r+s1)*(r+1)) )/((r+1)^2);
  return(c(deltat,dw))
}

mwsp<-function(tau1,tau2,k)
{
  r=tau2/tau1;
  s1=exp((r+1));

  deltat = -tau1* ( 2*r -2*r*s1 +r^2 -1 )/( (r*s1+1)*(r+1));
  dw     = k^2*(r*s1+1)*exp(-( 3*r*s1+2*r^2*s1+r^3*s1+2 ) /((r*s1+1)*(r+1)) )/((r+1)^2);

  return(c(deltat,dw))
}

mwns<-function(tau1,tau2,k)
{
  r=tau2/tau1;
  if(tau1>=tau2)
  {
    deltat = 2*tau1/(r+1);
    dw     = k^2*r*exp(-(2/(r+1)))/(r+1)^2;
  }
  else
  {
    deltat = tau1*(-r^2+2*r+1)/(r+1);
    dw     = k^2*r^2*exp(-(2*r/(r+1)))/(r+1)^2;
  }

  return(c(deltat,dw))
}

mwsn<-function(tau1,tau2,k)
{
  r=tau2/tau1;
  if(tau1>=tau2)
  {
    deltat = -tau1*(r^2+2*r-1)/(r+1);
    dw     = k^2*exp(-(2/(r+1)))/(r+1)^2;
  }
  else
  {
    deltat = -2*r^2*tau1/(r+1);
    dw     = k^2*r*exp(-(2*r/(r+1)))/(r+1)^2;
  }

  return(c(deltat,dw))
}

dwnnh<-function(deltat,tau1,tau2,k)
{
  y =
  exp(-(deltat+tau1+tau2)/tau1)*
  k^2*
  (-tau1^2+2*tau1*tau2+tau2^2+deltat*(tau1+tau2)
   )/
  (tau1+tau2)^3;

  return(y);
}

dwnnl<-function(deltat,tau1,tau2,k)
{
  y =
  -exp(-(-deltat+tau1+tau2)/tau2)*
  k^2*
  (-tau1^2-2*tau1*tau2+tau2^2+deltat*(tau1+tau2)
   )/
  (tau1+tau2)^3;
  return(y);
}

dwnph<-function(deltat,tau1,tau2,k)
{
  y =
  exp(-(deltat+tau1+tau2)/tau1)*
  k^2*
  (
   exp(1+tau2/tau1)*
   tau2*(-2*tau1^2+deltat*(tau1+tau2))+
   tau1*(-tau1^2+2*tau1*tau2+tau2^2+deltat*(tau1+tau2))
   )/
  (tau1*(tau1+tau2)^3);
  return(y);
}

dwnpl<-function(deltat,tau1,tau2,k)
{

  y =
  -exp(-(deltat*tau2+(tau1+tau2)^2)/(tau1*tau2))*
  k^2*
  (
   exp(1+(tau1/(tau2)))*
   (tau1^2-2*tau1*tau2-tau2^2-deltat*(tau1+tau2))+
   exp(((deltat+tau2)*(tau1+tau2))/(tau1*tau2))*
   (tau1^2+2*tau1*tau2-tau2^2-deltat*(tau1+tau2))
   )/ ((tau1+tau2)^3);
  return(y);
}

dwnsh<-function(deltat,tau1,tau2,k)
{

  y =
  exp(-deltat/tau1)*
  k^2*
  tau2*(tau1*(-tau1+tau2)+deltat*(tau1+tau2))/
  (tau1+tau2)^3;

  return(y);
}

dwnsl<-function(deltat,tau1,tau2,k)
{

  y =
  exp(-(-deltat+tau1+tau2)/tau2)*
  k^2*
  tau2*(-deltat*(tau1+tau2)+tau1*(tau1+3*tau2))/
  (tau1+tau2)^3;

  return(y);
}

dwpnh<-function(deltat,tau1,tau2,k)
{

  y =
  exp(-(deltat*tau2+(tau1+tau2)^2)/(tau1*tau2))*
  k^2*
  (
   exp(1+((tau1)/(tau2)))*
   (tau1^2-2*tau1*tau2-tau2^2-deltat*(tau1+tau2))+
   exp(((deltat+tau2)*(tau1+tau2))/(tau1*tau2))*
   (tau1^2+2*tau1*tau2-tau2^2-deltat*(tau1+tau2))
   )/
  ((tau1+tau2)^3);
  return(y);
}

dwpnl<-function(deltat,tau1,tau2,k)
{

  y =
  -exp(-(-deltat+tau1+tau2)/(tau2))*
  k^2*
  (
   tau2*(-tau1^2-2*tau1*tau2+tau2^2+deltat*(tau1+tau2))+
   exp(1+((tau1)/(tau2)))*
   tau1*(2*tau2^2+deltat*(tau1+tau2))
   )/
  (tau2*((tau1+tau2)^3));

  return(y);
}

dwpph<-function(deltat,tau1,tau2,k)
{

  y =
  exp(-1-deltat/(tau1)-(tau1)/(tau2))*
  k^2*
  (
   -exp(1+tau1/tau2)*
   tau2*(-2*tau1^2+deltat*(tau1+tau2))+
   exp(deltat*(1/tau1+1/tau2))*
   tau1*(-tau1^2-2*tau1*tau2+tau2^2+deltat*(tau1+tau2))
   )/
  (tau1*(tau1+tau2)^3);
  return(y);
}

dwppl<-function(deltat,tau1,tau2,k)
{
  y =
  exp(-(deltat+tau1+tau2)/(tau1))*
  k^2*
  (
   -tau2*(-tau1^2+2*tau1*tau2+tau2^2+deltat*(tau1+tau2))+
   exp(((deltat+tau2)*(tau1+tau2))/(tau1*tau2))*
   tau1*(2*tau2^2+deltat*(tau1+tau2))
   )/
  (tau2*((tau1+tau2)^3));

  return(y);
}

dwppml<-function(deltat,tau1,tau2,k)
{

  y =
  exp(-(-deltat+tau1+tau2)/tau2)*
  k^2*
  (tau2*(-tau1^2-2*tau1*tau2+tau2^2 +
         deltat*(tau1+tau2))+
   exp(1+tau1/tau2)*
   tau1*(2*tau2^2+deltat*(tau1+tau2))
   )/(tau2*(tau1+tau2)^3);

  return(y);
}

dwppmr<-function(deltat,tau1,tau2,k)
{
  y =
  exp(-(deltat+tau1+tau2)/tau1)*
  k^2*
  (
   -deltat*(tau1+tau2)*
   (tau1+exp(1+tau2/tau1)*tau2)+
   tau1*(tau1^2+2*(-1+exp(1+tau2/tau1))*tau1*tau2-tau2^2)
   )/
  (tau1*(tau1+tau2)^3);

  return(y);
}

dwpsh<-function(deltat,tau1,tau2,k)
{

  y =
  exp(-1-deltat/tau1-tau1/tau2)*
  k^2*
  tau2* (
         exp(1+tau1/tau2)*(tau1*(tau1-tau2)-deltat*(tau1+tau2))+
         exp(deltat*(1/tau1+1/tau2))*
         (-deltat*(tau1+tau2)+tau1*(tau1+3*tau2))
         )/
  (tau1+tau2)^3;

  return(y);
}

dwpsl<-function(deltat,tau1,tau2,k)
{

  y =
  -exp(-(-deltat+tau1+tau2)/tau2)*
  k^2*
  (
   exp(1+tau1/tau2)*
   tau1*(tau2*(-tau1+tau2)+deltat*(tau1+tau2))+
   tau2*(deltat*(tau1+tau2)-tau1*(tau1+3*tau2))
   )/
  (tau1+tau2)^3;
  return(y);
}

dwsnh<-function(deltat,tau1,tau2,k)
{

  y =
  exp(-((deltat+tau1+tau2)/tau1))*
  k^2*
  tau1*(deltat*(tau1+tau2)+tau2*(3*tau1+tau2))/
  (tau1+tau2)^3;

  return(y);
}

dwsnl<-function(deltat,tau1,tau2,k)
{
  y =
  -exp(deltat/tau2)*
  k^2*
  tau1*(tau2*(-tau1+tau2)+deltat*(tau1+tau2))/
  (tau1+tau2)^3;

  return(y);
}

dwsph<-function(deltat,tau1,tau2,k)
{

  y =
  exp(-(deltat+tau1+tau2)/tau1)*
  k^2*
  (
   exp(1+tau2/tau1)*
   tau2*(tau1*(-tau1+tau2)+deltat*(tau1+tau2))+
   tau1*(deltat*(tau1+tau2)+tau2*(3*tau1+tau2))
   )/
  (tau1+tau2)^3;

  return(y);
}

dwspl<-function(deltat,tau1,tau2,k)
{

  y =
  exp(-((deltat+tau1+tau2)/tau1))*
  k^2*
  tau1*(
        deltat*tau1+
        deltat*tau2+
        3*tau1*tau2+
        tau2^2+
        exp((deltat+tau2)*(tau1+tau2)/(tau1*tau2))*
        (tau2*(-tau1+tau2)+deltat*(tau1+tau2)))/
  (tau1+tau2)^3;

  return(y);
}

icomponents<-function(
                width=4,
                height=6,
                name='',
                EPS=FALSE,
                dt=.01,
                tau1=1,
                tau2=1,
                k=1,
                gpp=0,
                gnp=0,
                gpn=0,
                gnn=0,
                eps=0,
                esp=0,
                ens=0,
                esn=0)
{

  id=diag(8);

  gap=.01;
  range=seq(-20,20,gap);
  trange=length(range);
  tt=1:trange;
  w=rep(0,length(range));

  if ( tau1 >= tau2 ) {
    t = 1;
    for (deltat in range)
    {
      if ( deltat <= -tau2 )
      {
        w[t] =
        gnn*dwnnl(deltat,tau1,tau2,k)   +
        gpn*dwpnl(deltat,tau1,tau2,k)  +
        esn*dwsnl(deltat,tau1,tau2,k)  +
        ens*dwnsl(deltat,tau1,tau2,k) +
        eps*dwpsl(deltat,tau1,tau2,k);
      } else if ( deltat <= 0 )
      {
        w[t] =
        gpp*dwppl(deltat,tau1,tau2,k)  +
        gnn*dwnnl(deltat,tau1,tau2,k)  +
        gpn*dwpnh(deltat,tau1,tau2,k)  +
        esn*dwsnh(deltat,tau1,tau2,k)  +
        ens*dwnsl(deltat,tau1,tau2,k)  +
        esp*dwspl(deltat,tau1,tau2,k)  +
        eps*dwpsl(deltat,tau1,tau2,k);
      } else if ( deltat <= (tau1 - tau2) )
      {
        w[t] =
        gpp*dwppmr(deltat,tau1,tau2,k)  +
        gnn*dwnnl(deltat,tau1,tau2,k)   +
        gpn*dwpnh(deltat,tau1,tau2,k)   +
        esn*dwsnh(deltat,tau1,tau2,k)  +
        ens*dwnsl(deltat,tau1,tau2,k)  +
        esp*dwsph(deltat,tau1,tau2,k)  +
        eps*dwpsh(deltat,tau1,tau2,k);
      } else if ( deltat <= tau1 )
      {
        w[t] =
        gpp*dwpph(deltat,tau1,tau2,k)  +
        gnn*dwnnh(deltat,tau1,tau2,k)  +
        gnp*dwnpl(deltat,tau1,tau2,k)  +
        esn*dwsnh(deltat,tau1,tau2,k)  +
        ens*dwnsl(deltat,tau1,tau2,k)  +
        esp*dwsph(deltat,tau1,tau2,k)  +
        eps*dwpsh(deltat,tau1,tau2,k);
      } else
      {
        w[t] =
        gnn*dwnnh(deltat,tau1,tau2,k)  +
        gnp*dwnph(deltat,tau1,tau2,k)  +
        esn*dwsnh(deltat,tau1,tau2,k)  +
        ens*dwnsh(deltat,tau1,tau2,k) +
        esp*dwsph(deltat,tau1,tau2,k);
      }
      t = t + 1;
    }
  }
  else
  {
    t = 1;
    for (deltat in range)
    {
      if ( deltat <= -tau2 )
      {
        w[t] =
        gnn*dwnnl(deltat,tau1,tau2,k)   +
        gpn*dwpnl(deltat,tau1,tau2,k)   +
        esn*dwsnl(deltat,tau1,tau2,k)   +
        ens*dwnsl(deltat,tau1,tau2,k)   +
        eps*dwpsl(deltat,tau1,tau2,k);
      } else if ( deltat <= (tau1 - tau2) )
      {
        w[t] =
        gpp*dwppl(deltat,tau1,tau2,k)   +
        gnn*dwnnl(deltat,tau1,tau2,k)   +
        gpn*dwpnh(deltat,tau1,tau2,k)   +
        esn*dwsnh(deltat,tau1,tau2,k)   +
        ens*dwnsl(deltat,tau1,tau2,k)   +
        esp*dwspl(deltat,tau1,tau2,k)   +
        eps*dwpsl(deltat,tau1,tau2,k);
      } else if ( deltat <= 0 )
      {
        w[t] =
        gpp*dwppml(deltat,tau1,tau2,k)  +
        gnn*dwnnh(deltat,tau1,tau2,k)   +
        gnp*dwnpl(deltat,tau1,tau2,k)   +
        esn*dwsnh(deltat,tau1,tau2,k)   +
        ens*dwnsl(deltat,tau1,tau2,k)   +
        esp*dwspl(deltat,tau1,tau2,k)   +
        eps*dwpsl(deltat,tau1,tau2,k);
      } else if ( deltat <= tau1 )
      {
        w[t] =
        gpp*dwpph(deltat,tau1,tau2,k)   +
        gnn*dwnnh(deltat,tau1,tau2,k)   +
        gnp*dwnpl(deltat,tau1,tau2,k)   +
        esn*dwsnh(deltat,tau1,tau2,k)   +
        ens*dwnsl(deltat,tau1,tau2,k)   +
        esp*dwsph(deltat,tau1,tau2,k)   +
        eps*dwpsh(deltat,tau1,tau2,k);
      } else
      {
        w[t] =
        gnn*dwnnh(deltat,tau1,tau2,k)   +
        gnp*dwnph(deltat,tau1,tau2,k)   +
        esn*dwsnh(deltat,tau1,tau2,k)   +
        ens*dwnsh(deltat,tau1,tau2,k)   +
        esp*dwsph(deltat,tau1,tau2,k);
      }
      t = t + 1;
    }
  }

  graphics.off();

  xgap=range[length(range)]/4;
  xlim=c((range[1]-4*xgap),range[length(range)]+3*xgap)
  ylim=c(-3*max(w)/10,max(w)+3*(max(w)/10))
  axlim=c((range[1]-xgap/2),range[length(range)]+xgap/2)
  aylim=c(-3*max(w)/10,max(w)+3*(max(w)/10))

  if(EPS==TRUE) {
    postscript(
               paste('integral_component_',name,'.eps',sep=''),
               onefile=FALSE,
               horizontal=FALSE,
               width=width,height=height,
               pointsize=11,
               family="Times");
  }

  par(mar=c(100,100,1,1)*.005)

  plot(
       range,
       w,
       type='l',
       frame.plot=FALSE,
       axes=FALSE,
       xlab='',
       ylab='',
       lwd=1,
       xlim=xlim,
       ylim=ylim,
       family="serif")
  polygon(c(range[1],range,range[length(range)]),c(0,w,0), col='#DDDDDD',border=NA)
  lines(range,w,lwd=1);

  d<-c()
  d<-rbind(d,c(rbind(axlim,aylim*0)))
  d<-rbind(d,c(rbind(axlim*0,aylim)))
  arrows(d[,1],d[,2],d[,3],d[,4],lwd=1,length=.08,code=3);

  rr = (aylim[2]-aylim[1])/2;

  kappa=(k/100)/2;

  arrows(
         axlim[1]-10,
         rr-kappa,
         axlim[1]-10,
         rr+kappa,
         ,lwd=.5,length=.01,angle=90,code=3);
  text(axlim[1]-8,(aylim[2]-aylim[1])/2,expression( paste("") %prop% italic(kappa)),adj=c(.1,.5),cex=1)

  arrows(
         axlim[2]+6,
         rr+rr/8,
         (axlim[2]+6)-tau1,
         rr+rr/8,
         ,lwd=.5,length=.01,angle=90,code=3);
  text(axlim[2]+10,
         rr+rr/8,
       expression(italic(tau[1])),adj=c(.5,.5),cex=1)
  arrows(
         axlim[2]+6,
         rr-rr/8,
         (axlim[2]+6)-tau2,
         rr-rr/8,
         ,lwd=.5,length=.01,angle=90,code=3);
  text(axlim[2]+10,
         rr-rr/8,
       expression(italic(tau[2])),adj=c(.5,.5),cex=1)

  lmax<-c('pp','np','pn','nn','ps','sp','ns','sn')
  cc<-sum(c(gpp,gnp,gpn,gnn,eps,esp,ens,esn)*1:8);

  #ssubs=substitute(w[index],list(index=lmax[cc]));
  ssubs="w";
  text(-1.2*xgap,ylim[2]-(1/20)*ylim[2],substitute(bolditalic(paste(Delta,index,sep='')),list(index=ssubs)),cex=1)
  text(axlim[2]+6,0,expression(italic(paste(Delta,t))),adj=c(.5,.5),cex=1)
  text(axlim[1]-12,0,expression(italic(-paste(Delta,t))),adj=c(.5,.5),cex=1)

  # if(tau2>tau1) {
    # txt=expression(italic(tau[1]<tau[2]));
  # } else if(tau1>tau2) {
    # txt=expression(italic(tau[2]<tau[1]));
  # }
  # else {
    # txt=expression(italic(tau[1]==tau[2]));
  # }
  # text(4*xgap,ylim[2]-(1/20)*ylim[2],txt,cex=1)
#
  p=c(0,0);
  if(gnp==1)
  {
    p=mwnp(tau1,tau2,k);
  } else if(gnn==1) {
    p=mwnn(tau1,tau2,k);
  } else if(gpp==1) {
    p=mwpp(tau1,tau2,k);
  } else if(gpn==1) {
    p=mwpn(tau1,tau2,k);
  } else if(eps==1) {
    p=mwps(tau1,tau2,k);
  } else if(esp==1) {
    p=mwsp(tau1,tau2,k);
  } else if(ens==1) {
    p=mwns(tau1,tau2,k);
  } else if(esn==1) {
    p=mwsn(tau1,tau2,k);
  }

  tc<-c(axlim[2]-axlim[2]*1/8,aylim[2]-aylim[2]*1/8);
  gap=c(axlim[2]*1/32,aylim[2]*1/32)

  #text(p[1]+3*gap[1],p[2],substitute(italic(M[index]),list(index=lmax[cc])),adj=c(.1,.1),cex=2)

  points(p[1],p[2],cex=.5,pch=21,bg='#999999');

  if(EPS==TRUE) {
    dev.off();
  }

}

allcomponents<-function()
{

  labels=c('gpp','gnp','gpn','gnn','eps','esp','ens','esn')
  taus=c('t2t1','tt','t1t2')

  k=1
  for(tau2 in c(2,3,4))
  {
    for(x in 1:8)
    {

      cmp=rep(0,8);
      cmp[x]=1;
      icomponents(tau1=3,tau2=tau2,
                  EPS=TRUE,
                  width=1.7,height=1,
                  name=paste(labels[x],'_',taus[k],sep=''),
                  gpp=cmp[1],
                  gnp=cmp[2],
                  gpn=cmp[3],
                  gnn=cmp[4],
                  eps=cmp[5],
                  esp=cmp[6],
                  ens=cmp[7],
                  esn=cmp[8])
    }
    k=k+1;
  }

}


#########################################################################################
###### This file provides functions implement the Consonant Likelihood Ratio Test  ######
###### for multiple endpoints problem.                                             ######
###### Copyright(c) 2011 Bushi Wang.                                               ######
###### Modified May 3, 2011, version 1.0.1                                         ######
###### This code is distributed WITHOUT ANY WARRANTY.                              ######
#########################################################################################
###### Modified May 24, 2011, version 1.0.2                                        ######
###### In this version, .CLRT.PS4.test has been modified to return p-value and cv. ######
#########################################################################################
###### Modified September 19, 2011, version 1.1.0                                  ######
###### Build R package clrt.                                                       ######
#########################################################################################

# The program is only for the case with one primary and one secondary endpoint problem.
# Comparing k-1 doses of study drug with a control.

# If m is the number of endpoints, we restrict m=2.

# The natural partition divides the parameter space into (m+1)^(k-1)=26 pieces for k=4.
#   Thus there are 26 null hypotheses to test. The null distribution of the parameter
#   of interest in all 26 hypotheses are identical, which assumes there is no dose effect
#   for both primary and secondary endpoints.

# We first generate simu=10^5 datasets, each contains k=4 groups of 2-by-1 vectors,
#   each group represent the patients receiving a paticular dose. Thus the number
#   of vectors in each group is the number of patients in this group.

# Next we calculate the LRT for each of these simu=10^5 datasets. Each LRT is a
#   26-by-1 vector indicating test statistic for each null hypothesis.

# In order to inplement the power of Consonant likelihood ratio test, we generate
#   powersimu=10^5 datasets following some senario with dose effect and known
#   correlation between endpoints. Then put each one of this powersimu=10^5
#   dataset into the original simulated dataset and calculate the p-value according
#   to the complete consonant adjustment. Thus we get powersimu=10^5 p-values each
#   one a 26-by-1 vector.

# For each of the powersimu=10^5 26-by-1 p-values, find the 2-by-k inference matrix.
#   Average among the powersimu=10^5 inference matrix we get the power.

.Constraint<-function(label,k=4){
	# label is a length k-1 vector indicating the label of an intersection hypothesis.
	# It follows the definition as in Table 1 and 2.
    hnullp<-hnulls<-matrix(0,nrow=k-1,ncol=k)
    for(i in 1:(k-1)){
        if(label[i]==1){
            hnullp[i,c(k,i)]<-c(1,-1)     # \Theta_i^{e_i}
        }else if(label[i]==2){
            hnulls[i,c(k,i)]<-c(1,-1)
        }
    }
    return(list('hnullp'=t(hnullp),'hnulls'=t(hnulls)))
}

.naturalpartition<-function(k=4,m=2,balanced=F){
    #k is the number of treatment arms, including control.
    nhypo<-(m+1)^(k-1)-1
    npmtrx<-matrix(NA,nrow=nhypo+1,ncol=k-1)
    for(a in 1:(k-1))npmtrx[,a]<-as.numeric(sapply(1:(m+1),function(x)rep(x,(m+1)^(k-1-a))))
    npmtrx<-npmtrx[1:nhypo,]
    # npmtrx gives all the possible labelings of intersection hypotheses

    if(balanced){
		# In the case of balanced treatment arms, the computation of critical constants can be greatly
		# 	simplified by sharing the same values among certain intersection hypohteses.
		# For example, hypothesis H_121 and H_112 will use the same critical value.
        labmtrx<-t(apply(npmtrx,1,sort))
        diff.label<-rep(1,nhypo)
        unique.label<-list()
        for(i in 1:nhypo){
            if(diff.label[i]==0){
                unique.label[[i]]<-0;
                next;
            }
            unique.label[[i]]<-which(sapply(1:nhypo,function(x)all(labmtrx[x,]==labmtrx[i,])))
            diff.label[ unique.label[[i]] ]<-0
        }
        balanced<-unique.label
    }

    # Some general definition, specified below.
	Comp.Amat<-list()
    component.array<-list()
    row.ind<-list()
    active.array<-list()
    if(k>3)col.ind<-lapply(1:(k-2),function(x)matrix(nrow=choose(k-1,x+1),ncol=choose(x+1,x)))

	for(cross in 1:(k-1)){
        component.array[[cross]]<-array(m+1,dim=c(m^cross,k-1,choose(k-1,cross)))
		# component.array also gives the labeling of all intersection hypotheses.
		# However, we may locate certain intersection hypothesis through component.array
        matrix.comb<-combn(k-1,cross)
        active.array[[cross]]<-matrix(NA,nrow=m^cross,ncol=cross)
        for(a in 1:cross)active.array[[cross]][,a]<-as.numeric(sapply(1:m,function(x)rep(x,m^(cross-a))))
        # active.array[[cross]] gives the possible combination of endpoints in a "cross"-way intersection.

		for(i in 1:choose(k-1,cross))component.array[[cross]][,matrix.comb[,i],i]<-active.array[[cross]]
        # component.array[[cross]] is an array, which consists of "choose(k-1,cross)" matrices.
		#	The number "cross" indicates how many original hypotheses involved in the intersection.
		#	Each matrix, for example, component.array[[cross]][,,1], has each row a label for one paticular
		#	intersection. The number of rows in each matrix is m^cross.
		Comp.Amat[[cross]]<-list()
        # Comp.Amat are the constraint matrix for the component hypothesis.
		# It provide guidance on how to compute the restricted MLEs and the likelihood ratio statistics.
		# Comp.Amat[[1]] contain the constraint matrix for all the elementary hypotheses
		# Comp.Amat[[2]] contain the constraint matrix for all 2 way intersection hypotheses
		# 	ect... up to k-1.
		for(i in 1:choose(k-1,cross)){
            Comp.Amat[[cross]][[i]]<-list()
            for(j in 1:m^cross) Comp.Amat[[cross]][[i]][[j]]<-.Constraint(label=component.array[[cross]][j,,i],k=k)
        }

		# The list row.ind and col.ind tells how to perform the consonant adjustment.
		# Read the instruction in function .rNull.dist for definitions on ComponentLRT first.
		# Since each intersection hypothesis is located by one cell in the matrix of ComponentLRT[[1]][,,i],
		#	ComponentLRT[[2]][,,i], and ComponentLRT[[3]][,,i] for the ith replication, we give the index of those
		#	intersection hypotheses that needs to be tested in consonance adjustment.

		# For example, a three way intersection hypothesis H_121, will be located in ComponentLRT[[3]].
		#	According to active.array[[3]], it is on the 3rd row of ComponentLRT[[3]]. And ComponentLRT[[3]][,,i] only
		#	has one column. So the index for H_121 is ComponentLRT[[3]][3,1,i].
		# To reject H_121, we need to also reject at least two of H_123, H_131 and H_321. They are associated with three
		#	indices in ComponentLRT.
		# First, since they are all two-way intersections, they all located in ComponentLRT[[2]].
		#	row.ind[[2]][3,]=c(2,1,3) gives the three row index of these hypotheses,
		#	col.ind[[2]][1,]=c(1,2,3) gives the three col index of these hypotheses.
		#	They are ComponentLRT[[2]][2,1,i], ComponentLRT[[2]][1,2,i] and ComponentLRT[[2]][3,3,i].
		if(cross>1){
            row.ind[[cross-1]]<-matrix(NA,nrow=m^cross,ncol=cross)
            combn.mat<-combn(cross,cross-1)
            for(a in 1:m^cross)for(b in 1:cross)
                row.ind[[cross-1]][a,b]<-which(sapply(1:m^(cross-1),function(x)all(active.array[[cross-1]][x,1:(cross-1),drop=F]==active.array[[cross]][a,combn.mat[,b]])))
            combn.mat<-combn(k-1,cross-1)
            for(a in 1:nrow(col.ind[[cross-1]]))
                col.ind[[cross-1]][a,]<-which(sapply(1:choose(k-1,cross-1),function(x)all(combn.mat[,x]%in%combn(k-1,cross)[,a])))
        }
    }
    return(list('matrix'=npmtrx,'Comp.Amat'=Comp.Amat,'component.array'=component.array,'row.ind'=row.ind,'col.ind'=col.ind,'balanced'=balanced))
}

# LR compute the likelihood ratio statistics for each intersection hypothesis.
library(quadprog)
.LR<-function(Amat,k=4,m=2,Ybar,sigma,n=rep(50,4)){
    # Ybar is a m-by-k matrix, the last column in Ybar is the control.
	# sigma is a length m vector, includes stdev of each endpoint.
	# Amat is the constraint matrix for certain dose-endpoint combination from Comp.Amat
    sigma<-sum(n-1)*sigma^2
    ynullp<-solve.QP(Dmat=diag(n),dvec=diag(n)%*%Ybar[1,],Amat=Amat$hnullp)$solution
    ynulls<-solve.QP(Dmat=diag(n),dvec=diag(n)%*%Ybar[2,],Amat=Amat$hnulls)$solution
    LR<-( sigma[1]*sigma[2]
         /(sigma[1]+sum(n*(Ybar[1,]-ynullp)^2))/(sigma[2]+sum(n*(Ybar[2,]-ynulls)^2)) )^(-sum(n)/2)
    # To the power of -sum(n)/2 so that reject the null if LR > critical value.
    return(LR)
}

# .rNull.dist generate samples from the null distribution and compute their test statistics.
library(mvtnorm)
.rNull.dist<-function(n=rep(50,4),simu=10^5,rho=0){
    # n is the sample size for each dose. It is a vector of length 4, the last elements is the control.
    # The number of doses in this example, including control, is 4.
    # The number of endpoints is fixed at 2, for this function.
    k<-length(n)
    balanced<-(length(unique(n[1:(k-1)]))==1)
    NP<-.naturalpartition(k=k,m=2,balanced=balanced)
    # Generate null distribution
    sigma<-matrix(nrow=simu,ncol=2)
    Ybar<-array(dim=c(2,k,simu))
    ComponentLRT<-list()
    for(cross in 1:(k-1)) ComponentLRT[[cross]]<-array(dim=c(2^cross,choose(k-1,cross),simu))
    # ComponentLRT[[cross]] is a 2^cross * choose(k-1,cross) * simu array, where simu is the replication.
	# In the case of 4 treatment groups and 2 endpoints,
	#	ComponentLRT[[1]] is 2 by choose(3,1)=3 matrix, each cell is a one-way intersection hypothesis with
	#		index of the form x33, 3x3 or 33x. The x can be 1 or 2 for two endpoints, thus two rows.
	#	ComponentLRT[[2]] is 4 by choose(3,2)=3 matrix, each cell indicates a two-way intersection hypothesis
	#		with index of the form xx3, x3x or 3xx. The xx can be 11, 12, 21 and 22 from two endpoints, thus
	#		there are 4 rows.
	#	ComponentLRT[[3]] is 8 by choose(3,3)=1 matrix, each cell indicates a three-way intersection hypothesis
	#		with index of the form xxx. The xxx comes for two endpoints combinations.

	# Each intersection hypothesis fits into one cell of the matrix in ComponentLRT[[1]][,,i], ComponentLRT[[2]][,,i],
	#	and ComponentLRT[[3]][,,i] for the ith replication. There are in total 26 of them.

	# The following piece of code comes from Normal random variable generating function.
	# To same computation time, part of the repeating computation is done here only once.
    retval<-list()
    VC<-matrix(rho,nrow=2,ncol=2)+(1-rho)*diag(2)
    for(i in 1:k){
        altersigma<-VC/n[i]
        ev<-eigen(altersigma, symmetric = TRUE)
        retval[[i]] <- ev$vectors %*% diag(sqrt(ev$values), length(ev$values)) %*% t(ev$vectors)
    }

    for(i in 1:simu){
            sigma[i,]<-rchisq(2,df=sum(n-1))/sum(n-1)
            # sigma[i,] is the pooled estimate of the standard deviation, it is a vector
            #   of length 2, corresponding to each endpoint.

            Ybar[,,i]<-sapply(1:k,function(x)matrix(rnorm(2), nrow = 1) %*% retval[[x]])
            # 2 by 4 matrix, the last column is the control.

            for(cross in 1:(k-1))
                #ComponentLRT[[cross]][,,i]<-sapply(1:choose(k-1,cross),function(j)sapply(1:2^cross,function(x) .LR(Amat=NP$Comp.Amat[[cross]][[j]][[x]],k=k,m=2,Ybar=Ybar[,,i],sigma=sigma[i,],n=n)))
                for(j in 1:choose(k-1,cross))
                    ComponentLRT[[cross]][,j,i]<-sapply(1:2^cross,function(x) .LR(Amat=NP$Comp.Amat[[cross]][[j]][[x]],k=k,m=2,Ybar=Ybar[,,i],sigma=sigma[i,],n=n))
			# Compute all the likelihood ratio statistics. For some reason, it is faster to use a for loop.
    }
    return(list('ComponentLRT'=ComponentLRT,'NP'=NP,'n'=n,'simu'=simu))
}

#t<-proc.time()[1]
#set.seed(10)
#PS4.null<-.rNull.dist(n=rep(50,4),simu=10^3)
#proc.time()[1]-t

# .rAlternative.dist generate samples from alternative/true distribution and compute likelihood ratio statistics.
# It returns several statistics for different uses.
#	ComponentLRT is used by consonant likelihood ratio test
#	tstat is used by Dunnett gatekeeping procedure
#	DP.object is used by Decision path partition testing
#	NP, scenario, powersimu and delta is carried out to identify the problem.
.rAlternative.dist<-function(n=rep(50,4),powersimu=10^5,rho=0.3,delta=c(0,0),scenario=matrix(0,nrow=2,ncol=3)){
    # delta is the difference between treatment and control that we want to detect.
	k<-length(n)
    balanced<-(length(unique(n[1:(k-1)]))==1)
    NP<-.naturalpartition(k=k,m=2,balanced=balanced)

    sigma<-matrix(nrow=powersimu,ncol=2)
    Ybar<-array(dim=c(2,k,powersimu))
    ComponentLRT<-list()
	tstat<-array(dim=c(2,k-1,powersimu))
    # tstat is the t statistics used in Dunnett Gatekeeping procedure.
	for(cross in 1:(k-1)) ComponentLRT[[cross]]<-array(dim=c(2^cross,choose(k-1,cross),powersimu))
    if(length(delta)!=2)stop("delta should be of the same length as the number of endpoints!")
    trtmean<-cbind(scenario,delta)

    retval<-list()
    VC<-matrix(rho,nrow=2,ncol=2)+(1-rho)*diag(2)
    for(i in 1:k){
        altersigma<-VC/n[i]
        ev<-eigen(altersigma, symmetric = TRUE)
        retval[[i]] <- ev$vectors %*% diag(sqrt(ev$values), length(ev$values)) %*% t(ev$vectors)
    }

    object<-list()
    for(i in 1:powersimu){
            sigma[i,]<-rchisq(2,df=sum(n-1))/sum(n-1)
            # sigma[i,] is the pooled estimate of the standard deviation, it is a vector
            #   of length 2, corresponding to each endpoint.

            Ybar[,,i]<-sapply(1:k,function(x) sweep(matrix(rnorm(2), nrow = 1) %*% retval[[x]], 2, trtmean[,x], "+") )
            # 2 by 4 matrix, the last column is the control

            for(cross in 1:(k-1))
                for(j in 1:choose(k-1,cross))
                    ComponentLRT[[cross]][,j,i]<-sapply(1:2^cross,function(x) .LR(Amat=NP$Comp.Amat[[cross]][[j]][[x]],k=k,m=2,Ybar=Ybar[,,i],sigma=sigma[i,],n=n))

    }
    return(list('ComponentLRT'=ComponentLRT,'NP'=NP,'scenario'=scenario,'delta'=delta,'powersimu'=powersimu))
}

#t<-proc.time()[1]
#PS4.alter<-.rAlternative.dist(n=rep(50,4),powersimu=10^4,rho=0.3,delta=c(0,0),scenario=matrix(c(0,0.65,0.65,0.65,0,0.65),nrow=2,ncol=3,byrow=T))
#proc.time()[1]-t

# In Windows System
#if(!is.loaded("consonant.adj")) dyn.load('./consonant.adj.dll')
# In Linux System
dyn.load("src/clrt.so")
.CLRT.PS4.cv<-function(alpha=0.025,null){
    # The number of endpoints comes from null, which is fixed at 2.
	n<-null$n
    simu<-null$simu
    k<-length(n)
    balanced<-(length(unique(n[1:(k-1)]))==1)
    NP<-null$NP
    ComponentLRT.cv<-list()
    for(cross in 1:(k-1)) ComponentLRT.cv[[cross]]<-matrix(nrow=2^cross,ncol=choose(k-1,cross))

    if(balanced){
    ComponentLRT.cv[[1]][1,]<-ComponentLRT.cv[[1]][2,]<-quantile(null$ComponentLRT[[1]],probs=1-alpha)
    for(cross in 2:(k-1)){
        n.adj<-dim(NP$col.ind[[cross-1]])[2]
        # List of variables needed by .C function
		# NP$col.ind[[cross-1]] is a choose(k-1,cross) by cross matrix
        # NP$row.ind[[cross-1]] is a 2^cross by cross matrix
		#	they share the same number of columns cross, which is the number of hypotheses to test in
		#	the consonance adjustment. Denoted by n.adj (equal to cross).
        # null$ComponentLRT[[cross-1]] is a 2^(cross-1) * choose(k-1,cross-1) * simu array
        # null$ComponentLRT[[cross]] is a 2^cross * choose(k-1,cross) * simu array
        for(a in 1:2^cross){
            cv<-sapply(1:choose(k-1,cross), function(j)
                            sapply(1:n.adj,function(x)ComponentLRT.cv[[cross-1]][NP$row.ind[[cross-1]][a,x],NP$col.ind[[cross-1]][j,x]]))
            # cv is a n.adj (cross) by choose(k-1,cross) matrix

			# The following .C code is the consonance adjustment, it will replace the likelihood ratio statistics of
			#	those intersection hypotheses do not satisfy consonance with 0.
            null$ComponentLRT[[cross]][a,,]<-.C("component_adj",
              as.double(null$ComponentLRT[[cross-1]]),
              as.integer(2^(cross-1)),
              as.integer(choose(k-1,cross-1)),
              ComponentLRT_post=as.double(null$ComponentLRT[[cross]][a,,]),
              as.integer(choose(k-1,cross)),
              as.integer(NP$row.ind[[cross-1]][a,]),
              as.integer(NP$col.ind[[cross-1]]),
              as.double(cv),
              as.integer(n.adj),
              as.integer(simu),
              PACKAGE="clrt"
              )$ComponentLRT_post
        }
		# For balanced case, the critical constants are the same among intersection hypotheses with the same number
		#	of treatments involved regardless of endpoints involved.
        for(unq in k:1){
            L<-which(sapply(1:2^cross,function(x)length(unique(NP$component.array[[cross]][x,,1]))==unq))
            if(length(L)==0)next
            ComponentLRT.cv[[cross]][L,]<-quantile(null$ComponentLRT[[cross]][L,,],probs=1-alpha)
        }
    }
    }

    else{
    for(j in 1:(k-1))ComponentLRT.cv[[1]][,j]<-quantile(null$ComponentLRT[[1]][,j,],probs=1-alpha)
    for(cross in 2:(k-1)){
        n.adj<-dim(NP$col.ind[[cross-1]])[2]
        for(a in 1:2^cross){
            cv<-sapply(1:choose(k-1,cross), function(j)
                sapply(1:n.adj,function(x)ComponentLRT.cv[[cross-1]][NP$row.ind[[cross-1]][a,x],NP$col.ind[[cross-1]][j,x]]))
            null$ComponentLRT[[cross]][a,,]<-.C("component_adj",
                  as.double(null$ComponentLRT[[cross-1]]),
                  as.integer(2^(cross-1)),
                  as.integer(choose(k-1,cross-1)),
                  ComponentLRT_post=as.double(null$ComponentLRT[[cross]][a,,]),
                  as.integer(choose(k-1,cross)),
                  as.integer(NP$row.ind[[cross-1]][a,]),
                  as.integer(NP$col.ind[[cross-1]]),
                  as.double(cv),
                  as.integer(n.adj),
                  as.integer(simu),
                  PACKAGE="clrt"
                  )$ComponentLRT_post
        }
        for(unq in k:1){
            L<-which(sapply(1:2^cross,function(x)length(unique(NP$component.array[[cross]][x,,1]))==unq))
            if(length(L)==0)next
            ComponentLRT.cv[[cross]][L,]<-sapply(1:choose(k-1,cross),function(j)quantile(null$ComponentLRT[[cross]][L,j,],probs=1-alpha))
        }
    }
    }

    return(ComponentLRT.cv)
}

#a<-proc.time()[1]
#cv<-.CLRT.PS4.cv(alpha=0.025,PS4.null)
#(proc.time()[1]-a)
#dyn.unload('./consonant.adj.dll')

.CLRT.PS4.test<-function(alpha=0.05,cv=NULL,n=rep(50,4),ybar,sigma,alter=NULL,powersimu=NULL,null=NULL,rho=0,delta=c(0,0),scenario=NULL){
    # The number of endpoints in this function is fixed at 2.
	# This function can take existing observations generated by .rAlternative.dist before, specify "alter".
	#	The delta and scenario will be obtained from the list "alter".
	# This function can also generate samples using .rAlternative.dist, give the desired sample size by "powersimu".
	#	And specify the correlation between endpoints with "rho" and the scenario want to test.
	# Otherwise, this function is used to test a specific observation, give their mean matrix and variance vector
	#	by "ybar" and "sigma". ybar is a m-by-k matrix treatment means, the last column is the control. sigma is
	#	a vector of length m, the stdev of each endpoint.
	k=length(n)
    m=2
    balanced<-(length(unique(n[1:(k-1)]))==1)

	if(is.null(cv))cv=.CLRT.PS4.cv(alpha=alpha,null=null)

    if(is.null(powersimu)){
        NP<-.naturalpartition(k=k,m=2,balanced=balanced)
        if(is.null(alter)){
            powersimu=1
            alter<-list('ComponentLRT'=list())
            for(cross in 1:(k-1)) alter$ComponentLRT[[cross]]<-array(dim=c(2^cross,choose(k-1,cross),1))
            ybar[,k]<-ybar[,k]+delta
            for(cross in 1:(k-1))
                for(j in 1:choose(k-1,cross))
                    alter$ComponentLRT[[cross]][,j,1]<-sapply(1:2^cross,function(x) .LR(Amat=NP$Comp.Amat[[cross]][[j]][[x]],k=k,m=2,Ybar=ybar,sigma=sigma,n=n))
        }
        else{
            powersimu<-alter$powersimu
            scenario<-alter$scenario
            delta<-alter$delta
        }
    }else{
        alter<-.rAlternative.dist(n=n,powersimu=powersimu,rho=rho,delta=delta,scenario=scenario)
        NP<-alter$NP
    }

    for(cross in 2:(k-1)){
        n.adj<-dim(NP$col.ind[[cross-1]])[2]
        for(a in 1:2^cross){
            cc<-sapply(1:choose(k-1,cross), function(j)
                sapply(1:n.adj,function(x)cv[[cross-1]][NP$row.ind[[cross-1]][a,x],NP$col.ind[[cross-1]][j,x]]))
            # The following .C code is the consonance adjustment, it will replace the likelihood ratio statistics of
			#	those intersection hypotheses do not satisfy consonance with 0.
            alter$ComponentLRT[[cross]][a,,]<-.C("component_adj",
                  as.double(alter$ComponentLRT[[cross-1]]),
                  as.integer(2^(cross-1)),
                  as.integer(choose(k-1,cross-1)),
                  ComponentLRT_post=as.double(alter$ComponentLRT[[cross]][a,,]),
                  as.integer(choose(k-1,cross)),
                  as.integer(NP$row.ind[[cross-1]][a,]),
                  as.integer(NP$col.ind[[cross-1]]),
                  as.double(cc),
                  as.integer(n.adj),
                  as.integer(powersimu),
                  PACKAGE="clrt"
                  )$ComponentLRT_post
        }
    }
	# After the consonance adjustment, compare the likelihood ratio statistics with critical constants.
    if(is.null(null)){
		rejection<-matrix(nrow=(m+1)^(k-1)-1,ncol=powersimu)
		for(cross in 1:(k-1)){
			for(i in 1:choose(k-1,cross)){
				for(j in 1:m^cross){
					for(h in 1:((m+1)^(k-1)-1)){
						if(all(NP$matrix[h,]==NP$component.array[[cross]][j,,i])){
							rejection[h,]<-sapply(1:powersimu,function(x)alter$ComponentLRT[[cross]][j,i,x]>cv[[cross]][j,i])
							break
						}
					}
				}
			}
		}
	}
	# If p-value is desired, then compare likelihood ratio statistics with the null distribution and calculate p-value.
	else{
		pvalue<-rejection<-matrix(nrow=(m+1)^(k-1)-1,ncol=powersimu)
		for(cross in 1:(k-1)){
			for(i in 1:choose(k-1,cross)){
				for(j in 1:m^cross){
					for(h in 1:((m+1)^(k-1)-1)){
						if(all(NP$matrix[h,]==NP$component.array[[cross]][j,,i])){
							pvalue[h,]<-sapply(1:powersimu,function(x)mean(null$ComponentLRT[[cross]][j,i,]>alter$ComponentLRT[[cross]][j,i,x]))
							rejection[h,]<-pvalue[h,]<alpha
							break
						}
					}
				}
			}
		}
	}

    # The rejection rule follows Section 4.1
	Inference<-matrix(0,nrow=m,ncol=k-1)
    FWER<-numeric(powersimu)
    for(edp in 1:m){
        for(dose in 1:(k-1)){
            if(is.null(scenario)){
                Inference[edp,dose]<-all(rejection[which(NP$matrix[,dose]<=edp),1]==1)
                FWER<-NA
            }
            else if(scenario[edp,dose]==0) for(i in 1:powersimu){
                if(FWER[i]==1) Inference[edp,dose]<-Inference[edp,dose]+all(rejection[which(NP$matrix[,dose]<=edp),i]==1)
                else Inference[edp,dose]<-Inference[edp,dose]+(FWER[i]<-all(rejection[which(NP$matrix[,dose]<=edp),i]==1))
            }
            else for(i in 1:powersimu){
                Inference[edp,dose]<-Inference[edp,dose]+all(rejection[which(NP$matrix[,dose]<=edp),i]==1)
            }
        }
    }

	if(!is.null(null))
		return(list('alpha'=alpha,'Power'=Inference/powersimu,'FWER'=sum(FWER)/powersimu,'Partition'=apply(rejection,1,mean),'cv'=cv,'Pvalue'=pvalue,'Hypotheses'=NP$matrix[,1:3],'ComponentLRT'=alter$ComponentLRT ))
	else
		return(list('alpha'=alpha,'Power'=Inference/powersimu,'FWER'=sum(FWER)/powersimu,'Partition'=apply(rejection,1,mean),'cv'=cv,'Pvalue'=rejection,'Hypotheses'=NP$matrix[,1:3],'ComponentLRT'=alter$ComponentLRT ))
}

#a<-proc.time()[1]
#.CLRT.PS4.test(cv=cv,n=rep(50,4),powersimu=10^3,rho=0.3,delta=c(0,0),scenario=matrix(0.65,nrow=2,ncol=3))
#(proc.time()[1]-a)
#.CLRT.PS4.test(cv=cv,n=rep(50,4),ybar=matrix(8:1,nrow=2,ncol=4),sigma=c(2,4),delta=c(2,1))
#.CLRT.PS4.test(cv=cv,n=rep(50,4),alter=PS4.alter)

#source('./main.r') # Appended main.r source code above
if(!is.loaded("consonant.adj"))
# In Windows System
# dyn.load('./consonant.adj.dll')
# In Linux System
dyn.load("src/clrt.so")

clrt<-function(alpha=NULL,cv=NULL,n=NULL,grpmean=NULL,grpstdev=NULL,distr.null=NULL,distr.null.size=NULL,distr.alter=NULL,distr.alter.size=NULL,rho=0,delta=c(0,0),scenario=NULL,savenull=FALSE,savealter=FALSE,showpvalues=FALSE,showLRT=FALSE){
	if(is.null(alpha)){
		if(savenull){
			if(is.null(n))stop("Please specify sample size in each treatment groups and the control group.")
			if(is.null(distr.null.size))stop("Please specify how many samples are required for the null distribution.")
			distr.null=.rNull.dist(n=n,simu=distr.null.size,rho=0)
		}
		if(savealter){
			if(is.null(n))stop("Please specify sample size in each treatment groups and the control group.")
			if(is.null(distr.alter.size))stop("Please specify how many samples are required for the alternative distribution.")
			if(dim(scenario)[1]!=2)stop("This program can only handle cases with two endpoints.")
			if(dim(scenario)[2]!=length(n)-1)stop("Please specify the effect size for each treatment arm in each endpoint.")
			distr.alter=.rAlternative.dist(n=n,powersimu=distr.alter.size,rho=rho,delta=delta,scenario=scenario)
		}
		if(savenull&savealter) return(list('distr.null'=distr.null,'distr.alter'=distr.alter))
		else if(savenull) return(list('distr.null'=distr.null))
		else if(savealter) return(list('distr.alter'=distr.alter))
		else stop("Please specify significance level alpha if you want to perform test or calculate critical constants.")
	}
	else if(!is.null(grpmean) | !is.null(distr.alter) | !is.null(distr.alter.size)){
		if(is.null(cv)&is.null(distr.null)){
			if(is.null(n))stop("Please specify sample size in each treatment groups and the control group.")
			if(is.null(distr.null.size))stop("Please specify how many samples are required for the null distribution.")
			distr.null=.rNull.dist(n=n,simu=distr.null.size,rho=0)
		}
		if(!is.null(distr.null))showpvalue=TRUE
		else if(showpvalues){
			if(is.null(n))stop("Please specify sample size in each treatment groups and the control group.")
			if(is.null(distr.null.size))stop("Please specify how many samples are required for the null distribution.")
			distr.null=.rNull.dist(n=n,simu=distr.null.size,rho=0)
			showpvalue=TRUE
		}
		test.result<-.CLRT.PS4.test(alpha=alpha,cv=cv,n=n,ybar=grpmean,sigma=grpstdev,alter=distr.alter,powersimu=distr.alter.size,null=distr.null,rho=rho,delta=delta,scenario=scenario)
		if(!savenull)distr.null=NULL
		if(!savealter)distr.alter=NULL
		if(!showLRT)test.result$ComponentLRT=NULL
		if(showpvalue) return(list('alpha'=alpha,'Power.Decision'=test.result$Power,'FWER'=test.result$FWER,'Partition.power'=test.result$Partition,'cv'=test.result$cv,'Partition.pvalue'=test.result$Pvalue,'Hypotheses'=test.result$Hypotheses,'ComponentLRT'=test.result$ComponentLRT,'distr.null'=distr.null,'distr.alter'=distr.alter))
		else return(list('alpha'=alpha,'Power.Decision'=test.result$Power,'FWER'=test.result$FWER,'Partition.power'=test.result$Partition,'cv'=test.result$cv,'Partition.rejection'=test.result$Pvalue,'Hypotheses'=test.result$Hypotheses,'ComponentLRT'=test.result$ComponentLRT,'distr.null'=distr.null,'distr.alter'=distr.alter))
	}
	else{
		if(is.null(distr.null)){
			if(is.null(n))stop("Please specify sample size in each treatment groups and the control group.")
			if(is.null(distr.null.size))stop("Please specify how many samples are required for the null distribution.")
			distr.null=.rNull.dist(n=n,simu=distr.null.size,rho=0)
			cv<-.CLRT.PS4.cv(alpha=alpha,null=distr.null)
		}
		else cv<-.CLRT.PS4.cv(alpha=alpha,null=distr.null)
		if(savenull)return(list('alpha'=alpha,'cv'=cv,'distr.null'=distr.null))
		else return(list('alpha'=alpha,'cv'=cv))
	}
}


#' Covert grid reference to latitude and longitude
#'
#' @export
#' @param gridref a vector of strings giving grid references to be changed
#' @param precision gives the precision of the grid references. Must be of
#'        the same length as gridref. precision is given in meters as a numeric
#'        i.e. 10km square = 10000, 1km square = 1000. If NULL then the function
#'        tries to work out the precision itself.
#' @param centre If \code{TRUE} the coordinates for the centre of the cell are given
#'        else if \code{FALSE} the coordinates for the bottom left corner are given.
#' @return A dataframe of results are returned
#' @keywords mapping latitude longitude grid-reference
#' @examples
#'
#' gr2gps_latlon('SU616896')

gr2gps_latlon = function(gridref, precision = NULL, centre = TRUE){
    # NOTE FOR UTM30 gridrefs then no need to use helmert transformation as lat long are already in correct projection

    # Setup up variable to hold final output
    out_latlon = data.frame(LATITUDE = rep(NA, length(gridref)), LONGITUDE = rep(NA, length(gridref)))

    # Determine eastings & northings
    org_en = gr_let2num(gridref, centre = centre, gr_prec = precision, return_projection = TRUE)

    # Determine lat lon (original projection)
    out_latlon = OSGridstoLatLong(org_en$EASTING, org_en$NORTHING, org_en$PROJECTION)

    # Determine indices of gridrefs that are not UTM30 (which will need transformed)
    i_trans = which(!org_en$PROJECTION %in% c("UTM30","WGS84", NA))

	# Determine whether any supplied grid references need reprojection (i.e. are any grid references from UK, Ireland)
	if(length(i_trans) > 0){
		# Determine Cartesian (Original projection)
		org_cart = LatLong_Cartesian(out_latlon$LATITUDE[i_trans], out_latlon$LONGITUDE[i_trans], org_en$PROJECTION[i_trans])

		# Apply Helmert transformation to convert original projections to WGS84 (Cartesian in WGS84)
		helm_tran = helmert_trans(x =org_cart$x, y = org_cart$y, z = org_cart$z, trans = paste(org_en$PROJECTION[i_trans],"toWGS84", sep=""))

		# Convert Cartesian coordinates to Latitude/Longitude (Lat Lon in WGS84)
		out_latlon[i_trans,] = Cartesian_LatLong(helm_tran$x, helm_tran$y, helm_tran$z, "UTM30")
    }
    # Return output
    return(out_latlon)
}

#### ADDINTIONAL FUNCTIONS ####

gr_det_country <-
    function(gridref){
        # Create variable to store output
        cty_out = rep(NA, length(gridref))

        "(^[[:upper:]]{1,2}[[:digit:]]{2}([[:upper:]]?|[[:upper:]]{2})$)|(^[[:upper:]]{1,2}[[:digit:]]{2,}$)"

        # Find British Gridrefs
        cty_out[grepl('(^[[:upper:]]{2}[[:digit:]]{2}([[:upper:]]?|[[:upper:]]{2})$)|(^[[:upper:]]{2}[[:digit:]]{2,}$)',gridref) & !grepl('^(WA)|(WV)',gridref)] = "OSGB"

        # Find Irish Gridrefs
        cty_out[grepl('(^[[:upper:]]{1}[[:digit:]]{2}([[:upper:]]?|[[:upper:]]{2})$)|(^[[:upper:]]{1}[[:digit:]]{2,}$)',gridref)] = "OSNI"

        # Find Channel Islands Gridrefs
        cty_out[grepl('(^(WA)|(WV)[[:digit:]]{2}([[:upper:]]?|[[:upper:]]{2})$)|(^(WA)|(WV)[[:digit:]]{2,}$)',gridref)] = "UTM30"

        # Return output object
        return(cty_out)
    }

gr_let2num <-
    function(gridref, centre = FALSE, gr_prec = NULL, return_projection = FALSE){
        # Function required to calculate easting in Letter Grid
        spmod = function(x, mod){
            ret_obj = x %% mod
            ret_obj[ret_obj == 0] = mod
            return(ret_obj)
        }

        # Validate grid reference format (removing any spaces or hyphens)
        gr_comps = gr_components(gridref)
        gridref = gsub("[ -]","",toupper(gridref))

        # Setup variable to hold output
        len_grvec = nrow(gr_comps)
        if(return_projection){
            ret_obj = data.frame( EASTING = rep(NA,len_grvec), NORTHING = rep(NA, len_grvec), PROJECTION = rep(NA, len_grvec), row.names = NULL ) # row.names set to null to stop duplicate row names error
        } else {
            ret_obj = data.frame( EASTING = rep(NA,len_grvec), NORTHING = rep(NA, len_grvec), row.names = NULL ) # row.names set to null to stop duplicate row names error
        }

        # First find all British Gridrefs
        cty_inds = which(grepl('(^[[:upper:]]{2}[[:digit:]]{2}([[:upper:]]?|[[:upper:]]{2})$)|(^[[:upper:]]{2}[[:digit:]]{2,}$)',gr_comps$VALID_GR) & !grepl('^(WA)|(WV)',gr_comps$VALID_GR))

        # If British Gridrefs found then calc easting and northings
        if(length(cty_inds) > 0){
            # Get position of gridref letters in grid
            l1 = match(substr(gr_comps$CHARS[cty_inds],1,1), LETTERS[-9])
            l2 = match(substr(gr_comps$CHARS[cty_inds],2,2), LETTERS[-9])
            # Determine initial easting northing digits based on 500km square
            e = (spmod(l1,5) - 1)*5
            n = floor(abs(l1 - 25)/5)*5
            # Modify initial easting/northing digits based on 100km square
            e = e + (spmod(l2,5) - 1)
            n = n + floor(abs(l2 - 25)/5)
            # Recalulate for false origin (SV) of British Grid
            e = e - 10
            n = n - 5
            # Extend so easting and northing digits so that nchars of east_num/north_num = 5 right padded with zeros
            east_num = gsub(" ","0", format(gr_comps$DIGITS_EAST[cty_inds], width = 5))
            north_num = gsub(" ","0", format(gr_comps$DIGITS_NORTH[cty_inds], width = 5))
            # append numeric part of references to grid index
            e = paste(e,east_num, sep="")
            n = paste(n,north_num, sep="")
            # Overwrite placeholder values in ret_obj
            ret_obj[cty_inds,c("EASTING", "NORTHING")] = c(as.numeric(e), as.numeric(n))
            if(return_projection){
                ret_obj[cty_inds,"PROJECTION"] = "OSGB"
            }
        }

        # Find all Irish Gridrefs
        cty_inds = which(grepl('(^[[:upper:]]{1}[[:digit:]]{2}([[:upper:]]?|[[:upper:]]{2})$)|(^[[:upper:]]{1}[[:digit:]]{2,}$)',gr_comps$VALID_GR))
        # If Irish Gridrefs found the calc easting and northings
        if(length(cty_inds) > 0){
            # Get position of gridref letters in grid
            l2 = match(substr(gr_comps$CHARS[cty_inds],1,1), LETTERS[-9])
            # Determine initial easting/northing digits based on 100km square
            e = spmod(l2,5) - 1
            n = floor(abs(l2 - 25)/5)
            # Extend so easting and northing digits so that nchars of east_num/north_num = 5 right padded with zeros
            east_num = gsub(" ","0", format(gr_comps$DIGITS_EAST[cty_inds], width = 5))
            north_num = gsub(" ","0", format(gr_comps$DIGITS_NORTH[cty_inds], width = 5))
            # append numeric part of references to grid index
            e = paste(e,east_num, sep="")
            n = paste(n,north_num, sep="")
            # Overwrite placeholder values in ret_obj
            ret_obj[cty_inds,c("EASTING", "NORTHING")] = c(as.numeric(e), as.numeric(n))
            if(return_projection){
                ret_obj[cty_inds,"PROJECTION"] = "OSNI"
            }
        }

        # Find all Channel Islands Gridrefs
        cty_inds = which(grepl('(^(WA)|(WV)[[:digit:]]{2}([[:upper:]]?|[[:upper:]]{2})$)|(^(WA)|(WV)[[:digit:]]{2,}$)',gr_comps$VALID_GR))
        # If CI gridrefs found then calc easting and northings
        if(length(cty_inds) > 0){
            # Determine initial easting/northing based on letters
            e = rep(5, length(cty_inds))
            n = ifelse(grepl('^(WA)[[:digit:]]{2,}$',gr_comps$VALID_GR[cty_inds]),55,54)
            # Extend so easting and northing digits so that nchars of east_num/north_num = 5 right padded with zeros
            east_num = gsub(" ","0", format(gr_comps$DIGITS_EAST[cty_inds], width = 5))
            north_num = gsub(" ","0", format(gr_comps$DIGITS_NORTH[cty_inds], width = 5))
            # append numeric part of references to grid index
            e = paste(e,east_num, sep="")
            n = paste(n,north_num, sep="")
            # Overwrite placeholder values in ret_obj
            ret_obj[cty_inds,c("EASTING", "NORTHING")] = c(as.numeric(e), as.numeric(n))
            if(return_projection){
                ret_obj[cty_inds,"PROJECTION"] = "UTM30"
            }
        }

        # If any grid refs contained a tetrad or quadrant code then need to modify the easting and northing
        # Find all grid refs with a tetrad code
        cty_inds = which(!is.na(gr_comps$TETRAD))
        # For these grid refs modify the eastings and northings accordingly
        if(length(cty_inds) > 0){
            # Get list of tetrad codes (all letters but O)
            tet_codes = LETTERS[-15]
            # Determine the position in the tetrad codes vector for each code
            code_match = match(gr_comps$TETRAD[cty_inds], tet_codes)
            # Modify easting
            ret_obj[cty_inds, "EASTING"] = ret_obj[cty_inds,"EASTING"] + ((code_match-1) %/% 5)*2000
            # Modify northing
            ret_obj[cty_inds, "NORTHING"] = ret_obj[cty_inds,"NORTHING"] + ((code_match-1) %% 5)*2000
        }

        # Find all grid refs with a quadrant code
        cty_inds = which(!is.na(gr_comps$QUADRANT))
        # For these grid refs modify the eastings and northings accordingly
        if(length(cty_inds) > 0){
            # Get list of tetrad codes (all letters but O)
            quad_codes = c("SW","NW","SE","NE")
            # Determine the position in the tetrad codes vector for each code
            code_match = match(gr_comps$QUADRANT[cty_inds], quad_codes)
            # Modify easting
            ret_obj[cty_inds, "EASTING"] = ret_obj[cty_inds,"EASTING"] + ((code_match-1) %/% 2)*5000
            # Modify northing
            ret_obj[cty_inds, "NORTHING"] = ret_obj[cty_inds,"NORTHING"] + ((code_match-1) %% 2)*5000
        }

        # If centre is true the determine precision and give easting and northing for centre of gridref
        if(centre){
            # Determine precision (if gr_prec not supplied)
            if(is.null(gr_prec)){
                gr_prec = gr_comps$PRECISION
            }
            # Add half of precision to easting and northing
            ret_obj[,c("EASTING", "NORTHING")] = ret_obj[,c("EASTING", "NORTHING")] + (gr_prec/2)
        }
        # Return easting and Northings
        return(ret_obj)
    }

OSGridstoLatLong <-
    function(Easting, Northing, Datum = "OSGB", datum_params = NULL, full_output = FALSE) {
        # If datum_params is null then defaults data.frame included with package will be used
        if(is.null(datum_params)){

            # Set datum_params to datum_vars
            datum_params = datum_vars
        }

        # Determine length of Easting & check same as Northing
        east_len = length(Easting)
        if(length(Northing) != east_len){
            stop("ERROR: 'Easting' & 'Northing' are of different lengths")
        }

        # Get list of Datums to be converted from Datum
        # If length of Datum input not 1 or same length as Easting/Northing then stop
        if(!length(Datum) %in% c(1,east_len)){
            stop("ERROR: Length of 'Datum' does not match length of Easting/Northing values")
        }
        datum_list = na.omit(unique(Datum))
        # Check all Datum are in datum_params data frame
        miss_datum = which(!datum_list %in% datum_params$Datum)
        if(length(miss_datum) > 0){
            stop(paste("ERROR: Datum present in data for which parameters have not been given (",paste(sQuote(datum_list[miss_datum]), collapse=","), ")", sep=""))
        }

        # Setup object to hold output data
        if(full_output){
            ret_obj = data.frame(EASTING = Easting, NORTHING = Northing, DATUM = Datum, LATITUDE = rep(NA, east_len), LONGITUDE =rep(NA, east_len), stringsAsFactors = FALSE)
        } else {
            ret_obj = data.frame(LATITUDE = rep(NA, east_len), LONGITUDE =rep(NA, east_len), stringsAsFactors = FALSE)
        }

        # Loop through datum and extract params and then calculate lat long
        for(i_datum in 1:length(datum_list)){

            # Extract indices of easting/northing values corresponding to current datum
            if(length(Datum) == 1){
                dat_inds = 1:east_len
            } else {
                dat_inds = which(Datum == datum_list[i_datum])
            }

            # Extract datum params from datum_params (at same time covert lat0 and lon0 from degrees to radians
            par_ind = which(datum_params$Datum == datum_list[i_datum])
            # Check only one row of datum parameters data frame matches current datum
            if(length(par_ind) > 1){
                stop(paste("ERROR: More than one match for current Datum (",sQuote(datum_list[i_datum]),") found in datum_params data frame",sep=""))
            }
            a = datum_params$a[par_ind]
            b = datum_params$b[par_ind]
            F0 = datum_params$F0[par_ind]
            lat0 = datum_params$lat0[par_ind] * (pi/180) # Converting to radians
            lon0 = datum_params$lon0[par_ind] * (pi/180) # Converting to radians
            N0 = datum_params$N0[par_ind]
            E0 = datum_params$E0[par_ind]

            # Calculate other derived variables for projection/datum
            e2 = 1 - (b^2)/(a^2)		# eccentricity squared
            n = (a-b)/(a+b)
            n2 = n^2   					# Calculate n squared (used several times so store as variable)
            n3 = n^3					# Calculate n cubed (used several times so store as variable)

            # Iterate to estimate value of lat and M
            # Intial values
            # Lat
            lat = ( (Northing[dat_inds] - N0) / (a * F0) ) + lat0
            # Meridional Arc
            Ma = ( 1 + n + ((5/4)*n2) + ((5/4)*n3) ) * (lat-lat0)
            Mb = ( (3*n) + (3*n2) + ((21/8)*n3) ) * sin(lat-lat0) * cos(lat+lat0)
            Mc = ( ((15/8)*n2) + ((15/8)*n3) ) * sin(2*(lat-lat0)) * cos(2*(lat+lat0))
            Md = ( (35/24)*n3) * sin(3*(lat-lat0)) * cos(3*(lat+lat0))
            M = (b * F0) * (Ma - Mb + Mc - Md)			# Calculate Developed Meridional arc (M)
            # Setup index for lats that need further iteration
            iter_inds = which(abs( Northing[dat_inds] - N0 - M) >= 0.01)
            while(length(iter_inds) > 0){
                # Lat
                lat[iter_inds] = ( (Northing[dat_inds][iter_inds] - N0 - M[iter_inds]) / (a * F0) ) + lat[iter_inds]
                # Meridional Arc
                Ma[iter_inds] = ( 1 + n + ((5/4)*n2) + ((5/4)*n3) ) * (lat[iter_inds]-lat0)
                Mb[iter_inds] = ( (3*n) + (3*n2) + ((21/8)*n3) ) * sin(lat[iter_inds]-lat0) * cos(lat[iter_inds]+lat0)
                Mc[iter_inds] = ( ((15/8)*n2) + ((15/8)*n3) ) * sin(2*(lat[iter_inds]-lat0)) * cos(2*(lat[iter_inds]+lat0))
                Md[iter_inds] = ( (35/24)*n3) * sin(3*(lat[iter_inds]-lat0)) * cos(3*(lat[iter_inds]+lat0))
                M[iter_inds] = (b * F0) * (Ma[iter_inds] - Mb[iter_inds] + Mc[iter_inds] - Md[iter_inds])			# Calculate Developed Meridional arc (M)
                # Recalculate iteration index
                iter_inds = which(abs( Northing[dat_inds] - N0 - M) >= 0.01)
            }

            sinLat = sin(lat)
            tanLat = tan(lat)
            tan2Lat = tanLat^2
            tan4Lat = tanLat^4
            tan6Lat = tanLat^6
            secLat = 1 / cos(lat)

            elon = Easting[dat_inds] - E0

            nu = (a * F0)*(1-e2*sinLat^2)^-0.5              # transverse radius of curvature
            rho = (a * F0) * (1-e2)*(1-e2*sinLat^2)^-1.5   # meridional radius of curvature
            eta2 = (nu/rho)-1								# East-west component of the deviation of the vertical squared

            VII = tanLat / (2*rho*nu)
            VIII = ( tanLat / (24*rho*nu^3) ) * ( 5 + (3*tan2Lat) + eta2 - (9 * tan2Lat * eta2) )
            IX = (tanLat/(720*rho*nu^5)) * (61 + (90*tan2Lat) + (45*tan4Lat))
            X = secLat / nu
            XI = (secLat / (6 * nu^3)) * ( (nu/rho) + 2*tan2Lat)
            XII = (secLat / (120 * nu^5)) * (5 + (28*tan2Lat) + (24*tan4Lat))
            XIIA = (secLat / (5040 * nu^7)) * (61 + (662*tan2Lat) + (1320*tan4Lat) + (720*tan6Lat))

            Lat_rad = lat - (VII*elon^2) + (VIII*elon^4) - (IX*elon^6)
            Long_rad = lon0 + (X*elon) - (XI*elon^3) + (XII*elon^5) - (XIIA*elon^7)

            Latitude = Lat_rad * (180/pi)
            Longitude = Long_rad * (180/pi)

            ret_obj[dat_inds,c("LATITUDE","LONGITUDE")] = data.frame(Latitude, Longitude)
        }
        return (ret_obj)
    }

LatLong_Cartesian <-
    function(Latitude, Longitude, Datum = "OSGB", datum_params = NULL, H = NULL, full_output = FALSE){
        # If datum_params is null then defaults data.frame included with package will be used
        if(is.null(datum_params)){
            # Set datum_params to datum_vars
            datum_params = datum_vars
        }

        # Determine length of Latitude & check same as Longitude
        lat_len = length(Latitude)
        if(length(Longitude) != lat_len){
            stop("ERROR: 'Latitude' & 'Longitude' are of different lengths")
        }

        # Get list of Datums to be converted from Datum
        # If length of Datum input not 1 or same length as Latitude/Longitude then stop
        if(!length(Datum) %in% c(1,lat_len)){
            stop("ERROR: Length of 'Datum' does not match length of Latitude/Longitude values")
        }
        datum_list = na.omit(unique(Datum))
        # Check all Datum are in datum_params data frame
        miss_datum = which(!datum_list %in% datum_params$Datum)
        if(length(miss_datum) > 0){
            stop(paste("ERROR: Datum present in data for which parameters have not been given (",paste(sQuote(datum_list[miss_datum]), collapse=","), ")", sep=""))
        }

        # Setup object to hold output data (Cartesian Coordinates)
        if(full_output){
            ret_obj = data.frame(LATITUDE = Latitude, LONGITUDE = Longitude, DATUM = Datum, x = rep(NA, lat_len), y = rep(NA, lat_len), z = rep(NA, lat_len),  stringsAsFactors = FALSE)
        } else {
            ret_obj = data.frame(x = rep(NA, lat_len), y = rep(NA, lat_len), z = rep(NA, lat_len), stringsAsFactors = FALSE)
        }

        # Loop through datum and extract params and then calculate Cartesian Coordinates
        for(i_datum in 1:length(datum_list)){

            # Extract indices of lat/long values corresponding to current datum
            if(length(Datum) == 1){
                dat_inds = 1:lat_len
            } else {
                dat_inds = which(Datum == datum_list[i_datum])
            }

            # Extract datum params from datum_params (at same time covert lat0 and lon0 from degrees to radians
            par_ind = which(datum_params$Datum == datum_list[i_datum])
            # Check only one row of datum parameters data frame matches current datum
            if(length(par_ind) > 1){
                stop(paste("ERROR: More than one match for current Datum (",sQuote(datum_list[i_datum]),") found in datum_params data frame",sep=""))
            }
            a = datum_params$a[par_ind]
            b = datum_params$b[par_ind]

            # Height (H) assummed to be 0 unless specified
            if(is.null(H)){
                H = 0
            } else {
                H = H
            }

            # Convert latitude/longitude values into radians
            lat = Latitude[dat_inds] * (pi/180)
            lon = Longitude[dat_inds] * (pi/180)

            # Calculate eccentricity squared (e2)
            e2 = (a^2 - b^2)/a^2

            # Calculate Cartezian coordinates
            v = a / sqrt(1 - e2*sin(lat)^2)
            x = (v + H)*cos(lat)*cos(lon)
            y = (v + H)*cos(lat)*sin(lon)
            z = (((1-e2)*v) + H)*sin(lat)

            # Write values to ret_obj
            ret_obj[dat_inds,c("x","y","z")] = data.frame(x,y,z)

        }
        return(ret_obj)
    }

helmert_trans <-
    function(x, y, z, trans = "OSNItoOSGB", trans_params = NULL, full_output = FALSE){
        # If trans_params is null then check where helmert_trans_vars data.frame has been loaded from package
        if(is.null(trans_params)){

            # set trans_params = helmert_trans_vars
            trans_params = helmert_trans_vars
        }

        # Determine length of input vars x,y,z and check all 3 variables are same length
        len_x = length(x)
        if(length(y) != len_x | length(z) != len_x){
            stop("ERROR: input variables 'x', 'y' and 'z' are of different lengths")
        }

        # Get list of trans to be performed from trans
        # If length of trans input not 1 or same length as input vars then stop
        if(!length(trans) %in% c(1,len_x)){
            stop("ERROR: Length of 'trans' does not match length of input 'x','y' & 'z' values")
        }
        trans_list = unique(trans)
        # Check all Datum present in data are in datum_params data frame
        miss_trans = which(!trans_list %in% trans_params$TRANS)
        if(length(miss_trans) > 0){
            stop(paste("ERROR: Transformation requested for which parameters have not been given (",paste(sQuote(trans_list[miss_trans]), collapse=","), ")", sep=""))
        }

        # Setup object to hold output data (x,y,z)
        if(full_output){
            ret_obj = data.frame(org_x = x, org_y = y, org_z = z, TRANS = trans, x = rep(NA, len_x), y = rep(NA, len_x), z = rep(NA, len_x), stringsAsFactors = FALSE)
        } else {
            ret_obj = data.frame(x = rep(NA, len_x), y = rep(NA, len_x), z = rep(NA, len_x), stringsAsFactors = FALSE)
        }

        # Loop through transformations and extract params and then perform helmert transformation
        for(i_trans in 1:length(trans_list)){
            # Extract indices of x,y,z values corresponding to current transformation
            if(length(trans) == 1){
                dat_inds = 1:len_x
            } else {
                dat_inds = which(trans == trans_list[i_trans])
            }
            # Select relevant helmert transformation parameters
            tp = trans_params[trans_params$TRANS == trans_list[i_trans],]
            # Convert trans paras for rotation from degress to radians
            tp[,c("rx","ry","rz")] = (tp[,c("rx","ry","rz")]/3600) * (pi/180)
            # Normalise s to ppm
            tp[,"s"] = tp$s*1e-6
            # Apply transformation
            x_out = x[dat_inds] + (x[dat_inds]*tp$s) - (y[dat_inds]*tp$rz) + (z[dat_inds]*tp$ry) + tp$tx
            y_out = (x[dat_inds]*tp$rz) + y[dat_inds] + (y[dat_inds]*tp$s) - (z[dat_inds]*tp$rx) + tp$ty
            z_out = (-1*x[dat_inds]*tp$ry) + (y[dat_inds]*tp$rx) + z[dat_inds] + (z[dat_inds]*tp$s) + tp$tz

            # Insert transformed cartesian coordincates into output variable
            ret_obj[dat_inds,c("x","y","z")] = data.frame(x = x_out, y = y_out, z = z_out)
        }
        return(ret_obj)
    }

Cartesian_LatLong <-
    function(x,y,z, Datum = "OSGB", datum_params = NULL, full_output = FALSE ){
        # If datum_params is null then defaults data.frame included with package will be used
        if(is.null(datum_params)){
            # Determine if datum variables data.frame is already loaded from package

            # Set datum_params to datum_vars
            datum_params = datum_vars
        }

        # Determine length of input vars x,y,z and check all 3 variables are same length
        len_x = length(x)
        if(length(y) != len_x | length(z) != len_x){
            stop("ERROR: input variables 'x', 'y' and 'z' are of different lengths")
        }

        # Get list of Datums to be converted from Datum
        # If length of Datum input not 1 or same length as input vars then stop
        if(!length(Datum) %in% c(1,len_x)){
            stop("ERROR: Length of 'Datum' does not match length of input 'x','y' & 'z' values")
        }
        datum_list = na.omit(unique(Datum))
        # Check all Datum present in data are in datum_params data frame
        miss_datum = which(!datum_list %in% datum_params$Datum)
        if(length(miss_datum) > 0){
            stop(paste("ERROR: Datum present in data for which parameters have not been given (",paste(sQuote(datum_list[miss_datum]), collapse=","), ")", sep=""))
        }

        # Setup object to hold output data (Latitude/Longitude)
        if(full_output){
            ret_obj = data.frame(x = x, y = y, z = z, DATUM = Datum, LATITUDE = rep(NA, len_x), LONGITUDE = rep(NA, len_x), HEIGHT = rep(NA, len_x), stringsAsFactors = FALSE)
        } else {
            ret_obj = data.frame(LATITUDE = rep(NA, len_x), LONGITUDE = rep(NA, len_x), stringsAsFactors = FALSE)
        }

        # Setup precision variable (used to determine when to stop iteration)
        prec = 1

        # Loop through datum and extract params and then calculate Latitude and Longitude
        for(i_datum in 1:length(datum_list)){

            # Extract indices of lat/long values corresponding to current datum
            if(length(Datum) == 1){
                dat_inds = 1:len_x
            } else {
                dat_inds = which(Datum == datum_list[i_datum])
            }

            # Extract datum params from datum_params (at same time covert lat0 and lon0 from degrees to radians
            par_ind = which(datum_params$Datum == datum_list[i_datum])
            # Check only one row of datum parameters data frame matches current datum
            if(length(par_ind) > 1){
                stop(paste("ERROR: More than one match for current Datum (",sQuote(datum_list[i_datum]),") found in datum_params data frame",sep=""))
            }
            a = datum_params$a[par_ind]
            b = datum_params$b[par_ind]

            # Calculate eccentricity squared (e2)
            e2 = (a^2 - b^2)/a^2

            # Determine longitude
            lon = atan(y[dat_inds]/x[dat_inds])
            # Iteratively determine latitude
            p = sqrt(x[dat_inds]^2 + y[dat_inds]^2)
            lat = atan( z[dat_inds] / (p * (1 - e2)) )
            v = a / sqrt(1 - e2*sin(lat)^2)
            lat2 = atan( (z[dat_inds] + e2*v*sin(lat))/p )
            d_lat = lat - lat2
            iter_inds = which(d_lat > prec)
            while(length(iter_inds) > 0){
                # Change lat to lat2 and recalculate lat2
                lat[iter_inds] = lat2[iter_inds]
                v[iter_inds] = a[dat_inds][iter_inds] / sqrt(1 - e2*sin(lat[iter_inds])^2)
                lat2[iter_inds] = atan( (z[dat_inds][iter_inds] + e2*v[iter_inds]*sin(lat[iter_inds]))/p[iter_inds] )
                d_lat[iter_inds] = lat[iter_inds] - lat2[iter_inds]
                # Recalculate which rows need further iteration
                iter_inds = which(d_lat > prec)
            }
            # Calculate Height (although in majority of cases not really needed/wanted)
            H = (p / cos(lat)) - v
            # Convert Lat / long back to degrees
            lat = lat * (180/pi)
            lon = lon * (180/pi)

            # Setup return object
            if(full_output){
                ret_obj[dat_inds,c("LATITUDE","LONGITUDE", "HEIGHT")] = data.frame(lat, lon, H)
            } else {
                ret_obj[dat_inds,c("LATITUDE","LONGITUDE")] = data.frame(lat, lon)
            }

        }
        # Return output object
        return(ret_obj)
    }

fmt_gridref = function(gridref, gr_fmt = NULL){
    # Setup object to hold output grid refs
    gr_out = rep(NA, length(gridref))
    # convert gridref string to upper case
    gridref = toupper(gridref)
    # Replace any spaces, punctuation or control characters
    gridref = gsub("[[:space:][:cntrl:][:punct:]]", "", gridref)
    # Check that gridref conforms to grid reference pattern after removals
    # Get indices of gridrefs which are in a valid format
    gr_inds = which(grepl("^[[:upper:]]{1,2}[[:digit:]]{2,}([[:upper:]]?|[[:upper:]]{2})$", gridref))
    # Copy valid gridrefs to output object
    gr_out[gr_inds] = gridref[gr_inds]
    # Extract components where gr_fmt is not NULL (1 = Whole gridref minus tet/quad codes, 2 = Inital letter(s), 3 = Digits only, 4 = Tetrad/Quad only, 5 = Tetrad only, 6 = Quadrant only)
    if(!is.null(gr_fmt)){
        gr_out = gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", paste("\\",gr_fmt, sep=""), gr_out)
    }
    # Return formatted gridref
    return(gr_out)
}

det_gr_precision <- function(
    gridref
){
    # Convert letters to uppercase
    gridref = toupper(gridref)

    # Set up variable to store output
    prec_out = rep(NA,length(gridref))

    # Find valid gridrefs
    v_inds = which(grepl("(^[[:upper:]]{1,2}[[:digit:]]{2}([[:upper:]]?|[[:upper:]]{2})$)|(^[[:upper:]]{1,2}[[:digit:]]{2,}$)", gridref) & nchar(gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", "\\3", gridref)) %% 2 == 0)

    # Split into components
    gr_char = gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", "\\2", gridref[v_inds])
    gr_digits = gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", "\\3", gridref[v_inds])
    gr_tet = gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", "\\5", gridref[v_inds])
    gr_quad = gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", "\\6", gridref[v_inds])

    # Determine number of digits pairs
    n_pairs = nchar(gr_digits)/2

    # Determine precison based on gr
    gr_prec = 10^5 / 10^n_pairs

    # If gr_tet contains valid letter then ignore precision based on gridref length and assign 2000
    gr_prec[gr_tet %in% LETTERS[-15]] = 2000
    # If not valid tetrad code in gr_tet then set to NA (i.e. O is not a valid tetrad code)
    gr_prec[!gr_tet %in% LETTERS[-15] & gr_tet != ""] = NA

    # If gr_quad contains valid letter then ignore precision based on gridref length and assign 5000
    gr_prec[gr_quad %in% c("NW","NE","SW","SE")] = 5000
    # If not valid quadrant code in gr_tet then set to NA
    gr_prec[!gr_quad %in% c("NW","NE","SW","SE") & gr_quad != ""] = NA

    # Write gr_prec values to output variable
    prec_out[v_inds] = gr_prec

    # Return output variable
    return(prec_out)
}
gr_components <- function(gridref, output_col = NULL){

    # Convert letters to uppercase
    gridref = toupper(gridref)

    # Set up variable to store output
    gr_comps = data.frame(GRIDREF = gridref, VALID_GR = NA, PRECISION = NA, CHARS = NA, DIGITS = NA, DIGITS_EAST = NA, DIGITS_NORTH = NA, TETRAD = NA, QUADRANT = NA)

    # Check values for output_col if supplied
    if(!is.null(output_col)){
        if(!all(toupper(output_col) %in% names(gr_comps))){
            stop("Supplied output column name not recognised, valid values are:\n\t", paste(shQuote(names(gr_comps)), collapse = ", "))
        }
    }

    # Find valid gridrefs
    v_inds = which(grepl("(^[[:upper:]]{1,2}[[:digit:]]{2}([[:upper:]]?|[[:upper:]]{2})$)|(^[[:upper:]]{1,2}[[:digit:]]{2,}$)", gsub("[ -]","",gridref)) & nchar(gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", "\\3", gsub("[ -]","",gridref))) %% 2 == 0)

    if(length(v_inds) > 0){

        # Update valid gridrefs to data.frame
        gr_comps[v_inds,"VALID_GR"] = gsub("[ -]","", gridref[v_inds])

        # Split into components
        # Characters
        gr_comps[v_inds,"CHARS"] = gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", "\\2", gr_comps$VALID_GR[v_inds])
        # Digits
        gr_comps[v_inds,"DIGITS"] = gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", "\\3", gr_comps$VALID_GR[v_inds])
        # split digits into east and north
        len_digit = nchar(gr_comps$DIGITS[v_inds])
        gr_comps[v_inds, "DIGITS_EAST"] = substr(gr_comps$DIGITS[v_inds], 1, len_digit/2)
        gr_comps[v_inds, "DIGITS_NORTH"] = substr(gr_comps$DIGITS[v_inds], (len_digit/2)+1, len_digit)
        # Determine precision based on digits
        gr_comps[v_inds,"PRECISION"] = 10^5 / 10^(len_digit[v_inds]/2)
        # Tetrad
        gr_comps[v_inds,"TETRAD"] = gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", "\\5", gr_comps$VALID_GR[v_inds])
        # Find blank string values in gr_tet and replace with NA
        na_inds = which(!gr_comps$TETRAD %in% LETTERS[-15])
        if(length(na_inds) > 0){
            gr_comps[na_inds,"TETRAD"] = NA
        }
        # Quadrant
        gr_comps[v_inds,"QUADRANT"] = gsub("^(([[:upper:]]{1,2})([[:digit:]]{2,}))(([[:upper:]]?)|([[:upper:]]{2}))$", "\\6", gr_comps$VALID_GR[v_inds])
        # Find blank string values in gr_tet and replace with NA
        na_inds = which(!gr_comps$QUADRANT %in% c("NW","NE","SW","SE"))
        if(length(na_inds) > 0){
            gr_comps[na_inds,"QUADRANT"] = NA
        }

        # Modify precision if tetrad or quadrant is not null
        # Tetrad
        gr_comps[grepl("^[[:upper:]]{1,2}[[:digit:]]{2}[[:upper:]]{1,2}$", gr_comps$VALID_GR) & !is.na(gr_comps$TETRAD),"PRECISION"] = 2000
        # quadrant
        gr_comps[grepl("^[[:upper:]]{1,2}[[:digit:]]{2}[[:upper:]]{1,2}$", gr_comps$VALID_GR) & !is.na(gr_comps$QUADRANT),"PRECISION"] = 5000

        # Modify valid_gr to remove any gridrefs that had non-valid tetrad/quadrant codes
        na_inds = which(grepl("^[[:upper:]]{1,2}[[:digit:]]{2}[[:upper:]]{1,2}$", gr_comps$VALID_GR) & is.na(gr_comps$TETRAD) & is.na(gr_comps$QUADRANT))
        if(length(na_inds) > 0){
            gr_comps[na_inds,-1] = NA
        }
    }

    # If output_col is null then output all columns otherwise only output requested columns
    if(is.null(output_col)){
        out_obj = gr_comps
    } else {
        out_obj = gr_comps[,toupper(output_col)]
    }

    # Return output object
    return(out_obj)
}

det_tet_quad <- function(
    gridref,
    precision = NULL,
    prec_out = NULL
){
    # Setup output object
    out_obj = data.frame(TETRAD_GR = rep(NA, length(gridref)), QUADRANT_GR = NA)

    # Split gridref into components (will also check gridref sytax is correct)
    gr_comps = gr_components(gridref)

    gr_inds = which(nchar(gr_comps$DIGITS) >= 2 & !is.na(gr_comps$VALID_GR))
    sq10 = rep(NA, length(gridref))
    sq10[gr_inds] = paste(gr_comps$CHARS[gr_inds], substr(gr_comps$DIGITS_EAST[gr_inds],1,1), substr(gr_comps$DIGITS_NORTH[gr_inds],1,1), sep="")

    # All gridrefs that have valid tetrad/quadrant codes can be filled directly to out_obj
    # Tetrads
    gr_inds = which(!is.na(gr_comps$TETRAD))
    if(length(gr_inds) > 0){
        out_obj[gr_inds,"TETRAD_GR"] = paste(sq10[gr_inds], gr_comps$TETRAD[gr_inds], sep="")
    }
    #Quadrants
    gr_inds = which(!is.na(gr_comps$QUADRANT))
    if(length(gr_inds) > 0){
        out_obj[gr_inds,"QUADRANT_GR"] = paste(sq10[gr_inds], gr_comps$QUADRANT[gr_inds], sep="")
    }

    # If original gridref had tetrad code then where can be mapped directly to quadrant then do so
    # Find gridrefs with calculated precision of 2000 i.e. those that had a tetrad code in the grid ref
    gr_inds = which(gr_comps$PRECISION == 2000)
    if(length(gr_inds) > 0){
        # SW
        gr_inds = which(gr_comps$PRECISION == 2000 & gr_comps$TETRAD %in% c("A","B","F","G"))
        if(length(gr_inds) > 0){
            out_obj[gr_inds,"QUADRANT_GR"] = paste(sq10[gr_inds], "SW", sep="")
        }
        # NW
        gr_inds = which(gr_comps$PRECISION == 2000 & gr_comps$TETRAD %in% c("D","E","J","I"))
        if(length(gr_inds) > 0){
            out_obj[gr_inds,"QUADRANT_GR"] = paste(sq10[gr_inds], "NW", sep="")
        }
        # SE
        gr_inds = which(gr_comps$PRECISION == 2000 & gr_comps$TETRAD %in% c("Q","R","V","W"))
        if(length(gr_inds) > 0){
            out_obj[gr_inds,"QUADRANT_GR"] = paste(sq10[gr_inds], "SE", sep="")
        }
        # NE
        gr_inds = which(gr_comps$PRECISION == 2000 & gr_comps$TETRAD %in% c("T","U","Y","Z"))
        if(length(gr_inds) > 0){
            out_obj[gr_inds,"QUADRANT_GR"] = paste(sq10[gr_inds], "NE", sep="")
        }
    }

    # Find all valid gridrefs where precision is high enough
    gr_inds = which(gr_comps$PRECISION <= 1000)

    if(length(gr_inds) > 0){

        # Extract relevant digits for tetrad/quadrant estimation
        code_e = as.numeric(substr(gr_comps$DIGITS_EAST[gr_inds],2,2))
        code_n = as.numeric(substr(gr_comps$DIGITS_NORTH[gr_inds],2,2))

        # Determine tetrad code from easting and northing digits (can perhaps
        # Get list of tetrad codes (no O)
        tet_codes = LETTERS[-15]
        # Get tetrad code for each gridref of suitable precision
        tets = tet_codes[(code_e%/%2)*5 + (code_n%/%2)+1]
        out_obj[gr_inds,"TETRAD_GR"] = paste(sq10[gr_inds],tets, sep="")

        # Determine quadrant codes from easting and northing digits
        # Build vector of quadrant codes (in correct order)
        quad_codes = c("SW","NW","SE","NE")
        # Get tetrad code for each gridref of suitable precision
        quads = quad_codes[(code_e%/%5)*2 + (code_n%/%5)+1]
        out_obj[gr_inds,"QUADRANT_GR"] = paste(sq10[gr_inds],quads, sep="")

    }

    # If precision is supplied determine if it matches value estimated from gridref
    if(!is.null(precision)){
        # Check that precision is either a vector of length gridref or a single value
        if( !(length(precision) == 1 | length(precision) == length(gridref)) ){
            stop("precision does not match gridref length, supply either single value or vector of same length as gridref")
        }
        # Find non-matching precisions
        # Find non-matching non padded gridrefs (i.e. ones that shouldn't be wrong)
        gr_inds = which(gr_comps$PRECISION != precision & gr_comps$PRECISION != 1000 & (precision != 2000 | precision != 5000) )
        # Find all non-matched precision values
        if(length(gr_inds) > 0){
            stop("Precision supplied does not match determined precision for", length(gr_inds), " grid refs")
        }
        # If estimated precision = 1000 and supplied prec = 2000 or 5000 then assume tetrad/quadrant padded values (e.g. BRC type data)
        # Padded tetrads
        # Note if tetrad grid ref and tetrad code in (C,H,K,L,M,N,P,S,X) then quadrant cannot be uniquely determined
        # Find grid refs matching this criteria
        gr_inds = which(gr_comps$PRECISION != precision & gr_comps$PRECISION == 1000 & precision == 2000 & grepl("^[[:alpha:]]{1,2}[[:digit:]]{2}[CHKLMNPSX]$",out_obj$TETRAD_GR))
        # Set quadrant to NA
        if(length(gr_inds) > 0){
            out_obj[gr_inds,"QUADRANT_GR"] = NA
        }
        # Padded Quadrant
        # For all padded quadrant codes tetrad cannot be uniquely determined
        gr_inds = which(gr_comps$PRECISION != precision & gr_comps$PRECISION == 1000 & precision == 5000)
        # Set quadrant to NA
        if(length(gr_inds) > 0){
            out_obj[gr_inds,"TETRAD_GR"] = NA
        }

    }

    # Return output object based on prec_out value
    if(is.null(prec_out)){
        return(out_obj)
    } else if(prec_out == 2000){
        return(out_obj$TETRAD_GR)
    } else if(prec_out == 5000){
        return(out_obj$QUADRANT_GR)
    }
}


#' backsolve
#'
#' Solve a triangular system.
#'
#' @param r,l
#' A triangular coefficients matrix.
#' @param x
#' The right hand sides.
#' @param k
#' The number of equations (columns of r + rows of x) to use.
#' @param upper.tri
#' Should the upper triangle be used? (if not the lower is)
#' @param transpose
#' Should the transposed coefficients matrix be used? More efficient than
#' manually transposing with \code{t()}.
#'
#' @examples
#' library(float)
#'
#' s = flrunif(10, 3)
#' cp = crossprod(s)
#' y = fl(1:3)
#' backsolve(cp, y)
#'
#' @useDynLib float R_backsolve_spm
#' @name backsolve
#' @rdname backsolve
NULL

backsolve_float32 = function(r, x, k=ncol(r), upper.tri=TRUE, transpose=FALSE)
{
  if (is.integer(r))
  {
    if (is.float(x))
      r = fl(r)
  }

  if (is.integer(x))
  {
    if (is.float(r))
      x = fl(x)
  }

  if (is.double(r) || is.double(x))
  {
    if (is.float(r))
      r = dbl(r)
    if (is.float(x))
      x = dbl(x)

    backsolve(r, x, k, upper.tri, transpose)
  }
  else
  {
    if (!is.numeric(k) || k < 1 || k > nrow(r) || is.na(k))
      stop("invalid 'k' argument")

    ret = .Call(R_backsolve_spm, DATA(r), DATA(x), as.integer(upper.tri), as.integer(transpose), as.integer(k))
    float32(ret)
  }
}

forwardsolve_float32 = function(l, x, k=ncol(l), upper.tri=FALSE, transpose=FALSE)
{
  backsolve_float32(l, x, k, upper.tri, transpose)
}

#' @rdname backsolve
#' @export
setMethod("backsolve", signature(r="float32", x="float32"), backsolve_float32)

#' @rdname backsolve
#' @export
setMethod("backsolve", signature(r="float32", x="BaseLinAlg"), backsolve_float32)

#' @rdname backsolve
#' @export
setMethod("backsolve", signature(r="BaseLinAlg", x="float32"), backsolve_float32)

#' @rdname backsolve
#' @export
setMethod("forwardsolve", signature(l="float32", x="float32"), forwardsolve_float32)

#' @rdname backsolve
#' @export
setMethod("forwardsolve", signature(l="float32", x="BaseLinAlg"), forwardsolve_float32)

#' @rdname backsolve
#' @export
setMethod("forwardsolve", signature(l="BaseLinAlg", x="float32"), forwardsolve_float32)


#!/usr/local/bin/Rscript --vanilla

###############################################################################
# METAREP : High-Performance Comparative Metagenomics Framework (http://www.jcvi.org/metarep)
# Copyright(c)  J. Craig Venter Institute (http://www.jcvi.org)
#
# Licensed under The MIT License
# Redistributions of files must retain the above copyright notice.
#
# link http://www.jcvi.org/metarep METAREP Project
# package metarep
# version METAREP v 1.3.2
# author Johannes Goll
# lastmodified 2010-07-09
# license http://www.opensource.org/licenses/mit-license.php The MIT License
###############################################################################

args 		= commandArgs(TRUE)
infile 		= args[1];
outfile 	= args[2];
test 		= args[3];
propround 	= as.numeric(args[4]);
pvalround 	= as.numeric(args[5]);

data = read.table(file=infile,sep="\t",header=F,colClasses=c("character","numeric","numeric","numeric","numeric"));
n = nrow(data);

## specify result columns
colums  = c("id","count1","count2","prop1","prop2","odds_ratio","relative_risk","p_value","b_value","q_value");

## init result data frame
result = data.frame(data[,1],matrix(cbind(data[,2],data[,4],matrix(rep(NA,n*(length(colums)-3)),ncol=length(colums)-3)),ncol=length(colums)-1,nrow=n),stringsAsFactors=FALSE);

## set column names for data frame
colnames(result) = colums;

## iterate through features
for(i in 1:n) {

	## generate 2-2 matrix
	m = matrix(as.numeric(data[i,2:5]),ncol=2,nrow=2);

	## proportion one
	result[i,4] = round((m[1,1]/sum(m[,1])),propround);

	## proportion two
	result[i,5] = round((m[1,2]/sum(m[,2])),propround);

	## log odds_ratio
	result[i,6] = round(log((m[1,1]*m[2,2])/(m[2,1]*m[1,2])),3);

	## relative_risk
	result[i,7] = round((m[1,1]/sum(m[,1]))/((m[1,2]/sum(m[,2]))),4);

	## execute test
	result[i,8] = do.call(test,list(m))$p.value;
}

## correct for multiple testing and round adjusted p/q-values
result[,9]  = round(p.adjust(result$p_value, method = "bonferroni"),pvalround);
result[,10] = round(p.adjust(result$p_value, method = "fdr"),pvalround);

## round non adjusted p-value after using the non-rounded values for multi-testing correction
result[,8] = round(result$p_value,pvalround);
write.table(result, file=outfile, row.names=F,sep="\t", eol = "\n",append=F,quote=F)
q(status=0)


#' @export
#' @title cor.prob
#' @description couldn't accurately describe
#' @param \code{X}
#' @param \code{dfr} degrees of freedom
#' @return \code{}
#' @family abysmally documented
#' @author  unknown, \email{<unknown>@@dfo-mpo.gc.ca}
#' @export
cor.prob <- function(X, dfr = nrow(X) - 2) {
	 R <- cor(X)
	 above <- row(R) < col(R)
	 r2 <- R[above]^2
	 Fstat <- r2 * dfr / (1 - r2)
	 R[above] <- 1 - pf(Fstat, 1, dfr)
	 R
}


# Fast version of trigraf assuming that
#           ie(m) < je(m)
#           ie[is in ascending order
#           je is in ascending order within ie,
# that is, je(ie==i) is in ascending order for each fixed i.
# Code adapted from C code in trigraf.c, from the spatstat package
# by Adrian Baddeley.
#

subroutine trigraf(nv, ne, ie, je, nt, it, jt, kt)
#
# nv --- number of points being triangulated.
# ne --- number of triangle edges
# ie and je --- vectors of indices of ends of each edge
# nt --- number of triangles assumed to be at most ne
# it, jt, kt --- vectors of indices of vertices of triangles
#
integer firstedge, lastedge;
dimension ie(1), je(1), it(1), jt(1), kt(1)

# Initialise output.
nt = 1
lastedge = 0
while(lastedge < ne) {
# Consider next vertex i.
# The edges (i,j) with i < j appear contiguously in the edge list.
 firstedge = lastedge + 1
 i = ie(firstedge)
 do m = firstedge+1,ne {
  if ( ie(m) != i ) break
 }
  lastedge = m-1
# Consider each pair j, k of neighbours of i, where i < j < k.
# Scan entire edge list to determine whether j, k are joined by an edge.
# If so, save triangle (i,j,k)
  if(lastedge > firstedge) {
   do mj = firstedge,lastedge-1 {
    j = je(mj)
    do mk = firstedge+1,lastedge {
     k = je(mk)
# Run through edges to determine whether j, k are neighbours.
     do m = 1,ne {
      if(ie(m) >= j) break
     }
      while(m <= ne & ie(m) == j) {
       if(je(m) == k) {
# Add (i, j, k) to list of triangles.
        it(nt) = i;
        jt(nt) = j;
        kt(nt) = k;
        nt = nt+1
       }
      m = m+1
      }
     }
    }
   }
  }

return
end