R/flan.R

    ## --------------------------------------------------------------------------------------------------------------------------
    ############################################## Estimations and tests functions ##############################################
    ## --------------------------------------------------------------------------------------------------------------------------

  # Estimation function of the mean number of mutations. Compute also the probability of mutation if with.prob is TRUE and the fitness parameter if fitness is empty.
    # Arguments:
    # mc:  a (non-empty) numeric vector of mutants counts.
    # fn:  an optional (non-empty) numeric vector with same length as mc of final numbers of cells.
    # mfn:  mean final number of cells which. Ignored if fn is non-missing.
    # cvfn:  coefficient of variation of final number of cells. Ignored if fn is non-missing.
    # fitness:  fitness parameter: ratio of growth rates of normal and mutant cells. If fitness is NULL (default) then the fitness will be estimated. Otherwise, the given value will be used to estimate the mean mutation number mutations
    # death:  death probability. Must be smaller than 0.5.
    # method:  estimation method as a character string: one of ML (default), P0, or GF.
    # winsor:  winsorization parameter: positive integer. Only used when method is ML or when method is P0 and fitness is NULL.
    # model:  statistical lifetime model as a character string: one of LD (default) for Luria-Delbruck model with exponential lifetimes, or H for Haldane model with constant lifetimes.
    # Assumptions for the estimation
    #   - fitness (if given)
    #   - death probability
    #   - lifetimes distribution model : exponentialy distributed lifetime ("LD") or constant lifetime "H"
    #   - sample of mutants counts
    #   - sample of finals counts (or a mean and coefficient of variation for finals counts)
    # Three possible methods :
    #   - p0-method ("P0")   (winsorize the mc sample if rho is estimated with the parameter winsor)
    #   - Generating function method ("GF")
    #   - Maximum of Likelihood method ("ML")  (winsorize the mc sample with the parameter winsor)
    #
    # Returns :
    #   - Estimate of alpha (or pi) and rho if non given
    #   - Standard deviation of alpha, (or pi) and rho if non given

mutestim <- function(mc,fn=NULL,mfn=NULL,cvfn=NULL,                 # user's data
                  fitness=NULL,death=0.,                # user's parameters
                  method=c("ML","GF","P0"),winsor=512, # estimation method
                  model=c("LD","H"))                   # clone growth model
                  {

    if(missing(method)){method <- "ML"}
    if(missing(model)){model <- "LD"}
    method <- match.arg(method)
    model <- match.arg(model)

    if(is.null(mc)){
      stop("'mc' is empty...")
    }
    if(sum(floor(mc)==mc) != length(mc)) stop("'mc' must be a vector of integer.")
    if(!is.null(fn)){
      if(length(fn) != length(mc)){
	stop("'fn must have the same length as 'mc'.")
      }
      mfn <- mean(fn)
      cvfn <- sd(fn)/mfn
      if(sd(fn) == 0) fn <- NULL
    }
    if(!is.null(mfn)){
      if(mfn < 0 | length(mfn) > 1){
	stop("'mfn' must be a single positive number.")
      }
      if(is.null(cvfn)) cvfn <- 0
    }
    if(!is.null(cvfn)){
      if(cvfn < 0 | length(cvfn) > 1){
	stop("'cvfn' must be a single positive number.")
      }
      if(is.null(mfn)) mfn <- 1e9
    }
    if(!is.null(fitness)){
      if(fitness < 0 | length(fitness) > 1){
	stop("'fitness' must be empty or a single positive number.")
      }
    }
    if(death < 0 | death >= 0.5 | length(death) > 1){
      stop("'death must be a single positive and < 0.5 number.")
    }
    if(winsor < 0 | trunc(winsor) != winsor | length(winsor) > 1){
      stop("'winsor' must be a single positive integer.")
    }
    if(method=="P0" & sum(mc==0) == 0 & death == 0){
      stop(paste("P0 method can not be used if 'mc' does not contain any null counts and if 'death' is null.",sep=" "))
    }
    if(is.null(fitness)){   # If fitness is empty : compiute estimates of mean number of mutations (mutation probaility), fitness

      # Maximum of Likelihood estimators
      if(method == "ML"){
	
	if(!is.null(fn)) output <- MutationProbabilityFitnessMLOptimization(mc=mc,fn=fn,model=model,death=death,winsor=winsor)
	else output <- MutationFitnessMLOptimization(mc=mc,mfn=mfn,cvfn=cvfn,model=model,death=death,winsor=winsor)
	
# 	if(!output$succeeds) warning("Initialization of 'fitness' with 'GF'-method may have failed.")
# 	output$succeeds <- NULL
      }
      # P0 method
      if(method == "P0") output <- MutationFitnessP0Estimation(mc=mc,fn=fn,mfn=mfn,cvfn=cvfn,model=model,death=death,winsor=winsor)
	
      # GF method
      if(method == "GF") {
	output <- MutationFitnessGFEstimation(mc=mc,mfn=mfn,cvfn=cvfn,death=death,model=model)
	if(!output$succeeds) warning(paste("Impossible to estimate 'fitness' with 'GF'-method : 'fitness' is set to default value 1 and only",if(!is.null(mfn)){"mutation probability"}else{"mutation number"},"is estimated.",sep=" "))
	output$succeeds <- NULL
      }
    } else {    # Else : compute estimate(s) of mean number of mutations, or mutation probability

      # Maximum of Likelihood estimator of mutations or mutprob
      if(method == "ML"){
	if(!is.null(fn)) output <- MutationProbabilityMLOptimization(mc=mc,fn=fn,model=model,fitness=fitness,death=death,winsor=winsor)
	else output <- MutationMLOptimization(mc=mc,mfn=mfn,cvfn=cvfn,model=model,fitness=fitness,death=death,winsor=winsor)


      }
      # P0 method
      if(method == "P0") output <- MutationP0Estimation(mc,mfn=mfn,cvfn=cvfn,death=death)     # P0 estimator of mutations
      

      # GF method
      if(method == "GF")  output <- MutationGFEstimation(mc=mc,mfn=mfn,cvfn=cvfn,fitness=fitness,death=death,model=model)

    }

    output
}


    # One-sample or two-sample tests for mean number of mutations, fitness and mutation probability using mutestim estimates
    # The possible assumptions are the same as for the mutestim function.
    # Arguments :
    # Returns a "flantest" object, which contains:
    # Tstat:  the value of the computed statistic.
    # parameter:  the values of the parameter of the model: fitness(if not tested), death, mfn (if needed) and cvfn
    # p.value:  the p-value(s) of the test.
    # conf.int:  a confidence interval for the parameter(s) of interest appropriate to the specified alternative hypothesis.
    # estimates:  the estimate(s) of interest.
    # null.value:  the specified hypothesized value(s).
    # alternative:  a character string describing the alternative hypothesis.
    # model:  the statistical lifetime model.
    # method:  method used to compute the estimation(s) of the parameter(s) of interest.
    # data.name:  a character string giving the name of the complete data.


flan.test <- function(mc,fn=NULL,mfn=NULL,cvfn=NULL,                      # user's data
               fitness=NULL,death=0.,                         # user's parameters
               mutations0=1,mutprob0=NULL,fitness0=1,       # null hypotheses
               conf.level=0.95,                              # confidence level
               alternative=c("two.sided","less","greater"),  # alternative
               method=c("ML","GF","P0"),winsor=512,          # estimation method
               model=c("LD","H"))                            # clone growth model
               {

  with.prob <- FALSE               # Boolean: if TRUE (if fn, mfn, or cvfn are given), mutprob is tested instead of mutations

  if(is.null(mc)){
    stop("'mc' is empty...")
  } else {
    if(is.list(mc)){
      if(length(mc) == 1){
	nsamples <- 1
	dname <- list(deparse(substitute(mc)))
	if(is.null(mc[[1]])) stop("'mc[[1]]' is empty...")
	if(is.list(fn)){
	  if(length(fn) != nsamples) stop("'mc' and 'fn' must have the same length.")
	  if(!is.null(fn[[1]])){
	    dname <- c(dname,deparse(substitute(fn)))
	    with.prob <- TRUE
	    mfn <- mean(fn)
	    cvfn <- sd(fn)/mfn
	  }
	} else {
	  if(!is.null(fn)) stop("'fn' must have the same type as 'mc'.")
	  fn <- list(fn)
	}
      }
      if(length(mc) == 2){
	nsamples <- 2
	dname <- list(c(paste(deparse(substitute(mc)),"1",sep=""),paste(deparse(substitute(mc)),"2",sep="")))
	if(is.null(mc[[1]])) stop("'mc[[1]]' is empty...")
	if(is.null(mc[[2]])) stop("'mc[[2]]' is empty...")

	if(is.list(fn)){
	  if(length(fn) != nsamples) stop("'fn' must have the same length as 'mc'.")

	  if(!is.null(fn[[1]])) {
	    if(length(fn[[1]]) != length(mc[[1]])) stop("'fn[[1]]' must have the same length as 'mc[[1]]'.")

	    if(is.null(fn[[2]])){
	      warning("'fn[[2]]' is empty : 'fn[[1]]' is ignored.")
	      fn <- list(NULL,NULL)
	    } else {
	      if(length(fn[[2]]) != length(mc[[2]])) stop("'fn[[2]]' must have the same length as 'mc[[2]]'.")

	      dname <- c(dname,list(c(paste(deparse(substitute(fn)),"1",sep=""),paste(deparse(substitute(fn)),"2",sep=""))))
	      with.prob <- TRUE
	      mfn <- unlist(lapply(fn,mean))
	      cvfn <- unlist(lapply(fn,sd))/mfn
	    }
	  } else {
	    if(!is.null(fn[[2]])) {
	      warning("'fn[[1]]' is empty : 'fn[[2]]' is ignored.")
	      fn <- list(NULL,NULL)
	    }
	  }
	} else {
	  if(!is.null(fn)) stop("'fn' must have the same type as 'mc'.")
	  fn <- list(fn,fn)
	}
      }
    } else {
      nsamples <- 1
      dname <- list(deparse(substitute(mc)))
      if(!is.null(fn)){
	if(is.list(fn)) stop("'fn' must have the same type as 'mc'.")
	if(length(fn) != length(mc)) stop("'fn' must have the same length as 'mc'.")
	dname <- c(dname,deparse(substitute(fn)))
	with.prob <- TRUE
	mfn <- mean(fn)
	cvfn <- sd(fn)/mfn
      }
      mc <- list(mc)
      fn <- list(fn)
    }
  }

  if(!is.null(mfn)){
    if(sum(mfn < 0) != 0 | length(mfn) > 2) stop("if given, 'mfn' must be a vector with size <= 2 of positive numbers.")

    if(is.null(cvfn)) cvfn <- rep(0,length(mfn))
    with.prob <- TRUE
  }
  if(!is.null(cvfn)){
    if(sum(cvfn < 0) != 0 | length(cvfn) > 2){
      stop("if given, 'cvfn' must be a vector with size <= 2 of positive numbers.")
    }
    if(is.null(mfn)) mfn <- rep(1e9,length(cvfn))
    with.prob <- TRUE
  }
  if(!is.null(fitness)){
    if(sum(fitness < 0) != 0 | length(fitness) > 2){
      stop("if given, 'fitness' must be a vector with size <= 2 of positive numbers.")
    }
    fitness0 <- NULL
  }
  if(length(mutations0) > 1 | mutations0 < 0){
    stop("'mutations0' must be a single positive number.")
  }
  if(!is.null(fitness0)){
    if(length(fitness0) > 1 | fitness0 < 0){
      stop("'fitness0' must be a single positive number.")
    }
  }
  if(!is.null(mutprob0)){
    if(length(mutprob0) > 1 | mutprob0 < 0 | mutprob0 >= 1){
      stop("if given, 'mutprob0' must be a positive and <= 1 number.")
    }
    with.prob <- TRUE
    if(is.null(mfn)) mfn <- 1e9
    if(is.null(cvfn)) cvfn <- 0
  } else {
    if(with.prob){
      if(is.null(mfn)) mfn <- 1e9
      if(is.null(cvfn)) cvfn <- 0
      if(nsamples == 1) mutprob0 <- mutations0/mfn
    }
  }


  # Default values if two-samples test
  if(nsamples == 2){
    if(missing(mutations0)) mutations0 <- 0
    if(is.null(fitness)){
      if(missing(fitness0)) fitness0 <- 0
    }
    if(with.prob) {
      if(missing(mutprob0)) mutprob0 <- 0
    }
  }

  if((length(conf.level) > 1) | conf.level > 1 | conf.level < 0){
    stop("'conf.level' must be a single positive and <= 1 numbers.")
  }
  if(sum(death < 0 | death >= 0.5) != 0 | length(death) > 2){
    stop("'death' must be a vector with size <= 2 of positive and < 0.5 numbers.")
  }
  if(winsor < 0 | trunc(winsor) != winsor | length(winsor) > 1){
    stop("'winsor' must be a single positive integer.")
  }

  H0 <- c(if(with.prob) mutprob0 else mutations0,fitness0)     # Vector of null hypothesises

  np <- length(H0)                                             # Number of tested values

  if(missing(alternative)) {alternative <- rep("two.sided",np)}
  if(missing(method)) {method <- "ML"}
  if(missing(model)) {model <- "LD"}

  alternative <- match.arg(alternative,several.ok=TRUE)
  method <- match.arg(method)
  model <- match.arg(model)


  if(nsamples == 1){

    parameter <- NULL
    names <- character()

    if(np == 1){
      names(H0) <- if(with.prob) "mutation probability" else "mutation number"
      parameter <- c(fitness,death)
      names <- c("fitness","death")
      if(with.prob){
	parameter <- c(parameter,mfn,cvfn)
	names <- c(names,"mfn","cvfn")
      }
    }
    if(np == 2) {
      names(H0) <- c(if(with.prob) "mutation probability" else "mutation number", "fitness")
      parameter <- death
      names <- "death"
      if(with.prob){
	parameter <- c(parameter,mfn,cvfn)
	names <- c(names,"mfn","cvfn")
      }
    }
    names(parameter) <- names
  }
  if(nsamples == 2){
    if(np == 1 & length(fitness) == 1){fitness <- c(fitness,fitness)}
    if(length(death) == 1){death <- c(death,death)}
    if(length(mfn) == 1){mfn <- c(mfn,mfn)}
    if(length(cvfn) == 1){cvfn <- c(cvfn,cvfn)}

    parameter <- NULL
    names <- character()


    if(np == 1){
      names(H0) <- if(with.prob) "mutprob difference" else "mutations difference"
      parameter <- cbind(fitness,death)
      names <- c("fitness","death")
      if(with.prob) {
	parameter <- cbind(parameter,mfn,cvfn)
	names <- c(names,"mfn","cvfn")
      }
    }
    if(np == 2){
      names(H0) <- c(if(with.prob) "mutprob difference" else "mutations difference","fitness difference")
      parameter <- cbind(death)
      names <- "death"
      if(with.prob){
	parameter <- cbind(parameter,mfn,cvfn)
	names <- c(names,"mfn","cvfn")
      }
    }
    colnames(parameter) <- names
  }

  if(is.null(mfn)) mfn <- list(mfn)
  if(is.null(cvfn)) cvfn <- list(cvfn)
  if(is.null(fitness)) fitness <- list(fitness)

   # Estimates mean number of mutations alpha, given fitness parameter rho
  ests <- mapply(function(x,y,m,c,f,d){
    mutestim(mc=x,fn=y,mfn=m,cvfn=c,method=method,model=model,fitness=f,death=d,winsor=winsor)
  },mc,fn,mfn,cvfn,fitness,death)


  if(np == 1){   # If only mutations (or mutprob) is tested
    if(length(alternative) > 1) alternative <- alternative[1]

    Tstat <- unlist(ests[1,])    # Extract the estimate to compute statistic of the test
    sds <- unlist(ests[2,])      # Standard deviation of the estimate
    names(Tstat) <- NULL
    ests <- Tstat                # Keep the estimate

    if(nsamples == 2){    # If Two-sample test
      ests <- cbind(ests)
      Tstat <- -diff(Tstat)      # Statistic of the test is build with difference of estimates
      sds <- sqrt(sum(sds^2))    # Standard deviation of the difference between estimates
      colnames(ests) <- if(with.prob) "mutprob" else "mutations"
    }
    names(ests) <- if(with.prob) "mutprob" else "mutations"


  }
  if(np == 2){    # If fitness is also tested
    if(length(alternative) == 1) alternative <- rep(alternative,2)
    if(length(alternative) > 2) alternative <- alternative[c(1,2)]

    Tstat <- rbind(unlist(ests[1,]),unlist(ests[3,]))   # Extract estimates to compute statistic of the test
    sds <- rbind(unlist(ests[2,]),unlist(ests[4,]))     # Standard deviation of the estimates
    colnames(Tstat) <- NULL
    ests <- cbind(Tstat[1,],Tstat[2,])                  # Keep the estimates

    if(nsamples == 2){               # If Two-sample test
      Tstat <-- apply(Tstat,1,diff)                     # Statistic of the test is build with difference of estimates
      sds <- apply(sds,1,function(s){sqrt(sum(s^2))})   # Standard deviation of the difference between estimates
    }
    colnames(ests) <- c(if(with.prob) "mutprob" else "mutations","fitness")
  }

  cint <- mapply(function(e,s,alt){
    if(alt == "less"){                                        # Confidence interval(s) of the test
      c(-Inf,e+s*qnorm(conf.level))                           # with respect to the confidence level
    } else if(alt == "greater"){                              # and the alternative
      c(e-s*qnorm(conf.level),Inf)
    } else if(alt == "two.sided"){
      e+s*c(-1,1)*qnorm((1+conf.level)/2)
    }
  },Tstat,sds,alternative)



  Tstat <- (Tstat-H0)/sds                                      # Statistic(s) of the test

  pval <- mapply(function(alt,tstat){
      if(alt == "less"){                                        # p-value(s) of the test
	pnorm(tstat)                                            # with respect to the alternative
      } else if(alt == "greater"){
	pnorm(tstat,lower.tail=FALSE)
      } else if(alt == "two.sided"){
	2*pnorm(-abs(tstat))
      }
    },alternative,Tstat)

    if(nsamples == 2){
      names(Tstat) <- sapply(colnames(ests),function(noun){paste(noun,"difference")})
    } else {
      names(Tstat) <- names(ests)
    }

    colnames(cint) <- names(Tstat)
    names(pval) <- names(Tstat)
    names(alternative) <- names(Tstat)

  rownames(cint) <- c("bInf","bSup")


  attr(cint,"conf.level") <- conf.level

  # Build object with 'flantest' class

  flantest(Tstat=Tstat,estimate=ests,parameter=parameter,conf.int=cint,p.value=pval,
  null.value=H0,alternative=alternative,data.name=dname,model=model,method=method,nsamples=nsamples)

}

    ## --------------------------------------------------------------------------------------------------------------
    ############################ Density, distribution function, quantile function and random #######################
    ################################## generation for the mutants counts ############################################
    ## --------------------------------------------------------------------------------------------------------------

    # There are two cases :
    #  - If alpha is given, then returns a sample mcs of mutants counts with parameters :
    #   * mutations : mean number of mutation of mutation
    #   * fitness : fitness parameter
    #   * death : probability of death
    #   * dist : lifetimes distribution
    #
    #  - If alpha is not given, then compute first a sample fn of final counts with a Log-Normal distribution with mean mfn and
    #    coefficient of variation cvfn. Then compute a sample mcs of mutants counts, where the ith count has the following parameters :
    #   * mutprob*fni : mean number of mutation
    #                      (where fni is the corresponding of final count, and pi the probability of mutation)
    #   * fitness : fitness parameter
    #   * death : probability of death
    #   *dist : lifetimes distribution
    #
    #   Returns the two samples mcs and fn
    #
rflan <- function(n,mutations=1,mutprob=NULL,fitness=1,death=0.,
        dist=list(name="lnorm",meanlog=-0.3795851,sdlog=0.3016223),
        mfn=1e9,cvfn=0) {

    if(n <= 0) stop("'n' must be a positive integer.")

    if(length(n) > 1) n <- length(n)

    if(mutations < 0 | length(mutations) > 1) stop("'mutations' must be a single positive number")

    if(fitness < 0 | length(fitness) > 1) stop("'fitness' must be a single positive number")

    if(mfn < 0 | length(mfn) > 1) stop("'mfn' must be a single positive number")

    if(cvfn < 0 | length(cvfn) > 1) stop("'cvfn' must be a single positive number")

    if(!is.list(dist)) stop("'dist' must be a list of a character chain followed by its arguments")


    names(dist)[1] <- "name"
    if(dist$name == "exp"){
      names(dist)[2] <- "rate"
    } else if(dist$name == "dirac"){
      names(dist)[2] <- "location"
    } else if(dist$name == "lnorm"){
      names(dist)[2] <- "meanlog"
      names(dist)[3] <- "sdlog"
    } else if(dist$name == "gamma"){
      names(dist)[2] <- "shape"
      names(dist)[3] <- "scale"
    } else stop("'dist[[1]]' must be a character chain among 'exp', 'dirac', 'lnorm', 'gamma'")


    if(death < 0 | death >= 0.5 | length(death) > 1) stop("'death' must be a single positive and < 0.5 number ")


    if(!is.null(mutprob)){
      if(mutprob < 0 | mutprob > 1 | length(mutprob) > 1) stop("'mutprob' must be a single positive and <= 1 number")
      mutations <- mutprob*(if(cvfn == 0) mfn else 1)              # Sample with mutprob instead of mutations if cvfn > 0
    } else {
      if(cvfn > 0) mutations <- mutations/mfn    # Default value of mutprob if missing and cvfn > 0
    }



      # output <- .Call("rflan",list(
			#   n=as.integer(n),
			#   mutations=as.double(mutations),
			#   fitness=as.double(fitness),
			#   death=as.double(death),
			#   distribution=dist,
			#   mfn=as.double(mfn),
			#   cvfn=as.double(cvfn)
			#   )
		  # )

    if(dist$name == "lnorm" | dist$name == "gamma")  dist <- adjust.rate(dist,1,death)
    flan.sim <- new(FlanSim,list(
      mutations=mutations,
      fitness=fitness,
      death=death,
      dist=dist,
      mfn=mfn,
      cvfn=cvfn
      ))
      
    output <-flan.sim$rflan(n)


    mc <- output$mc
    indNA <- which(mc < 0)
    if(length(indNA) > 0){
      warning("Production of NaNs in geometric sampling.")
      output$mc[indNA] <- NaN
    }
    
    if(cvfn == 0) output$fn <- rep(mfn,n)

    output
}

  # Quantile function of the mutants count with parameter
  #   mutations : mean number of mutations
  #   fitness : fitness parameter
  #   death : death probability
  #   model : lifetimes distribution model : exponentialy distributed lifetimes ("LD") or constant lifetimes ("H")

qflan <- function(p,mutations=1,fitness=1,death=0.,model=c("LD","H"),lower.tail=TRUE){

  if((sum(p < 0)+sum(p > 1)) != 0){
    stop("'p' must be a vector of positive and <= 1 numbers")
  }
  if(mutations < 0 | length(mutations) > 1){
    stop("'mutations' must be a single positive number.")
  }
  if(fitness < 0 | length(fitness) > 1){
    stop("'fitness' must be a single positive number.")
  }
  if(death < 0 | death >= 0.5 | length(death) > 1){
    stop("'death' must be a single positive and < 0.5 number.")
  }
  if(missing(model)){model="LD"}
  model <- match.arg(model)
#   if(!lower.tail) p <- 1-p


  m <- 100
  P <- pflan(0:m,mutations,fitness,death,model,lower.tail)
  sapply(p,function(pp){
    if(pp == 1) Inf
    if (lower.tail & pp <= P[1]) 0
    if (!lower.tail & pp >= P[1]) 0
    else {
      k <- if(lower.tail) max(which(P<pp)) else max(which(P>pp))          # quantile if in the actual table
      while (k>=m){                   # if p not yet in the table
	m2 <- 2*m                       # double the table
	P2 <- pflan(m:m2,mutations,fitness,death,model,lower.tail)      # truncated distribution function
	if (lower.tail & pp <= P2[1]) k
	if (!lower.tail & pp >= P2[1]) k
	else {
	  k <- k-1+if(lower.tail) max(which(P2<pp)) else max(which(P2>pp))           # quantile if in the table
	  m <- m2
	}
      }                              # end while
    }                                  # end if
    k
  })

}

  # Distribution function of the mutants count with parameter
  #   mutations : mean number of mutations
  #   fitness : fitness parameter
  #   death : death probability
  #   model : lifetimes distribution model : exponentialy distributed lifetimes ("LD") or constant lifetimes ("H")


pflan <- function(m,mutations=1,fitness=1,death=0.,model=c("LD","H"),lower.tail=TRUE){

  if(sum(m < 0) > 0 | sum(trunc(m) != m) > 0){
    stop("'m' must be a vector of positive integers")
  }
  if(mutations < 0 | length(mutations) > 1){
    stop("'mutations' must be a single positive number.")
  }
  if(fitness < 0 | length(fitness) > 1){
    stop("'fitness' must be a single positive number.")
  }
  if(death < 0 | death >= 0.5 | length(death) > 1){
    stop("'death' must be a single positive and < 0.5 number.")
  }
  if(missing(model)){model="LD"}
  model <- match.arg(model)

#   output=.Call("pflan",
#     list(m=as.integer(max(m)),mutations=as.double(mutations),fitness=as.double(fitness),death=as.double(death),model=as.character(model),lowerTail=as.logical(lower.tail),bool=as.logical(length(m)>1)))

  flan.mutmodel <- new(FlanMutMod,list(
    mutations=mutations,
    fitness=fitness,
    death=death,
    model=model,
    lt=lower.tail
  ))
  
#   print(flan.mutmodel$getfcts())
  
  M=max(m)
  output <- flan.mutmodel$pflan(M)

  output[m+1]
}


  # Density function of the mutants count with parameter
  #   mutations : mean number of mutations
  #   fitness : fitness parameter
  #   death : death probability
  #   model : lifetimes distribution model : exponentialy distributed lifetimes ("LD") or constant lifetimes ("H")


dflan <- function(m,mutations=1,fitness=1,death=0.,model=c("LD","H")){

  if(sum(m < 0) > 0 | sum(trunc(m) != m) > 0){
    stop("'m' must be a vector of positive integers")
  }
  if(mutations < 0 | length(mutations) > 1){
    stop("'mutations' must be a single positive number.")
  }
  if(fitness < 0 | length(fitness) > 1){
    stop("'fitness' must be a single positive number.")
  }
  if(death < 0 | death >= 0.5 | length(death) > 1){
    stop("'death' must be a single positive and < 0.5 number.")
  }
  if(missing(model)){model="LD"}
  model <- match.arg(model)

  
  flan.mutmodel <- new(FlanMutMod,list(
    mutations=mutations,
    fitness=fitness,
    death=death,
    model=model,
    lt=TRUE
  ))
  
  M <- max(m)
  output <- flan.mutmodel$dflan(M)

  output[m+1]
}



    ## --------------------------------------------------------------------------------------------------------------
    ############################################## Hidden functions #################################################
    ## --------------------------------------------------------------------------------------------------------------


## Sampling
adjust.rate <- function(dist,fitness=1,death=0.){
#   rescales the parameter(s) of distribution dist to obtain growh rate equal to fitness.
#   The distribution is given and returned as a list of a character chain 
#   followed by the list of parameters. 

  adist <- dist				# adjusted distribution
  m <- 2*(1-death)			# mean offspring number
  switch(dist[[1]],
    dirac={                              # Dirac distribution
	adist$location <- log(m)/fitness      # new location parameter
	return(adist)
	  },                              # end Dirac distribution
    exp={                                # Exponential distribution
	adist$rate <- fitness/(m-1)
	return(adist)
	  },   
    gamma={				# Gamma distribution
      a <- dist$shape			# according to the shape parameter
      adist$scale <- (m^(1/a)-1)/fitness	# adjust scale parameter 
    },
    lnorm={					# Log-normal distribution
#       s <- growth.rate(dist,death)		# according to the rate
      a <- dist$sdlog
      l <- dist$meanlog
      lap <- function(s){               # Laplace transform
	f <- function(x){exp(-(s*exp(a*x*sqrt(2)+l)+x^2))}

	I <- {integrate(f,
	      lower=-Inf,upper=Inf,rel.tol=.flantol,subdivisions=.flansubd)}      # integrate from - to + infinity
	
	I <- I$value                      # get the value
  	I <- I/sqrt(pi)			# rescale
        I-1/m                     # return shifted Laplace transform
      }
      lwb <- 1                          # lower bound of search interval
      while(lap(lwb)<0){lwb<-lwb/2}     # adjust lower bound
      upb <- 1                          # upperbound of search interval
      while(lap(upb)>0){upb<-upb+1}     # adjust upperbound
      s <- uniroot(lap,c(lwb,upb))$root       # find root of lap 
      adist$meanlog <- log(s/fitness)+adist$meanlog	# adjust scale parameter 
     
    }
  )
  adist
}

## Estimation

	      #//////////////////////////////////ML method//////////////////////////////////#
	      
# Returns the ML estimate of mean number of mutation for a sample mc, given the fitness and death
# If mfn or cvfn are non-empty, returns the estimate of mutation probability instead of the mean number, after decreasing the bias
# induced if cvfn > 0
MutationMLOptimization <- function(mc,mfn=NULL,cvfn=NULL,model=c("LD","H"),fitness=1,death=0.,winsor=512){

  if(missing(model)) model <- "LD"
  model <- match.arg(model)

  
  # Initialization
  a.est <- MutationGFEstimation(mc,fitness=fitness,death=death,model=model)$mutations
  
  # Winsorization
  if(max(mc) > winsor) mc[mc > winsor] = winsor
  
  
  dC <- dclone(m=0:max(mc),fitness=fitness,death=death,model=model)
  
  ll <- function(a){
    p <- log(deduce.dflan(m=mc,mutations=a,fitness=fitness,death=death,model=model,clone=dC))
    -sum(p)
  }
  # gradient of log-likelihood of the sample
  dll <- function(a){
    p <- deduce.dflanda(m=mc,mutations=a,fitness=fitness,death=death,model=model,clone=dC)
    res <- p$dQ_da/p$Q
    -sum(res)
  }
  
  
  lower = 0.1*a.est
  upper = 10*a.est
  
  a.est <- lbfgsb3(prm=a.est,fn=ll,gr=dll,lower = lower,upper=upper,control=list(trace=0,iprint=-1))$prm
#   a.est <- optimx(par=a.est,fn=ll,gr=dll,lower = lower,upper=upper)$par_1
  
  dldd <- deduce.dflanda(m=mc,mutations=a.est,fitness=fitness,death=death,model=model,clone=dC)
  
  I <- sum((dldd$dQ_da)^2/(dldd$Q)^2)
  
  sda <- sqrt(1/I)
  
  if(!is.null(mfn)) {
    if(cvfn > 0){
      z4=.tunings$z4
      Mutmodel <- new(FlanMutMod,list(
		mutations=a.est,
		fitness=fitness,
		death=death,
		model=model,
		lt=TRUE
	      ))
      pm.est <- Mutmodel$unbias.mutprob(sda,z4,mfn,cvfn)
    } else pm.est <- list(mutprob=a.est/mfn,sd.mutprob=sda/mfn)
    pm.est
  } else list(mutations=a.est,sd.mutations=sda)
  
  
}

# Returns the ML estimate of mutation probability for a sample of couple (mc,fn), given the fitness and death
MutationProbabilityMLOptimization <- function(mc,fn,model=c("LD","H"),fitness=1,death=0.,winsor=512){

  if(missing(model)) model <- "LD"
  model <- match.arg(model)
  
  mfn <- mean(fn)
  cvfn <- sd(fn)/mfn
  
  # Initialization
  pm.est <- MutationGFEstimation(mc=mc,mfn=mfn,cvfn=cvfn,fitness=fitness,death=death,model=model)$mutprob*mfn

  # Winsorization
  if(max(mc) > winsor) mc[mc > winsor] = winsor
  
  dC <- dclone(m=0:max(mc),fitness=fitness,death=death,model=model)
  
  ll <- function(pm){
    p <- mapply(function(x,y){
      y <- y/mfn
      log(deduce.dflan(m=x,mutations=pm*y,fitness=fitness,death=death,model=model,clone=dC))
    },mc,fn)
    -sum(p)
  }
  
  # gradient of log-likelihood of the sample
  dll <- function(pm){
    res <- mapply(function(x,y){
      y <- y/mfn
      p<-deduce.dflanda(m=x,mutations=pm*y,fitness=fitness,death=death,model=model,clone=dC)
      p$dQ_da*y/p$Q
    },mc,fn)
    -sum(res)
  }
  
  lower = 0.1*pm.est
  upper = 10*pm.est
  
  pm.est <- lbfgsb3(prm=pm.est,fn=ll,gr=dll,lower = lower,upper=upper,control=list(trace=0,iprint=-1))$prm/mfn
#   pm.est <- optimx(par=pm.est,fn=ll,gr=dll,lower = lower,upper=upper)$ar_1/mfn
  
  dldd <- mapply(function(x,y){
	    deduce.dflanda(m=x,mutations=pm.est*y,fitness=fitness,death=death,model=model,clone=dC)
	  },mc,fn)
  
  I <- sum((unlist(dldd[2,])*fn)^2/unlist(dldd[1,])^2)            # Fisher information
  
  sdpm <- sqrt(1/I)
  
  list(mutprob=pm.est,sd.mutprob=sdpm)

}

# Returns the ML estimates of mean number of mutation and fitness for a sample mc, given the death
# If mfn or cvfn are non-empty, returns the estimate of mutation probability instead of the mean number, after decreasing the bias
# induced if cvfn > 0
MutationFitnessMLOptimization <- function(mc,mfn=NULL,cvfn=NULL,model=c("LD","H"),death=0.,winsor=512){

  if(missing(model)) model <- "LD"
  model <- match.arg(model)
  
  # Initialization
  est <- MutationFitnessGFEstimation(mc=mc,death=death,model=model)
  if(!est$succeeds) warning("Initialization of 'fitness' with 'GF'-method has failed.")
  a.est <- est$mutations ; r.est <- est$fitness

  # Winsorization
  if(max(mc) > winsor) mc[mc > winsor] = winsor
  
  ll <- function(param){
    a <- param[1]
    r <- param[2]
    p <- log(dflan(m=mc,mutations=a,fitness=r,death=death,model=model))
    -sum(p)
  }
  
  # gradient of log-likelihood of the sample
  dll <- function(param){
    a = param[1]
    r = param[2]
#     cat("alpha =",a,"| rho =",r,"\n")
    p <- dflan.grad(m=mc,mutations=a,fitness=r,death=death,model=model,dalpha=TRUE,drho=TRUE)
    res <- rbind(p$dQ_da,p$dQ_dr)/p$Q
    -apply(res,1,sum)
  }
  
  lower = 0.1*c(a.est,r.est)
  upper = 10*c(a.est,r.est)
  
  if(!est$succeeds) {
    lower[2] <- 10*r.est ; 
    upper[2] <- 500*r.est
  }
  
  est <- lbfgsb3(prm=c(a.est,r.est),fn=ll,gr=dll,lower = lower,upper=upper,control=list(trace=0,iprint=-1))$prm
#   est <- optimx(par=c(a.est,r.est),fn=ll,gr=dll,lower = lower,upper=upper,method="L-BFGS-B")  
  a.est = est[1]					# Update alpha estimate
  r.est = est[2]					# Update rho estimate
  
  dldd <- dflan.grad(m=mc,mutations=a.est,fitness=r.est,death=death,model=model,dalpha=TRUE,drho=TRUE)
  
  p2 <- (dldd$Q)^2
  dpa <- dldd$dQ_da
  dpr <- dldd$dQ_dr
  
  Ia <- sum((dpa^2/p2))
  Ir <- sum(dpr^2/p2)
  Iar <- sum(dpa*dpr/p2)
# #   
  det <- Ia*Ir-Iar^2
  sda <- sqrt(Ir/det)
  sdr <- sqrt(Ia/det)
  
  if(!is.null(mfn)) {
    if(cvfn > 0){
      z4=.tunings$z4
      Mutmodel <- new(FlanMutMod,list(
		mutations=a.est,
		fitness=r.est,
		death=death,
		model=model,
		lt=TRUE
	      ))
      pm.est <- Mutmodel$unbias.mutprob(sda,z4,mfn,cvfn)
    } else pm.est <- list(mutprob=a.est/mfn,sd.mutprob=sda/mfn)
    
    c(pm.est,fitness=r.est,sd.fitness=sdr)
  } else list(mutations=a.est,sd.mutations=sda,fitness=r.est,sd.fitness=sdr)
  

}


# Returns the ML estimates of mutation probability and fitness for a sample of couple (mc,fn), given the death
MutationProbabilityFitnessMLOptimization <- function(mc,fn,model=c("LD","H"),death=0.,winsor=512){
  
  if(missing(model)) model <- "LD"
  model <- match.arg(model)
  
  mfn <- mean(fn)
  cvfn <- sd(fn)/mfn
  
  
  # Initialization
  est <- MutationFitnessGFEstimation(mc,mfn=mfn,cvfn=cvfn,death=death,model=model)
  if(!est$succeeds) warning("Initialization of 'fitness' with 'GF'-method has failed.") 
  pm.est <- est$mutprob*mfn ; r.est <- est$fitness
  
  # Winsorization
  if(max(mc) > winsor) mc[mc > winsor] = winsor
  
  ll <- function(param){
    pm <- param[1]
    r <- param[2]
    p <- mapply(function(x,y){
      y <- y/mfn
      log(dflan(m=x,mutations=pm*y,fitness=r,death=death,model=model))
    },mc,fn)
    -sum(p)
  }
  
  # gradient of log-likelihood of the sample
  dll <- function(param){
    pm = param[1]
    r = param[2]
    res <- mapply(function(x,y){
      y <- y/mfn
      p<-dflan.grad(m=x,mutations=pm*y,fitness=r,death=death,model=model,dalpha=TRUE,drho=TRUE)
      rbind(p$dQ_da*y,p$dQ_dr)/p$Q
    },mc,fn)
    -apply(res,1,sum)
  }
  
  
  lower = 0.1*c(pm.est,r.est)
  upper = 10*c(pm.est,r.est)
  
  if(!est$succeeds) {
    lower[2] <- 10*r.est ; 
    upper[2] <- 500*r.est
  }
  
  est <- lbfgsb3(prm=c(pm.est,r.est),fn=ll,gr=dll,lower = lower,upper=upper,control=list(trace=0,iprint=-1))$prm
  
  pm.est = est[1]/mfn					# Update alpha estimate
  r.est = est[2]					# Update rho estimate
  
  dldd <- mapply(function(x,y){
	    dflan.grad(m=x,mutations=pm.est*y,fitness=r.est,death=death,model=model,dalpha=TRUE,drho=TRUE)
	  },mc,fn)
  
  p2 <- (unlist(dldd[1,]))^2
  dppm <- unlist(dldd[2,])
  dpr <- unlist(dldd[3,])
  
  Ipm <- sum((dppm^2/p2))
  Ir <- sum(dpr^2/p2)
  Ipmr <- sum(dppm*dpr/p2)
# #   
  det <- Ipm*Ir-Ipmr^2
  sdpm <- sqrt(Ir/det)
  sdr <- sqrt(Ipm/det)
  
  list(mutprob=pm.est,sd.mutprob=sdpm,fitness=r.est,sd.fitness=sdr)

}


	      #//////////////////////////////////P0 method//////////////////////////////////#

# Returns the P0 estimate of mean number of mutations for a sample of couple mc, given the death
MutationsNumberP0Estimation <- function(mc,death=0.){

# Return the estimate of alpha for a sample mc
# by p0-method under cell deaths with probability delta
# # when delta is known.
  if(death > 0){
    dstar <- death/(1-death)			# extinction probability
    epgf <- function(z) mean(z^mc)		# empirical PGF

    a <- -log(epgf(dstar))/(1-dstar)	#  estimate alpha

    sda <- (1-dstar)^(-2)*(epgf(dstar^2)/(epgf(dstar)^2)-1)	# variance of alpha's estimate

    sda <- sqrt(sda/length(mc))

  } else {
    p0 <- mean(mc==0)
    a <- -log(p0)
    sda <- sqrt((1/p0-1)/length(mc))
  }
  
  list(mutations=a,sd.mutations=sda)
  
}


# Returns the P0 estimate of mean number of mutations for a sample of couple mc, given the death
# If mfn or cvfn are non-empty, returns the estimate of the mutation probability instaed of the mean number
# after decreasing the induced bias if cvfn > 0
MutationP0Estimation <- function(mc,mfn=NULL,cvfn=NULL,death=0.){

# Return the estimate of alpha for a sample mc
# by p0-method under cell deaths with probability delta
# # when delta is known.
 
 
  a <- MutationsNumberP0Estimation(mc,death)
  
  sda <- a$sd.mutations
  a <- a$mutations
  
  if(!is.null(mfn)){
    pm <- a/mfn
    sdpm <- sda/mfn
    if(cvfn != 0){
      umds <- 1-death/(1-death)			# extinction probability
      temp <- a*(cvfn^2)*umds         # relative bias on mutprob
      pm <- pm*(1+temp/2)		# unbiased estimator of mutrate
      sdpm <- sdpm*(1+temp)		# standard deviation of unbiased estimator
    } 
    list(mutprob=pm,sd.mutprob=sdpm)
  } else list(mutations=a,sd.mutations=sda)  
}

# Returns the P0 estimate of mean number of mutations and fitness for a sample of couple mc,given the death
# If mfn or cvfn are non-empty, returns the estimate of the mutation probability instaed of the mean number
# after decreasing the induced bias if cvfn > 0
MutationFitnessP0Estimation <- function(mc,fn=NULL,mfn=NULL,cvfn=NULL,model=c("LD","H"),death=0.,winsor=512){

  if(missing(model)) model <- "LD"
  model <- match.arg(model)
  
  a <- MutationsNumberP0Estimation(mc,death)
  
  if(!is.null(fn)){
    mfn <- mean(fn)
    cvfn <- sd(fn)/mfn
  }
  
  sda <- a$sd.mutations
  a <- a$mutations
  
  if(!is.null(mfn)){
    pm <- a/mfn
    sdpm <- sda/mfn
    if(cvfn != 0){
      umds <- 1-death/(1-death)			# extinction probability
      temp <- a*(cvfn^2)*umds         # relative bias on mutprob
      pm <- pm*(1+temp/2)		# unbiased estimator of mutrate
      sdpm <- sdpm*(1+temp)		# standard deviation of unbiased estimator
    }
    output <- list(mutprob=pm,sd.mutprob=sdpm)
  } else output <- list(mutations=a,sd.mutations=sda)
  
  if(!is.null(fn)) r <- FitnessP0Optimization(mc=mc,fn=fn,model=model,mut=pm,death=death,winsor=winsor)
  else r <- FitnessP0Optimization(mc=mc,fn=fn,model=model,mut=a,death=death,winsor=winsor)
    
  c(output,fitness=r$fitness,sd.fitness=r$sd.fitness)  
  
}


# Returns the ML estimate of fitness for a sample of couple mc, given the mean number of mutations (or mutation probability) and death
# If fn is non-empty, 
FitnessP0Optimization <- function(mc,fn=NULL,model=c("LD","H"),mut,death=0.,winsor=512){

  if(missing(model)) model <- "LD"
  model <- match.arg(model)

  # Initialization
  est <- FitnessGFEstimation(mc,death,model)
  if(!est$succeeds) warning("Initialization of 'fitness' with 'GF'-method has failed.")
  r.est <- est$fitness
  
  # Winsorization
  if(max(mc) > winsor){ mc[which(mc>winsor)] = winsor}
  
  
  if(is.null(fn)){
    if(missing(mut)) mut <- 1
    
    ll <- function(r){
      p <- log(dflan(m=mc,mutations=mut,fitness=r,death=death,model=model))
      -sum(p)
    }
    
    # gradient of log-likelihood of the sample
    dll <- function(r){
      p <- dflan.grad(m=mc,mutations=mut,fitness=r,death=death,model=model,dalpha=FALSE,drho=TRUE)
      res <- p$dQ_dr/p$Q
      -sum(res)
    }
  } else {
    if(missing(mut)) mut <- 1e-9
    
    ll <- function(r){
      p <- mapply(function(x,y){
	    log(dflan(m=x,mutations=mut*y,fitness=r,death=death,model=model))
	  },mc,fn)
      -sum(p)
    }
    
    # gradient of log-likelihood of the sample
    dll <- function(r){
      res <- mapply(function(x,y){
	      p<-dflan.grad(m=x,mutations=mut*y,fitness=r,death=death,model=model,dalpha=FALSE,drho=TRUE)      
	      p$dQ_dr/p$Q
	    },mc,fn)
      -sum(res)
    }
  
  }
    
  
  lower = 0.1*r.est
  upper = 10*r.est
  
  if(est$succeeds) {
    lower <- 10*r.est ; 
    upper <- 500*r.est
  }
  
  est <- lbfgsb3(prm=r.est,fn=ll,gr=dll,lower = lower,upper=upper,control=list(trace=0,iprint=-1))
  r.est <- est$prm
  
  if(is.null(fn)) dldd <- dflan.grad(m=mc,mutations=mut,fitness=r.est,death=death,model=model,dalpha=FALSE,drho=TRUE)
  
  else dldd <- mapply(function(x,y){
		  dflan.grad(m=x,mutations=mut*y,fitness=r.est,death=death,model=model,dalpha=FALSE,drho=TRUE)
	       },mc,fn)
  
  I <- sum((dldd$dQ_dr)^2/(dldd$Q)^2)
  
  sdr <- sqrt(1/I)
  list(fitness=r.est,sd.fitness=sdr)
}

	      #//////////////////////////////////GF method//////////////////////////////////#

MutationGFEstimation <- function(mc,mfn=NULL,cvfn=NULL,fitness=1,death=0.,model=c("LD","H")){

  if(missing(model)) model <- "LD"
  model <- match.arg(model)

  q <- .tunings$q
  b <- quantile(mc,q,names=FALSE)+1           # scaling factor
  
  Mutmodel= new(FlanMutMod,list(
    mc=mc,
    mfn=mfn,cvfn=cvfn,
    fitness=fitness,death=death,
    model=model,
    scale=b
  ))
  
  Mutmodel$MutationGFEstimation()
  
}

FitnessGFEstimation <- function(mc,death=0.,model=c("LD","H")){

  if(missing(model)) model <- "LD"
  model <- match.arg(model)

  tu <- .tunings
  q <- tu$q
  b <- quantile(mc,q,names=FALSE)+1           # scaling factor
  z1 <- tu$z1                            # lower value
  z2 <- tu$z2                            # higher value
  z1<-z1^(1/b); z2<-z2^(1/b) ;            # rescale variables 
  
  g1 <- mean(z1^mc)                   # empirical generating function at z1
  g2 <- mean(z2^mc)                   # empirical generating function at z2
  y <- log(g1)/log(g2)                   # get ratio of logs
  
  if(model == "LD") clone=new(FlanExpClone,list(death=death))
  if(model == "H") clone=new(FlanDirClone,list(death=death))
  
  f <- function(r){
    PGF <- clone$pgf2(r,c(z1,z2))
    ((1-PGF[1])/(1-PGF[2]))-y
  }
		  
  binf <- 0.01
  bsup <- 100
  
  GFrho.succeeds <- TRUE
  if(f(binf)*f(bsup)>0) {
    rho <- 1
    GFrho.succeeds <- FALSE
  } else rho <- uniroot(f,interval=c(binf,bsup),tol=1e-6,maxiter=1e3)$root
  
  list(fitness=rho,succeeds=GFrho.succeeds)

}


MutationFitnessGFEstimation <- function(mc,mfn=NULL,cvfn=NULL,death=0.,model=c("LD","H")){

  if(missing(model)) model <- "LD"
  model <- match.arg(model)

  tu <- .tunings
  q <- tu$q
  b <- quantile(mc,q,names=FALSE)+1           # scaling factor
  z1 <- tu$z1                            # lower value
  z2 <- tu$z2                            # higher value
  z3 <- tu$z3
  z1<-z1^(1/b); z2<-z2^(1/b) ; z3 <- z3^(1/b)             # rescale variables 
  
  rho=FitnessGFEstimation(mc,death=death,model=model)
  
  if(rho$succeeds){
    
    a.est=MutationGFEstimation(mc,fitness=rho$fitness,death=death,model=model)
    
    Mutmodel <- new(FlanMutMod,list(
		  mutations=a.est$mutations,
		  fitness=rho$fitness,
		  death=death,
		  model=model,
		  lt=TRUE
		))
    
    Cov <- Mutmodel$CovGFEstimation(z1,z2,z3)
    
    sd <- sqrt(diag(Cov)/length(mc))
    
    if(!is.null(mfn)) {
      if(cvfn > 0) pm.est <- Mutmodel$unbias.mutprob(sd[1],z3,mfn,cvfn)
      else pm.est <- list(mutprob=a.est$mutations/mfn,sd.mutprob=sd[1]/mfn)
      
      c(pm.est,fitness=rho$fitness,sd.fitness=sd[2],
		succeeds=rho$succeeds)
      
    } else list(mutations=a.est$mutations,sd.mutations=sd[1],
		fitness=rho$fitness,sd.fitness=sd[2],
		succeeds=rho$succeeds)
  } else {
    res <- MutationGFEstimation(mc,mfn,cvfn,rho$fitness,death,model)
    c(res,fitness=rho$fitness,sd.fitness=0,succeeds=rho$succeeds)
  }
   
}

dclone <- function(m,fitness=1,death=0.,model=c("LD","H")){

  if(sum(m < 0) > 0 | sum(trunc(m) != m) > 0){
    stop("'m' must be a vector of positive integers")
  }
  if(fitness < 0 | length(fitness) > 1){
    stop("'fitness' must be a single positive number.")
  }
  if(death < 0 | death >= 0.5 | length(death) > 1){
    stop("'death' must be a single positive and < 0.5 number.")
  }
  
  if(missing(model)){model="LD"}
  model <- match.arg(model)

  
  if(model=="LD") clone <- new(FlanExpClone,list(fitness=fitness,death=death))
  if(model == "H") clone <- new(FlanDirClone,list(fitness=fitness,death=death))
  
  
  M <- max(m)
  
  
  clone$dclone(M)[m+1]

}



dflan.grad <- function(m,mutations=1,fitness=1,death=0.,model=c("LD","H"),dalpha=TRUE,drho=FALSE){

  if(sum(m < 0) > 0 | sum(trunc(m) != m) > 0){
    stop("'m' must be a vector of positive integers")
  }
  if(mutations < 0 | length(mutations) > 1){
    stop("'mutations' must be a single positive number.")
  }
  if(fitness < 0 | length(fitness) > 1){
    stop("'fitness' must be a single positive number.")
  }
  if(death < 0 | death >= 0.5 | length(death) > 1){
    stop("'death' must be a single positive and < 0.5 number.")
  }
  
  if(!(dalpha | drho)) stop("Need to precise which derivative has to be computed.")
  
  if(missing(model)){model="LD"}
  model <- match.arg(model)

#   output=.Call("dflan",
#   list(m=as.integer(max(m)),mutations=as.double(mutations),fitness=as.double(fitness),death=as.double(death),model=as.character(model),bool=as.logical(length(m)>1)))
  
  flan.mutmodel <- new(FlanMutMod,list(
    mutations=mutations,
    fitness=fitness,
    death=death,
    model=model,
    lt=TRUE
  ))
  
  M <- max(m)
  
  
  if(dalpha){
    if(drho) output <- flan.mutmodel$dflangrad(M)
    else output <- flan.mutmodel$dflanda(M)
  } else output <- flan.mutmodel$dflandr(M)
  
  lapply(output,function(l) l[m+1])
}


deduce.dflan <- function(m,mutations=1,fitness=1,death=0.,model=c("LD","H"),clone){

  if(sum(m < 0) > 0 | sum(trunc(m) != m) > 0){
    stop("'m' must be a vector of positive integers")
  }
  if(mutations < 0 | length(mutations) > 1){
    stop("'mutations' must be a single positive number.")
  }
  if(fitness < 0 | length(fitness) > 1){
    stop("'fitness' must be a single positive number.")
  }
  if(death < 0 | death >= 0.5 | length(death) > 1){
    stop("'death' must be a single positive and < 0.5 number.")
  }
  if(missing(model)){model="LD"}
  model <- match.arg(model)

  
  flan.mutmodel <- new(FlanMutMod,list(
    mutations=mutations,
    fitness=fitness,
    death=death,
    model=model,
    lt=TRUE
  ))
  
  M <- max(m)
  
  output <- flan.mutmodel$deduce.dflan(M,clone)

  output[m+1]
}

deduce.dflanda <- function(m,mutations=1,fitness=1,death=0.,model=c("LD","H"),clone){

  if(sum(m < 0) > 0 | sum(trunc(m) != m) > 0){
    stop("'m' must be a vector of positive integers")
  }
  if(mutations < 0 | length(mutations) > 1){
    stop("'mutations' must be a single positive number.")
  }
  if(fitness < 0 | length(fitness) > 1){
    stop("'fitness' must be a single positive number.")
  }
  if(death < 0 | death >= 0.5 | length(death) > 1){
    stop("'death' must be a single positive and < 0.5 number.")
  }
  
  if(missing(model)){model="LD"}
  model <- match.arg(model)

#   output=.Call("dflan",
#   list(m=as.integer(max(m)),mutations=as.double(mutations),fitness=as.double(fitness),death=as.double(death),model=as.character(model),bool=as.logical(length(m)>1)))
  
  flan.mutmodel <- new(FlanMutMod,list(
    mutations=mutations,
    fitness=fitness,
    death=death,
    model=model,
    lt=TRUE
  ))
  
  M <- max(m)
  
  
  output <- flan.mutmodel$deduce.dflanda(M,clone)
  
  lapply(output,function(l) l[m+1])
}


## --------------------------------------------------------------------------------------------------------------
  ############################################## flantest object class ##############################################
  ## --------------------------------------------------------------------------------------------------------------
    
# Constructor of the class flantest
flantest <- function(Tstat,parameter,estimate,p.value,conf.int,estimates,null.value,alternative,model,method,data.name,sample.name,nsamples){
  obj <- list(Tstat=Tstat,estimate=estimate,parameter=parameter,conf.int=conf.int,p.value=p.value,
  null.value=null.value,alternative=alternative,data.name=data.name,model=model,method=method,nsamples=nsamples)
  class(obj) <- "flantest"
  obj
}

# Print function for flantest objects, inspired from print function for htest objects
print.flantest <- function(x,...){
  digits <- getOption("digits")
  prefix <- "\t"
  cat("\n")
  if(x$nsamples == 2){
    cat(strwrap(paste("Two sample ",x$method,"-test"," (",x$model," model)",sep=""), prefix=prefix), sep="\n")
  } else {
    cat(strwrap(paste("One sample ",x$method,"-test"," (",x$model," model)",sep=""), prefix=prefix), sep="\n")
  }
  cat("\n")
  cat("------------------------------------- Data -----------------------------------\n")

  if(x$nsamples == 2){
    if(length(x$data.name) == 1){
      cat("data:  ",x$data.name[[1]][1]," and ",x$data.name[[1]][2],"\n", sep="")
    }
    if(length(x$data.name) == 2){
      if(length(x$data.name[[2]]) == 2){
	cat("data:  ",x$data.name[[1]][1]," with ",x$data.name[[2]][1],
	" and ",x$data.name[[1]][2]," with ",x$data.name[[2]][2],"\n", sep="")
      } else {
	cat("data:  ",x$data.name[[1]][1]," with ",x$data.name[[2]][1],
	" and ",x$data.name[[1]][2],"\n", sep="")
      }
    }
  }
  if(x$nsamples == 1){
    if(length(x$data.name) == 1){
      cat("data:  ",x$data.name[[1]][1],"\n", sep="")
    }
    if(length(x$data.name) == 2){
      cat("data:  ",x$data.name[[1]][1]," with ",x$data.name[[2]][1],"\n", sep="")
    }
  }
  
  out <- character()

  if(!is.null(x$null.value)){
    if(length(x$null.value) == 1){
      if(!is.null(x$parameter)){
	if(x$nsamples == 2){
	  Nparam <- dim(x$param)[2]
	  cat("Sample 1 parameters : ")
	  for(i in 1:Nparam){
	    out <- c(out,paste(colnames(x$parameter)[i], "=", format(signif(x$parameter[1,i], 
	      max(1, digits - 2)))))
	  }
	  cat(strwrap(paste(out, collapse=", ")), sep="\n")
	  out <- character()
	  cat("Sample 2 parameters : ")
	  for(i in 1:Nparam){
	    out <- c(out,paste(colnames(x$parameter)[i], "=", format(signif(x$parameter[2,i], 
	      max(1, digits - 2)))))
	  }
	} else {
	  Nparam <- length(x$parameter)
	  for(i in 1:Nparam){
	    if(names(x$parameter[i])=="mfn"){
	      out <- c(out,paste(names(x$parameter[i]), "=", format(x$parameter[i], 
	      scientific=TRUE,digit=5)))
	    } else {
	      out <- c(out,paste(names(x$parameter[i]), "=", format(signif(x$parameter[i], 
	      max(1, digits - 2)))))
	    }
	  }
	}
      }
      cat(strwrap(paste(out, collapse=", ")), sep="\n")
      cat("---------------------------------- Statistics --------------------------------\n")
      if(!is.null(x$Tstat)){
	cat("Tstat =", format(signif(x$Tstat, 
	  max(1, digits - 2))),"\n")
      }
      if (!is.null(x$p.value)) {
	fp <- format.pval(x$p.value, digits= max(1, digits - 
	    3))
	cat("p-value for",names(x$null.value[1]), if (substr(fp, 1, 1) == 
	  "<") fp else paste("=", fp),"\n")
      }
      
      if (!is.null(x$alternative)) {
	cat("Alternative hypothesis: ")
	alt.char <- switch(x$alternative, two.sided="not equal to", 
		less="less than", greater="greater than")
	cat("true ", names(x$null.value), " is ", alt.char, 
	  " ", x$null.value, "\n", sep="")
      }
      
      if (!is.null(x$conf.int)) {
	cat(format(100 * attr(x$conf.int, "conf.level")), " percent confidence interval:\n",
	paste(format(x$conf.int),collapse="  "),
	"\n")
      }
      if (!is.null(x$estimate)) {
	if(x$nsamples == 1){
	  cat("Sample estimates : \n")
	  print(x$estimate)
	}
	if(x$nsamples == 2){
	  cat("Sample 1 estimates : \n")
	  print(x$estimate[1,])
	  cat("Sample 2 estimates : \n")
	  print(x$estimate[2,])
	}
      }
    } else if(length(x$null.value)==2){
      
      if(!is.null(x$parameter)){
	if(x$nsamples == 2){
	  cat("Sample 1 parameters : ")
	  Nparam <- dim(x$param)[2]
	  for(i in 1:Nparam){
	    out <- c(out,paste(colnames(x$parameter)[i], "=", format(signif(x$parameter[1,i], 
	      max(1, digits - 2)))))
	  }
	  cat(strwrap(paste(out, collapse=", ")), sep="\n")
	  out <- character()
	  cat("Sample 2 parameters : ")
	  for(i in 1:Nparam){
	    if(colnames(x$parameter)[i] == "mfn"){
	      out <- c(out,paste(colnames(x$parameter)[i], "=", format(x$parameter[2,i], 
	      scientific=TRUE,digit=5)))
	    } else {
	      out <- c(out,paste(colnames(x$parameter)[i], "=", format(signif(x$parameter[2,i], 
	      max(1, digits - 2)))))
	    }
	  }
	} 
	if(x$nsamples == 1){
	  cat("Sample parameters : ")
	  Nparam <- length(x$parameter)

	  for(i in 1:Nparam){
	    out <- c(out,paste(names(x$parameter[i]), "=", format(signif(x$parameter[i], 
	      max(1, digits - 2)))))
	  }
	}
      }
      cat(strwrap(paste(out, collapse=", ")), sep="\n")
      cat("---------------------------------- Statistics --------------------------------\n")
      if(!is.null(x$Tstat)){
	cat("Tstat = (",format(signif(x$Tstat[1], 
	  max(1, digits - 2)))," , ",format(signif(x$Tstat[2],
	  max(1, digits - 2))),")","\n",sep="")
      }
      if (!is.null(x$p.value)) {
	fp1 <- format.pval(x$p.value[1], digits=max(1, digits - 
	    3))
	fp2 <- format.pval(x$p.value[2], digits=max(1, digits - 
	    3))
	cat("p-value for",names(x$null.value[1]), if (substr(fp1, 1, 1) == 
	  "<") fp1 else paste("=", fp1),"\np-value for",names(x$null.value[2]),if (substr(fp2, 1, 1) == 
	  "<") fp2 else paste("=", fp2),"\n")
      }
      if (!is.null(x$alternative)) {
	cat("Alternative hypotheses: ")
	alt.char1 <- switch(x$alternative[1], two.sided="not equal to", 
		less="less than", greater="greater than")
	alt.char2 <- switch(x$alternative[2], two.sided="not equal to", 
		less="less than", greater="greater than")
	cat("true ", names(x$null.value[1]), " is ", alt.char1, 
	  " ", x$null.value[1], "\n", sep="")
	cat("                        ")
	cat("true ", names(x$null.value[2]), " is ", alt.char2, 
	  " ", x$null.value[2], "\n", sep="")
      }
      if (!is.null(x$conf.int)) {
	cat(format(100 * attr(x$conf.int, "conf.level")), " percent confidence interval for ",names(x$null.value[1]),": \n", 
	  paste(format(x$conf.int[,1]),collapse="   "),
	  "\n",
	  format(100 * attr(x$conf.int, "conf.level")), " percent confidence interval for ",names(x$null.value[2]),": \n",
	  paste(format(x$conf.int[,2]),collapse="   "),
	  "\n",sep="")
      }
      if (!is.null(x$estimate)) {
	if(x$nsamples == 1){
	  cat("Sample estimates : \n")
	  print(x$estimate[1,])
	}
	if(x$nsamples == 2){
	  cat("Sample 1 estimates : \n")
	  print(x$estimate[1,])
	  cat("Sample 2 estimates : \n")
	  print(x$estimate[2,])
	}
      }
    } 
    cat("\n")
  }    
}


draw.clone <- function(t,mutprob=1e-2,fitness=1,death=0.,
	     dist=list("lnorm",meanlog=-0.3795851,sdlog=0.3016223)){
  #   Simulates a clone up to time t, represents the clone, and
  #   returns the vector of split times.
  #   At each division, the probability of having a mutant is mutprob.
  #   Variable death is the probability of death of a cell. 
  #   The division times of have distribution dist, normalized
  #   to unit growth rate for mutant, to fitness for normal cells.
  #   The distribution dist is given as a list of a character chain 
  #   followed by the list of parameters. 
  #
  #   usage: draw.clone(5)
  #          draw.clone(t=9,fitness=0.5,death=0.1)
  #          draw.clone(t=3,mutprob=0.1,fitness=2,dist=dexp,death=0.2)
  #
  
  
    names(dist)[1] <- "name"
    if(dist$name == "exp"){
      names(dist)[2] <- "rate"
    } else if(dist$name == "dirac"){
      names(dist)[2] <- "location"
    } else if(dist$name == "lnorm"){
      names(dist)[2] <- "meanlog"
      names(dist)[3] <- "sdlog"
    } else if(dist$name == "gamma"){
      names(dist)[2] <- "shape"
      names(dist)[3] <- "scale"
    } else stop("'dist[[1]]' must be a character chain among 'exp', 'dirac', 'lnorm', 'gamma'")

    
		    # initialization
  p <- mutprob                            # mutation probability
  distn <- adjust.rate(dist,fitness=fitness,death=death)      # division times of normal cells
  distm <- adjust.rate(dist,fitness=1,death=death)            # division times of mutants
  g <- 0                                  # current generation
  ce <- 1                                 # cells of current generation
  mu <- FALSE                                 # mutants in current generation
  bd <- 0                                 # birth dates of current generation
  dt <- rdt(1,distn)                      # life times of current generation
  de <- bd+dt                             # death dates of current generation
  or <- 1                                 # location of cells in current generation
  div <- {which((de<t)&                   # indices of cells dead before t
	      (runif(length(de))>death))} # that will divide
  de <- min(de,t)                         # truncate death dates
  nd <- length(div)                       # number of dividing cells
  nc <- nd                                # total number of cells
  CE <- ce                                # all cells
  MU <- mu                                # all mutants
  BD <- bd                                # all birth dates
  DE <- de                                # all death dates
  OR <- or                                # all locations
		    # main loop
  while((nd>0)&&(nc<1e+4)){               # while divisions still happen  
      g <- g+1                            # next generation
      ce <- 2*ce[div]; ce <- c(ce,ce+1)   # cells in next generation
	  mu <- mu[div]                   # mutants that divide
	  mu1 <- {sample(c(TRUE,FALSE),length(div),                      
	      replace=TRUE,prob=c(p,1-p))}# new mutants in next generation
  # 	if (){mu1}
	  mu1 <- mu|mu1                   # mutants in next generation
	  mu <- c(mu1,mu)                 # all mutants in next generation
      nd <- nd*2                          # double the number of cells
      bd <- c(de[div],de[div])            # birth dates of daughters
	  imu <- which(mu)                # indices of mutants
	  nmu <- length(imu)              # number of mutants
	  ino <- which(!mu)               # indices of normal cells
	  nno <- length(ino)              # number of normal cells
      dtmu <- rdt(nmu,distm)              # division times of mutants
      dtno <- rdt(nno,distn)              # division times of normal cells
	  dt <- rep(0,nd)                 # division times of daughters
      dt[imu] <- dtmu                     # insert division times of mutants
	  dt[ino] <- dtno                 # insert division times of normal cells
      de <- bd+dt                         # death dates of daughters
      or<-c(or[div]-2^(-g),or[div]+2^(-g))# location of daughters 
      div <- {which((de<t)&               # indices of cells dead before t
	      (runif(length(de))>death))} # that will divide
      de <- mapply(min,de,rep(t,nd))      # truncate death dates
      nd <- length(div)                   # number of dividing daughters
      nc <- nc+nd                         # total number of cells
      CE <- c(CE,ce)                      # stack new cells
      MU <- c(MU,mu)                      # stack mutants
      BD <- c(BD,bd)                      # stack birth dates
      DE <- c(DE,de)                      # stack death dates
      OR <- c(OR,or)                      # stack locations
  }                                       # end while
  if (nc > 1e+4){
    warning("too many cells to plot")
    }else{
		    # treatment for graphics
  if(mutprob == 0){colnor <- "green4"}
  else{
  colnor <- "green4"                      # color for normal cells
  colmut <- "orangered"                   # color for mutants
  }
  nc <- length(CE)                        # number of cells
  if (nc>1){                              # something to plot
  OR <- sort(OR,index.return=TRUE)$ix     # order for plotting
  CE <- CE[OR]                            # reorder cells
  MU <- MU[OR]                            # reorder mutants
  BD <- BD[OR]                            # reorder births
  DE <- DE[OR]                            # reorder deaths
  nmu <- length(which(MU))                # number of mutants
  nno <- nc - nmu                         # number of normal
  BDN <- BD[!MU]                          # births of normal
  DEN <- DE[!MU]                          # deaths of normal
  XN <- rbind(which(!MU),which(!MU))      # abscissas for vertical lines normal
  YN <- rbind(BDN,DEN)                    # ordinates for vertical lines normal
  nlc <- nc - length(which(DE<t))         # living cells at time t
  nlm <- nmu - length(which((DE<t)&MU))   # living mutants at time t
  para <- {substitute(list(               # list of parameters
	  "mutation probability" == t1, fitness == t2, death==t3,
	  cells == t4, mutants ==t5),    # names
	  list(t1=p,t2=fitness,t3=death,
	  t4=nlc,t5=nlm))}               # values
#   if(!Lab){para = NULL}
  name <- switch(dist[[1]],               # distribution of division times
	  dirac="constant lifetimes",
	  exp="exponential lifetimes",
	  gamma="gamma lifetimes",
	  lnorm="log-normal lifetimes")
  {matplot(XN,YN,                         # plot vertical lines
	  main=para,                     # add title
	  xlim=c(1,nc),             
	  ylim = c(t,0),                 # reverse y axis
	  type="l",col=colnor,           # color for normal
	  lty=rep(1,nno),                # solid lines
	  axes=FALSE,                    # remove axes
	  xlab=name,ylab="time")}        # axes labels
  axis(side=2)                            # draw time axis
  if(nmu>0){                              # if any mutant
    BDM <- BD[MU]                        # births of mutant
    DEM <- DE[MU]                        # deaths of mutant
    XM <- rbind(which(MU),which(MU))     # abscissas for vertical lines mutant
    YM <- rbind(BDM,DEM)                 # ordinates for vertical lines mutant
    {matlines(XM,YM,                     # plot horizontal lines
	  type="l",col=colmut,           # color for mutant
	  lty=rep(1,nmu))}               # solid lines
  }                                       # end if any mutants
  div <- which((DE<t)&(!MU))              # indices dividing cells normal
  DIN <- CE[div]                          # identities dividing cells normal
  DLN <- 2*DIN                            # identities of left daughters
  IO <- sort(CE,index.return=TRUE)        # numeral order of cells
  IOx <- IO$x; IOix <- IO$ix              # get cells and order
  indn <- which(IOx %in% DLN)             # identify left daughters normal 
  XLN <- IOix[indn]                       # indices of left daughters normal
  XRN <- IOix[indn+1]                     # indices of right daughters normal
  XN <- rbind(XLN,XRN)                    # abscissas for horizontal lines
  YN <- rbind(BD[XLN],BD[XRN])            # ordinates for horizontal lines
  {matlines(XN,YN,                        # plot horizontal lines
	  type="l",col=colnor,           # color normal
	  lty=rep(1,nno))}               # solid lines
  div <- which((DE<t)&MU)                 # indices dividing cells mutant
  if (length(div>0)){                     # if any dividing mutant
    DIM <- CE[div]                       # identities dividing cells mutant
    DLM <- 2*DIM                         # identities of left daughters
    indm <- which(IOx %in% DLM)          # identify left daughters mutant
    XLM <- IOix[indm]                    # indices of left daughters mutant
    XRM <- IOix[indm+1]                  # indices of right daughters mutant
    XM <- rbind(XLM,XRM)                 # abscissas for horizontal lines
    YM <- rbind(BD[XLM],BD[XRM])         # ordinates for horizontal lines
    {matlines(XM,YM,                     # plot horizontal lines
	  type="l",col=colmut,           # color mutant
	  lty=rep(1,nmu))}               # solid lines
  }                                       # end if any dividing mutant
  }                                       # end if something to plot
  }                                       # end if graphics
#   ST <- sort(BD)                          # split times
#   ST <- append(ST,t)                      # final instant
#   list(ST=ST,nc=nc)                              # return birth dates
}


rdt <- function(n,dist){
#   Returns a sample of size n of distribution dist.
#   The distribution dist is given as a list of a character chain 
#   followed by the list of parameters. 
#
#   usage: dist <- list("lnorm",meanlog=0,sdlog=1)
#          rdt(100,dist)
#          rdt(1000,goflnormBA)
#
switch(dist[[1]],
    dirac={                             # constant division times
        l <- dist$location              # location parameter
        rep(l,n)
          },                            # end Dirac distribution
    exp={                               # exponential distribution
        r <- dist$rate                  # rate parameter
        rexp(n,rate=r)
          },                            # end exponential distribution
    gamma={                             # gamma distribution
        a <- dist$shape                 # shape parameter
        l <- dist$scale                 # scale parameter
        rgamma(n,shape=a,scale=l)
          },                            # end gamma distribution
    lnorm={                             # Log Normal distribution
        a <- dist$sdlog                 # sdlog parameter
        l <- dist$meanlog               # meanlog parameter
        rlnorm(n,meanlog=l,sdlog=a)
          }                             # end log normal distribution
)                                       # end switch
}                                       # end function rdt
rcqls/flan documentation built on May 27, 2019, 3:05 a.m.