## --------------------------------------------------------------------------------------------------------------
############################################## 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"
return(obj)
}
# Print function for flantest objects, inspired from print function for htest objects
print.flantest <- function(object){
digits <- getOption("digits")
prefix <- "\t"
cat("\n")
if(object$nsamples == 2){
cat(strwrap(paste("Paired ",object$method,"-test"," (",object$model," model)",sep=""), prefix=prefix), sep="\n")
} else {
cat(strwrap(paste("One sample ",object$method,"-test"," (",object$model," model)",sep=""), prefix=prefix), sep="\n")
}
cat("\n")
cat("------------------------------------- Data -----------------------------------\n")
if(object$nsamples == 2){
if(length(object$data.name) == 1){
cat("data: ",object$data.name[[1]][1]," and ",object$data.name[[1]][2],"\n", sep="")
}
if(length(object$data.name) == 2){
if(length(object$data.name[[2]]) == 2){
cat("data: ",object$data.name[[1]][1]," with ",object$data.name[[2]][1],
" and ",object$data.name[[1]][2]," with ",object$data.name[[2]][2],"\n", sep="")
} else {
cat("data: ",object$data.name[[1]][1]," with ",object$data.name[[2]][1],
" and ",object$data.name[[1]][2],"\n", sep="")
}
}
}
if(object$nsamples == 1){
if(length(object$data.name) == 1){
cat("data: ",object$data.name[[1]][1],"\n", sep="")
}
if(length(object$data.name) == 2){
cat("data: ",object$data.name[[1]][1]," with ",object$data.name[[2]][1],"\n", sep="")
}
}
out <- character()
if(!is.null(object$null.value)){
if(length(object$null.value) == 1){
if(!is.null(object$parameter)){
if(object$nsamples == 2){
Nparam <- dim(object$param)[2]
cat("Sample 1 parameters : ")
for(i in 1:Nparam){
out <- c(out,paste(colnames(object$parameter)[i], "=", format(signif(object$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(object$parameter)[i], "=", format(signif(object$parameter[2,i],
max(1, digits - 2)))))
}
} else {
Nparam <- length(object$parameter)
for(i in 1:Nparam){
if(names(object$parameter[i])=="mfn"){
out <- c(out,paste(names(object$parameter[i]), "=", format(object$parameter[i],
scientific=TRUE,digit=5)))
} else {
out <- c(out,paste(names(object$parameter[i]), "=", format(signif(object$parameter[i],
max(1, digits - 2)))))
}
}
}
}
cat(strwrap(paste(out, collapse=", ")), sep="\n")
cat("---------------------------------- Statistics --------------------------------\n")
if(!is.null(object$Tstat)){
cat("Tstat =", format(signif(object$Tstat,
max(1, digits - 2))),"\n")
}
if (!is.null(object$p.value)) {
fp <- format.pval(object$p.value, digits= max(1, digits -
3))
cat("p-value for",names(object$null.value[1]), if (substr(fp, 1, 1) ==
"<") fp else paste("=", fp),"\n")
}
if (!is.null(object$alternative)) {
cat("Alternative hypothesis: ")
alt.char <- switch(object$alternative, two.sided="not equal to",
less="less than", greater="greater than")
cat("true ", names(object$null.value), " is ", alt.char,
" ", object$null.value, "\n", sep="")
}
if (!is.null(object$conf.int)) {
cat(format(100 * attr(object$conf.int, "conf.level")), " percent confidence interval:\n",
paste(format(object$conf.int),collapse=" "),
"\n")
}
if (!is.null(object$estimate)) {
if(object$nsamples == 1){
cat("Sample estimates : \n")
print(object$estimate)
}
if(object$nsamples == 2){
cat("Sample 1 estimates : \n")
print(object$estimate[1,])
cat("Sample 2 estimates : \n")
print(object$estimate[2,])
}
}
} else if(length(object$null.value)==2){
if(!is.null(object$parameter)){
if(object$nsamples == 2){
cat("Sample 1 parameters : ")
Nparam <- dim(object$param)[2]
for(i in 1:Nparam){
out <- c(out,paste(colnames(object$parameter)[i], "=", format(signif(object$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(object$parameter)[i] == "mfn"){
out <- c(out,paste(colnames(object$parameter)[i], "=", format(object$parameter[2,i],
scientific=TRUE,digit=5)))
} else {
out <- c(out,paste(colnames(object$parameter)[i], "=", format(signif(object$parameter[2,i],
max(1, digits - 2)))))
}
}
}
if(object$nsamples == 1){
cat("Sample parameters : ")
Nparam <- length(object$parameter)
for(i in 1:Nparam){
out <- c(out,paste(names(object$parameter[i]), "=", format(signif(object$parameter[i],
max(1, digits - 2)))))
}
}
}
cat(strwrap(paste(out, collapse=", ")), sep="\n")
cat("---------------------------------- Statistics --------------------------------\n")
if(!is.null(object$Tstat)){
cat("Tstat = (",format(signif(object$Tstat[1],
max(1, digits - 2)))," , ",format(signif(object$Tstat[2],
max(1, digits - 2))),")","\n",sep="")
}
if (!is.null(object$p.value)) {
fp1 <- format.pval(object$p.value[1], digits=max(1, digits -
3))
fp2 <- format.pval(object$p.value[2], digits=max(1, digits -
3))
cat("p-value for",names(object$null.value[1]), if (substr(fp1, 1, 1) ==
"<") fp1 else paste("=", fp1),"\np-value for",names(object$null.value[2]),if (substr(fp2, 1, 1) ==
"<") fp2 else paste("=", fp2),"\n")
}
if (!is.null(object$alternative)) {
cat("Alternative hypotheses: ")
alt.char1 <- switch(object$alternative[1], two.sided="not equal to",
less="less than", greater="greater than")
alt.char2 <- switch(object$alternative[2], two.sided="not equal to",
less="less than", greater="greater than")
cat("true ", names(object$null.value[1]), " is ", alt.char1,
" ", object$null.value[1], "\n", sep="")
cat(" ")
cat("true ", names(object$null.value[2]), " is ", alt.char2,
" ", object$null.value[2], "\n", sep="")
}
if (!is.null(object$conf.int)) {
cat(format(100 * attr(object$conf.int, "conf.level")), " percent confidence interval for ",names(object$null.value[1]),": \n",
paste(format(object$conf.int[,1]),collapse=" "),
"\n",
format(100 * attr(object$conf.int, "conf.level")), " percent confidence interval for ",names(object$null.value[2]),": \n",
paste(format(object$conf.int[,2]),collapse=" "),
"\n",sep="")
}
if (!is.null(object$estimate)) {
if(object$nsamples == 1){
cat("Sample estimates : \n")
print(object$estimate[1,])
}
if(object$nsamples == 2){
cat("Sample 1 estimates : \n")
print(object$estimate[1,])
cat("Sample 2 estimates : \n")
print(object$estimate[2,])
}
}
}
cat("\n")
}
}
MutationMLOptimization <- function(mc,mfn,cvfn,model,fitness,death,winsor){
if(max(mc) > winsor) mc[mc > winsor] = winsor
ll <- function(a){
p <- log(dflan(mc,a,fitness,death,model))
-sum(p)
}
# gradient of log-likelihood of the sample
dll <- function(a){
p <- dflan.grad(mc,a,fitness,death,model,dalpha=TRUE,drho=FALSE)
res <- p$dQ_da/p$Q
-sum(res)
}
a.est <- 1
lower = 0.05*a.est
upper = 20*a.est
a.est <- lbfgsb3(prm=a.est,fn=ll,gr=dll,lower = lower,upper=upper)$prm
dldd <- dflan.grad(mc,a.est,fitness,death,model,dalpha=TRUE,drho=FALSE)
I <- sum((dldd$dQ_da)^2/(dldd$Q)^2)
sda <- sqrt(1/I)
list(mutations=a.est,sd.mutations=sda)
}
MutationProbabilityMLOptimization <- function(mc,fn,model,fitness,death,winsor){
if(max(mc) > winsor) mc[mc > winsor] = winsor
mfn <- mean(fn)
cvfn <- sd(fn)/mfn
ll <- function(pm){
p <- mapply(function(x,y){
y <- y/mfn
log(dflan(x,pm*y,fitness,death,model))
},mc,fn)
-sum(p)
}
# gradient of log-likelihood of the sample
dll <- function(pm){
res <- mapply(function(x,y){
y <- y/mfn
p<-dflan.grad(mc,pm*y,fitness,death,model,dalpha=TRUE,drho=FALSE)
p$dQ_da*y/p$Q
},mc,fn)
-sum(res)
}
pm.est <- 1
lower = 0.05*pm.est
upper = 20*pm.est
pm.est <- lbfgsb3(prm=pm.est,fn=ll,gr=dll,lower = lower,upper=upper)$prm/mfn
dldd <- mapply(function(x,y){
dflan.grad(x,pm.est*y,fitness,death,model,dalpha=TRUE,drho=FALSE)
},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)
}
MutationFitnessMLOptimization <- function(mc,mfn,cvfn,model,death,winsor){
if(max(mc) > winsor) mc[mc > winsor] = winsor
ll <- function(param){
a <- param[1]
r <- param[2]
p <- log(dflan(mc,a,r,death,model))
-sum(p)
}
# gradient of log-likelihood of the sample
dll <- function(param){
a = param[1]
r = param[2]
p <- dflan.grad(mc,a,r,death,model,dalpha=TRUE,drho=TRUE)
res <- cbind(p$dQ_da,p$dQ_dr)/p$Q
-apply(res,2,sum)
}
a.est <- 1 ; r.est <- 1
lower = 0.05*c(a.est,r.est)
upper = 20*c(a.est,r.est)
est <- lbfgsb3(prm=c(a.est,r.est),fn=ll,gr=dll,lower = lower,upper=upper)$prm
a.est = est[1] # Update alpha estimate
r.est = est[2] # Update rho estimate
dldd <- dflan.grad(mc,a.est,r.est,death,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)
list(mutations=a.est,fitness=r.est,sd.mutations=sda,sd.fitness=sdr)
}
MutationProbabilityFitnessMLOptimization <- function(mc,fn,model,death,winsor){
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(x,pm*y,r,death,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(mc,pm*y,fitness,death,model,dalpha=TRUE,drho=FALSE)
p$dQ_da*y/p$Q
},mc,fn)
-apply(res,1,sum)
}
pm.est <- 1 ; r.est <- 1
lower = 0.05*c(pm.est,r.est)
upper = 20*c(pm.est,r.est)
est <- lbfgsb3(prm=c(pm.est,r.est),fn=ll,gr=dll,lower = lower,upper=upper)$prm
pm.est = est[1]/mfn # Update alpha estimate
r.est = est[2] # Update rho estimate
dldd <- mapply(function(x,y){
dflan.grad(x,pm.est*y,r.est,death,model,dalpha=TRUE,drho=TRUE)
},mc,fn)
p2 <- (unlist(dldd[1,]))^2
dpa <- unlist(dldd[2,])
dpr <- unlist(dldd[3,])
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)
list(mutprob=a.est,fitness=r.est,sd.mutprob=sda,sd.fitness=sdr)
}
### P0 method
MutationsNumberP0Estimation <- function(mc,death){
# 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)
}
MutationP0Estimation <- function(mc,mfn,cvfn,death){
# 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)
}
MutationFitnessP0Estimation <- function(mc,fn,mfn,cvfn,model,death,winsor){
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
}
output <- list(mutprob=pm,sd.mutprob=sdpm)
} else output <- list(mutations=a,sd.mutations=sda)
if(!is.null(fn)) r <- FitnessP0Optimization(mc,fn,model,pm,death,winsor)
else r <- FitnessP0Optimization(mc,fn,model,a,death,winsor)
c(output,fitness=r$fitness,sd.fitness=r$sd.fitness)
}
FitnessP0Optimization <- function(mc,fn,model,mut,death,winsor){
if(max(mc) > winsor){ mc[which(mc>winsor)] = winsor}
if(is.null(fn)){
ll <- function(r){
p <- log(dflan(mc,mut,r,death,model))
-sum(p)
}
# gradient of log-likelihood of the sample
dll <- function(r){
p <- dflan.grad(mc,mut,r,death,model,dalpha=FALSE,drho=TRUE)
res <- p$dQ_dr/p$Q
-sum(res)
}
} else {
ll <- function(r){
p <- mapply(function(x,y){
log(dflan(x,mut*y,r,death,model))
},mc,fn)
-sum(p)
}
# gradient of log-likelihood of the sample
dll <- function(r){
res <- mapply(function(x,y){
p<-dflan.grad(mc,mut*y,r,death,model,dalpha=FALSE,drho=TRUE)
p$dQ_da*y/p$Q
},mc,fn)
-sum(res)
}
}
r.est <- 1
lower = 0.05*r.est
upper = 20*r.est
r.est <- lbfgsb3(prm=r.est,fn=ll,gr=dll,lower = lower,upper=upper)$prm
if(is.nul(fn)) dldd <- dflan.grad(mc,mut,r.est,death,model,dalpha=FALSE,drho=TRUE)
else dldd <- mapply(function(x,y){
dflan.grad(x,mut*y,r.est,death,model,dalpha=FALSE,drho=FALSE)
},mc,fn)
I <- sum((dldd$dQ_dr)^2/(dldd$Q)^2)
sda <- sqrt(1/I)
list(fitness=r.est,sd.fitness=sdr)
}
## --------------------------------------------------------------------------------------------------------------------------
############################################## 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-Delbrück 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 <- .Call("MutationFitnessGFEstimation",
list(mc=mc,
fn=as.double(fn),
model=as.character(model),
death=as.double(death),
with.prob.fn=as.logical(with.prob.fn),
with.prob.stat=as.logical(with.prob.stat),
mfn=as.double(mfn),
cvfn=as.double(cvfn)
)
)
# Sometime the resolution of fixed point equation does not converge
if(!output$succeeds) warning(paste("Impossible to estimate 'fitness' of",deparse(substitute(mc)),"with 'GF'-method : 'fitness' is set to default value 1 and only",if(with.prob.fn | with.prob.stat){"mutation probability and mutation number are"}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,cvfn,death) # P0 estimator of mutations
# GF method
if(method == "GF") output <- MutationGFEstimation(mc=mc,mfn=mfn,cvfn=cvfn,fitness=fitness,death=death)
}
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)
# )
# )
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) return(Inf)
if (lower.tail & pp <= P[1]) return(0)
if (!lower.tail & pp >= P[1]) return(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]) return(k)
if (!lower.tail & pp >= P2[1]) return(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
return(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
))
output <- flan.mutmodel$dflan(max(m))
output[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])
}
# dflan.da <- 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)
#
# # 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$dflanda(M)
#
# lapply(output,function(l) l[m+1])
# }
#
#
# dflan.dr <- 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)
#
# # 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$dflandr(M)
#
# lapply(output,function(l) l[m+1])
# }
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.