Nothing
FrF2 <- function(nruns=NULL, nfactors=NULL,
factor.names = if(!is.null(nfactors)) {if(nfactors<=50) Letters[1:nfactors]
else paste("F",1:nfactors,sep="")} else NULL,
default.levels = c(-1,1), ncenter=0, center.distribute=NULL,
generators=NULL, design=NULL, resolution=NULL, select.catlg=catlg,
estimable=NULL, clear=TRUE, method="VF2", sort="natural",
ignore.dom=!isTRUE(all.equal(blocks,1)),
useV = TRUE, firsthit = FALSE, res3=FALSE, max.time=60,
perm.start=NULL, perms=NULL, MaxC2=FALSE,
replications=1, repeat.only=FALSE,
randomize=TRUE, seed=NULL, alias.info=2,
blocks=1, block.name="Blocks", block.old=FALSE, force.godolphin=alias.block.2fis,
bbreps=replications, wbreps=1, alias.block.2fis = FALSE,
hard=NULL, check.hard=10, WPs=1, nfac.WP=0, WPfacs=NULL, check.WPs=10, ...){
## Version 1.7: added the LAD method and made it the default for clear designs
## method option allows to change it to VF2
creator <- sys.call()
if (!is.logical(block.old)) stop("block.old must be logical")
if (block.old && ! identical(blocks, 1)){
## revert the call to the old FrF2 version
cc <- as.list(creator)
## remove arguments that did not exist earlier
cc$block.old <- NULL
cc[[1]] <- FrF2old
cc <- as.call(cc)
erg <- eval(cc)
di <- design.info(erg)
di$creator <- creator
di$block.old <- block.old
design.info(erg) <- di
return(erg)
}
catlg.name <- deparse(substitute(select.catlg))
nichtda <- "try-error" %in% class(try(eval(parse(text=paste(catlg.name,"[1]",sep=""))),silent=TRUE))
if (nichtda){
## provide valid catalogue names from FrF2.catlg128 (added for version 1.6-6
catlgs128 <- c("catlg128.8to15","catlg128.26to33",paste("catlg128",16:25,sep="."))
if (catlg.name %in% catlgs128){
if (!requireNamespace("FrF2.catlg128", quietly=TRUE, character.only=TRUE))
stop("Package FrF2.catlg128 is not available")
if (packageVersion("FrF2.catlg128") < numeric_version("1.2")){
if (catlg.name %in% catlgs128[c(1,3:11)])
stop("For this version of package FrF2.catlg128,\n",
"load ", catlg.name, " with the command data(", catlg.name,")\n",
"and then rerun the FrF2 command.\n",
"Alternatively, install the latest version of package FrF2.catlg128.")
else stop("You need to get the latest version of package FrF2.catlg128 for using ", catlg.name)
}
}
else stop(catlg.name, " not available")
}
if (!"catlg" %in% class(select.catlg)) stop("invalid choice for select.catlg")
## check validity of center point options
if (!is.numeric(ncenter)) stop("ncenter must be a number")
if (!length(ncenter)==1) stop("ncenter must be a number")
if (!ncenter==floor(ncenter)) stop("ncenter must be an integer number")
if (is.null(center.distribute)){
if (!randomize) center.distribute <- min(ncenter, 1)
else center.distribute <- min(ncenter, 3)}
if (!is.numeric(center.distribute)) stop("center.distribute must be a number")
if (!center.distribute==floor(center.distribute)) stop("center.distribute must be an integer number")
if (center.distribute > ncenter)
stop("center.distribute can be at most ncenter")
if (randomize & center.distribute==1) warning("running all center point runs together is usually not a good idea.")
block.name <- make.names(block.name) ## make block.name a valid R name
## check that no incompatible options are used together
## used || or && instead of | or & whereever appropriate (July 2019)
if (ncenter>0 && !identical(WPs,1)) stop("center points for split plot designs are not supported")
if (!(is.null(generators) || (identical(WPs,1) || !is.null(WPfacs))))
stop("generators can only be used with split-plot designs, if WPfacs are specified.")
if (!is.null(nruns)) if (ncenter>0) if (center.distribute > nruns + 1)
stop("center.distribute must not be larger than nruns+1")
if (!(is.null(generators) || is.null(design)))
stop("generators and design must not be specified together.")
if (is.null(nruns) & !(is.null(generators)))
stop("If generators is specified, nruns must be given.")
if (!(is.null(generators) || is.null(estimable)))
stop("generators and estimable must not be specified together.")
if (!(identical(blocks,1) || is.null(estimable))){
if (!(is.numeric(blocks) && length(blocks)==1))
stop("estimable can only be combined with automatic blocking.")
if (!clear) message("clear=FALSE will be ignored, ",
"as estimability for blocked designs is only implemented for clear 2fis.")
}
igdom <- ignore.dom ## ignore.dom argument for estimable
if (!(is.null(design) || is.null(estimable))){
## design and estimable together, 12 August 2019
## validity of design was not yet checked
message("estimability is only attempted for the specified design")
igdom <- TRUE ## always ignore dominating entry of one specific design
}
if (!is.null(useV)) {
if (!is.logical(useV)) stop("useV must be logical")
}
if (!is.logical(firsthit)) stop("firsthit must be logical")
### NULL case will be decided when resolution of ingoing design is known
## 1.7 it might be desirable to alleviate this constraint, and it might also be possible!
## 1.8 alleviated this constraint
if (!(identical(WPs,1) || is.null(estimable))) stop("WPs and estimable must not be specified together.")
if (!(is.null(hard) | is.null(estimable))) stop("hard and estimable must not be specified together.")
if (!(identical(blocks,1) || identical(WPs,1))) stop("blocks and WPs must not be specified together.")
if (!(identical(blocks,1) || is.null(hard))) stop("blocks and hard must not be specified together.")
if (!(identical(WPs,1) || is.null(hard))) stop("WPs and hard must not be specified together.")
if (identical(blocks,1) & !identical(wbreps,1)) stop("wbreps must not differ from 1, if blocks = 1.")
if (!(is.null(WPfacs) || identical(WPs,1)) && is.null(design) && is.null(generators))
stop("WPfacs requires explicit definition of a design via design or generators.")
if (identical(nfac.WP,0) && is.null(WPfacs) && !identical(WPs,1))
stop("WPs whole plots require specification of whole plot factors",
"through nfac.WP or WPfacs!")
if ((nfac.WP > 0 || !is.null(WPfacs)) && identical(WPs, 1)) stop("WPs must be specified for creating a split-plot design")
## thus, wbreps = 1 can always be assumed for non-split-plot situations,
## which reduces necessary case distinctions
#if ((!identical(WPs,1)) && is.null(nruns)) stop("WPs only works if nruns is specified.")
### ??? or is that needed for the automatic version only ???
if (!(is.null(resolution) || is.null(estimable))) stop("You can only specify resolution OR estimable.")
if (!(is.null(resolution) || is.null(nruns))) warning("resolution is ignored, if nruns is given.")
## simple checks for individual option entries
if (default.levels[1]==default.levels[2]) stop("Both default levels are identical.")
if (!(is.logical(clear) & is.logical(res3) & is.logical(MaxC2) & is.logical(repeat.only)
& is.logical(randomize) & is.logical(alias.block.2fis) & is.logical(force.godolphin)))
stop("clear, res3, MaxC2, repeat.only, randomize, alias.block.2fis and force.godolphin must be logicals (TRUE or FALSE).")
if (!is.numeric(max.time))
stop("max.time must be a positive maximum run time for searching a design with estimable given and clear=FALSE.")
if (!is.numeric(check.hard)) stop("check.hard must be an integer number.")
if (!is.numeric(check.WPs)) stop("check.WPs must be an integer number.")
check.hard <- floor(check.hard) ## avoid stupid errors
check.WPs <- floor(check.WPs) ## avoid stupid errors
if (!is.numeric(bbreps)) stop("bbreps must be an integer number.")
if (!is.numeric(wbreps)) stop("wbreps must be an integer number.")
if (!is.numeric(replications)) stop("replications must be an integer number.")
if (bbreps > 1 & identical(blocks,1) & !replications > 1)
stop("Use replications, not bbreps, for specifying replications for unblocked designs.")
if (!alias.info %in% c(2,3))
stop("alias.info can be 2 or 3 only.")
if (!(is.numeric(default.levels) | is.character(default.levels)))
stop("default.levels must be a numeric or character vector of length 2")
if (!length(default.levels) ==2)
stop("default.levels must be a numeric or character vector of length 2")
if (!(is.null(hard) | is.numeric(hard)))
stop("hard must be numeric.")
if (!(is.null(resolution) | is.numeric(resolution)))
stop("resolution must be numeric.")
if (is.numeric(resolution)) if(!(resolution == floor(resolution) & resolution>=3))
stop("resolution must be an integer number (at least 3), if specified.")
res.WP <- NULL ## for simple way of checking whether split-plot design later on
## treatment of one specifically-chosen design entry
if (!is.null(design)){
## design is looked for in the catalogue specified in select.catlg
if (!is.character(design)) stop("design must be a character string.")
if (!length(design)==1) stop("design must be one character string.")
if (design %in% names(select.catlg)){
cand <- select.catlg[design]
if (!is.null(nruns)) {if (!nruns==cand[[1]]$nruns)
stop("selected design does not have the desired number of runs.")}
else nruns <- cand[[1]]$nruns
if (!is.null(factor.names)) {if (!length(factor.names)==cand[[1]]$nfac)
stop("selected design does not have the number of factors specified in factor.names.")}
if (!is.null(nfactors)) {if (!nfactors==cand[[1]]$nfac)
stop("selected design does not have the number of factors specified in nfactors.")}
else nfactors <- cand[[1]]$nfac
}
else stop("invalid entry for design")
}
## should occur after special treatment for specific design
if (!is.null(nruns)){
k <- round(log2(nruns))
if (!2^k==nruns) stop("nruns must be a power of 2.")
if (nruns < 4 | nruns > 4096) stop("less than 4 or more than 4096 runs are not covered by function FrF2.")
}
## check factor specifications
if (is.null(factor.names) && is.null(nfactors) && (is.null(nruns) || is.null(generators)) && is.null(estimable))
stop("The number of factors must be specified via nfactors, via factor.names, via estimable, through selecting
one specific catalogued design or via nruns together with generators.")
if (!is.null(factor.names) && !(is.character(factor.names) || is.list(factor.names)) )
stop("factor.names must be a character vector or a list.")
if (is.null(nfactors)) {if (!is.null(factor.names)) nfactors <- length(factor.names)
else if (!is.null(generators)) nfactors <- length(generators)+k
}
if (!is.null(estimable)) {
if (!is.character(sort)) stop("option sort must be a character string")
if (!is.character(method)) stop("option method must be a character string")
if (!sort %in% c("natural","high","low")) stop("invalid choice for option sort")
if (clear && !method %in% c("LAD","VF2")) stop("invalid choice for option method")
estimable <- estimable.check(estimable, nfactors, factor.names)
if (is.null(nfactors)) nfactors <- estimable$nfac
estimable <- estimable$estimable
if (is.null(nruns)) {
## make even
nruns <- nfactors+ncol(estimable)+1 + (nfactors+ncol(estimable)+1)%%2
if (!isTRUE(all.equal(log2(nruns) %% 1,0))) nruns <- 2^(floor(log2(nruns))+1)
k <- round(log2(nruns))
if (k<3) stop("Please specify nruns and/or nfactors. Calculated values are unreasonable.")
}
if (is.null(perm.start)) perm.start <- 1:nfactors
else if (!is.numeric(perm.start))
stop ("perm.start must be NULL or a numeric permutation vector of length nfactors.")
if (!all(sort(perm.start)==1:nfactors))
stop ("perm.start must be NULL or a numeric permutation vector of length nfactors.")
if (!is.null(perms)) {
if (!is.matrix(perms) | !is.numeric(perms)) stop("perms must be a numeric matrix.")
if (!ncol(perms)==nfactors) stop ("matrix perms must have nfactors columns.")
if (any(apply(perms,1,function(obj) any(!sort(obj)==1:nfactors))))
stop("Each row of perms must be a permutation of 1:nfactors.")
}
if (is.null(design)) cand <- select.catlg ## otherwise, cand has already been set
}
## from here on, estimable is a numeric matrix with two rows
## and nfactors is known
if (!nfactors==floor(nfactors))
stop("nfactors must be an integer number.")
if (!is.null(factor.names) && !length(factor.names)==nfactors)
stop("There must be nfactors factor names, if any.")
if (is.null(factor.names))
if(nfactors<=50) factor.names <- Letters[1:nfactors] else factor.names <- paste("F",1:nfactors,sep="")
## check factor level specifications
if (!((is.character(default.levels) | is.numeric(default.levels)) & length(default.levels)==2) )
stop("default.levels must be a vector of 2 levels.")
if (is.list(factor.names)){
if (is.null(names(factor.names))){
if (nfactors<=50) names(factor.names) <- Letters[1:nfactors]
else names(factor.names) <- paste("F", 1:nfactors, sep="")
}
if (any(factor.names=="")) factor.names[which(factor.names=="")] <- list(default.levels)}
else {hilf <- vector("list",nfactors)
names(hilf) <- factor.names
hilf[1:nfactors]<-list(default.levels)
factor.names <- hilf}
## from here on, factor.names is a named list
## make all names valid R names
names(factor.names) <- make.names(names(factor.names), unique=TRUE)
if (ncenter > 0) if(any(is.na(sapply(factor.names,"is.numeric"))))
stop("Center points are implemented for experiments with all factors quantitative only.")
### prepare generators case
genspec <- FALSE ## for later checks, April 2020
if (!is.null(generators)){
genspec <- TRUE
## nruns and k are always given for this situation
generators <- gen.check(k, generators)
g <- nfactors - k
if (!length(generators)== g)
stop("This design in ", nruns, " runs with ", nfactors," factors requires ", g, " generators.")
res <- NA; nclear.2fis<-NA; clear.2fis<-NULL;all.2fis.clear<-NA
if (g<10) wl <- words.all(k, generators,max.length=6)
else if (g<15) wl <- words.all(k, generators,max.length=5)
else if (g<20) wl <- words.all(k, generators,max.length=4)
else if (g>=20) wl <- alias3fi(k, generators, order=2) ## not a word list
WLP <- NULL
### add meaningful clear.2fis July 2019
clear.2fis <- combn(nfactors, 2)
hilf <- rep(TRUE, choose(nfactors, 2))
wl4 <- wl[[2]]
wl4 <- wl4[lengths(wl4)==4]
if (length(wl4) > 0)
for (i in 1:choose(nfactors, 2))
if (any(sapply(wl4, function(obj) all(clear.2fis[,i] %in% obj)))) hilf[i] <- FALSE
clear.2fis <- clear.2fis[,hilf]
nclear.2fis <- ncol(clear.2fis)
all.2fis.clear <- (nclear.2fis==choose(nfactors, 2))
if (g < 20){
WLP <- wl$WLP
## added if for avoiding warning (April 2020)
if (all(WLP==0)) res <- Inf else
res <- min(as.numeric(names(WLP)[which(WLP>0)]))
if (res==Inf) {if (g<10) res="7+"
else if (g<15) res="6+"
else if (g<20) res="5+" }
}
else{
if (!is.list(wl)) res="5+"
else{
if (length(wl$"main")>0) res="3"
else if (length(wl$"fi2")>0) res="4"
else res="5+"}
}
gen <- sapply(generators,function(obj) which(sapply(Yates[1:(nruns-1)],
function(obj2) isTRUE(all.equal(sort(abs(obj)),obj2)))))
gen <- gen*sapply(generators, function(obj) sign(obj[1]))
cand <- list(custom=list(res=res, nfac=nfactors, nruns=nruns,
gen=unlist(gen),
WLP=WLP, nclear.2fis=nclear.2fis, clear.2fis=clear.2fis, all.2fis.clear=all.2fis.clear))
## needs to be list of list, because access later is always via cand[1]
class(cand) <- c("catlg","list")
}
## prepare blocks
## 1.8: if blocks and estimable go together, does this preparation need to accomodate estimable ?
## 1.8: so far, estimable is a two-row matrix, and nfactor and nruns are known (lines 135 to 170)
## 1.8: provisionally, it looks as though no adjustments are needed
## 1.8: estimable can only be non.null for a specified number of blocks
if (!identical(blocks,1)) {
blocks <- block.check(k, blocks, nfactors, factor.names)
if (is.list(blocks)) k.block <- length(blocks)
block.auto=FALSE ## default for block.auto, set to TRUE below, if TRUE
map <- NULL ## initialize, will be filled for use with estimable
}
## blocks is now list of generators or number of blocks
if (!is.list(blocks)){
if (blocks>1){
block.auto=TRUE
if (is.null(nruns))
stop("blocks>1 only works if nruns is specified.")
k.block <- round(log2(blocks))
if (blocks > nruns/2)
stop("There cannot be more blocks than half the run size.")
if (nfactors+blocks-1>=nruns)
stop(paste(nfactors, "factors cannot be accomodated in", nruns, "runs with", blocks, "blocks."))
ntreat <- nfactors
# nfactors <- nfactors + k.block #### omitted for new version, that alone is probably not yet the solution
}
}
### treat hard before WPs, so that it can be handled by split-plot approach
if (!is.null(hard)){
if (is.null(generators)){
## otherwise, cand has already been specified
if (is.null(nruns)){
## resolution requested, k not yet defined
cand <- select.catlg[which(res.catlg(select.catlg)>=resolution & nfac.catlg(select.catlg)==nfactors)]
if (length(cand)==0) {
message("full factorial design needed for achieving requested resolution")
k <- nfactors
nruns <- 2^k
cand <- list(list(gen=numeric(0)))
}
else {
nruns <- min(nruns.catlg(cand))
k <- round(log2(nruns))
cand <- cand[which(nruns.catlg(cand)==nruns)]
}
}
else {
## nruns specified
if (nfactors > k)
cand <- select.catlg[which(nfac.catlg(select.catlg)==nfactors &
nruns.catlg(select.catlg)==nruns)]
else cand <- list(list(gen=numeric(0)))
}
}
if (hard == nfactors) stop("It does not make sense to choose hard equal to nfactors.")
if (hard >= nruns/2)
warning ("Do you really need to declare so many factors as hard-to-change ?")
nfac.WP <- hard
## determine WPs (implying k.WP)
if (hard < nruns/2){
WPs <- NA
## for full factorials, WPs <- 2^hard,
## otherwise achievable WPs is determined using leftadjust
if (length(cand[[1]]$gen) > 0)
for (i in 1:min(length(cand),check.hard)){
leftadjust.out <- leftadjust(k,cand[[i]]$gen, early=hard, show=1)
if (is.na(WPs) | WPs > 2^leftadjust.out$k.early)
WPs <- 2^leftadjust.out$k.early
}
else WPs <- 2^hard
}
if (hard>=nruns/2 | WPs==nruns) {
warning("There are so many hard-to-change factors that no good special design could be found.
Randomization has been switched off.")
randomize <- FALSE
WPs <- 1
## desmat will be the special slow-change matrix
leftadjust.out <- leftadjust(k,cand[[1]]$gen,early=hard,show=1)
generators <- leftadjust.out$gen
## with this generator and the hard-to-change factors in the earliest columns
}
}
## prepare WPs
if (!identical(WPs,1)) {
if (is.null(nruns)) stop("WPs>1 only works if nruns is specified.")
if (WPs > nruns/2) stop("There cannot be more whole plots (WPs) than half the run size.")
k.WP <- round(log2(WPs))
if (!WPs == 2^k.WP) stop("WPs must be a power of 2.")
if (!is.null(WPfacs) & nfac.WP==0){
nfac.WP <- length(WPfacs)
if (nfac.WP < k.WP) stop("WPfacs must specify at least log2(WPs) whole plot factors.")
}
if (nfac.WP==0) stop("If WPs > 1, a positive nfac.WP or WPfacs must also be given.")
if (nfac.WP < k.WP) {
add <- k.WP - nfac.WP
names.add <- rep(list(default.levels),add)
names(names.add) <- paste("WP",(nfac.WP+1):(nfac.WP+add),sep="")
nfactors <- nfactors + add
factor.names <- c(factor.names[1:nfac.WP],names.add,factor.names[-(1:nfac.WP)])
nfac.WP <- k.WP
warning("There are fewer factors than needed for a full factorial whole plot design. ", add,
" dummy splitting factor(s) have been introduced.")
}
if (!is.null(WPfacs)) {
WPfacs <- WP.check(k, WPfacs, nfac.WP, nfactors, factor.names)
## WPfacs is now character vector of the form Fno or single number of whole plots
WPsnum <- as.numeric(chartr("F", " ", WPfacs))
## the factor positions within the factor names list from which the design is generated
WPsorig <- WPsnum
}
else {WPsorig <- WPsnum <- 1:nfac.WP } ## first nfac.WP factors are whole plot factors
## here, the original WPsorig has been documented
## this must not be overwritten later!
}
if (!is.null(nruns)){
## find FrF2 for given number of runs
## or one specific design (because nruns has already been calculated if necessary)
## or estimable given (because nruns has already been calculated if necessary)
if (nfactors<=k && identical(blocks,1) && identical(WPs,1)) {
### full factorial without blocks or WPs finally treated here
### result immediately returned, i.e. function ends here in this case
if (nfactors==k) aus <- fac.design(2, k, factor.names=factor.names,
replications=replications, repeat.only=repeat.only,
randomize=randomize, seed=seed)
else aus <- fac.design(2, nfactors, factor.names=factor.names,
replications=replications*2^(k-nfactors), repeat.only=repeat.only,
randomize=randomize, seed=seed)
aus <- qua.design(aus, quantitative="none", contrasts=rep("contr.FrF2",nfactors))
## add center points, if requested
if (ncenter>0) aus <- add.center(aus, ncenter, distribute=center.distribute)
di <- design.info(aus)
di$creator <- creator
di <- c(di, list(FrF2.version = sessionInfo(package="FrF2")$otherPkgs$FrF2$Version))
design.info(aus) <- di
return(aus)
}
else {
## block or WPs not possible for nfactors < k
if (nfactors < k) stop("A full factorial for nfactors factors requires fewer than nruns runs.
Please reduce the number of runs and introduce replications instead.")
## artificial generators and cand for full factorial with blocks or WPs
full <- FALSE
if (nfactors == k) {
full <- TRUE
genspec <- TRUE ## base.design entry of design.info handled in generators section
generators <- as.list(numeric(0))
cand <- list(custom=list(res=Inf, nfac=nfactors, nruns=nruns,
gen=numeric(0),
WLP=c(0,0,0,0), nclear.2fis=choose(k,2),
clear.2fis=combn(k,2), all.2fis.clear="all"))
## needs to be list of list, because access later is always via cand[1]
class(cand) <- c("catlg","list")
}
### fractional factorial
if (nfactors > nruns - 1)
stop("You can accomodate at most ", nruns-1,
" factors in a FrF2 design with ", nruns, " runs." )
g <- nfactors - k ## number of generators needed
if (!is.null(estimable)) {
## determine design that satisfies estimability requests
desmat <- estimable(estimable, nfactors, nruns,
clear=clear, res3=res3, max.time=max.time, select.catlg=cand,
method=method,sort=sort,
perm.start=perm.start, perms=perms, order=alias.info,
ignore.dom=igdom) ## added ignore.dom, August 2019
map <- desmat$map ## for use in blocking, if needed (July 2019)
cand <- cand[names(map)] ## for use in blocking, if needed (July 2019)
design.info <- list(type="FrF2.estimable",
nruns=nruns, nfactors=nfactors, factor.names=factor.names,
catlg.name = catlg.name,
map=desmat$map, aliased=desmat$aliased, clear=clear, res3=res3,
FrF2.version = sessionInfo(package="FrF2")$otherPkgs$FrF2$Version)
desmat <- desmat$design
desmat <- as.matrix(sapply(desmat,function(obj) as.numeric(as.character(obj))))
rownames(desmat) <- 1:nrow(desmat)
}
else if (is.null(generators) && is.null(design))
cand <- select.catlg[nruns.catlg(select.catlg)==nruns &
nfac.catlg(select.catlg)==nfactors]
## candidate designs for further steps
## resolution not here, because ignored for given nruns
## treating blocked designs
## 1.7 here is where the main changes are needed for allowing to block
## 1.7 designs with estimable 2fis;
## 1.7 probably restrict choose(nruns - 1 - nfactors - length(estimable), k.block)
## 1.7 also generally probably choose(nruns - 1 - nfactors - ncol2fis, k.block)
## 1.7 if alias.block.2fis = FALSE; but do I get ncol2fis?
block.gen <- NULL ## for later checks
if (!is.list(blocks)){
if (blocks > 1) {
### small case, without estimability requirements
if ((g==0 || choose(nruns - 1 - nfactors, k.block) < 100000) &&
is.null(estimable) && !force.godolphin ){
for (i in 1:length(cand)){
### loop through possible generator designs from best to worse overall
### break stops the loop as soon as design has been found
if (g==0) {blockpick.out <- try(blockpick(k, gen=0,
k.block=k.block, show=1, alias.block.2fis = alias.block.2fis),TRUE)
#print(blockpick.out) ## correct
}
else {
if (is.null(generators))
blockpick.out <- try(blockpick(k, design=names(cand[i]),
k.block=k.block, show=1, alias.block.2fis = alias.block.2fis),TRUE)
else blockpick.out <- try(blockpick(k, gen=cand[[i]]$gen,
k.block=k.block, show=1, alias.block.2fis = alias.block.2fis),TRUE)
}
if (!"try-error" %in% class(blockpick.out)) {
blocks <- blockpick.out$blockcols ## column numbers in Yates matrix
block.gen <- unlist(c(blocks)) ## for design.info; ## cannot be a list
cand <- cand[i]
cand[[1]]$gen <- c(cand[[1]]$gen, block.gen)
blocks <- nfactors + (1:k.block) ## now in terms of factors
#### nfactors changed, will be reduced again later
nfactors <- nfactors + k.block
g <- g + k.block
### adjust factor.names
hilf <- factor.names
factor.names <- vector("list", nfactors)
factor.names[-blocks] <- hilf
factor.names[blocks] <- list(default.levels)
names(factor.names) <- c(names(hilf),paste("b",1:k.block,sep=""))
blocks <- as.list(blocks) ### rest is treated with the manual routine
break
}
}## else treats big case
}
else{## blockpick.big up to version 1.7.x
## since 1.8: Godolphin approach
## if estimable, cand contains a single design
## that has been preselected with the estimable function
## !!! and map has to be observed !!! April 2020
for (i in 1:length(cand)){
if (is.null(useV)) useV <- cand[[1]]$res > 4 && !is.null(estimable)
if (useV)
X <- colpick(cand[i], k - k.block, estimable=estimable, quiet=TRUE,
method=method, sort=sort,
select.catlg = cand[i], res3=res3, firsthit=firsthit)
else
X <- colpickIV(cand[i], k - k.block, estimable=estimable, quiet=TRUE,
method=method, sort=sort,
select.catlg = cand[i], res3=res3, firsthit=firsthit)
if (!is.null(X)) {
## found a successful block structure
## in cand[i]
cand <- cand[i]
## all possible generating vectors (character version with letters)
block.gen <- blockgencreate(X$X, p=g)
## Yates column numbers
block.gen <- sapply(block.gen, function(obj)
which(names(Yates) %in% obj))
if (any(block.gen %in% cand[[1]]$gen))
warning("block generator coincides with main effect")
cand[[1]]$gen <- c(cand[[1]]$gen, block.gen)
blocks <- nfactors + 1:k.block ## column numbers for blocks
#### nfactors changed, will be reduced again later
nfactors <- nfactors + k.block
cand[[1]]$nfactors <- nfactors
g <- g + k.block
### adjust factor.names
if (!is.null(estimable)) map <- X$map
hilf <- factor.names # [map]
factor.names <- vector("list", nfactors)
factor.names[-blocks] <- hilf
factor.names[blocks] <- list(default.levels)
names(factor.names) <- c(names(hilf),
paste("b",1:k.block, sep=""))
blocks <- as.list(blocks)
### rest is treated with the manual routine
## for a list of added factor columns
break
}
}
} ## end else (for big case)
if (!is.list(blocks)) {
stopmsg <- "no adequate blocked design found"
if (nruns >= 128 && !full) stopmsg <- c(stopmsg,
" in catalogue ", deparse(substitute(select.catlg)))
if (!alias.block.2fis)
stopmsg <- c(stopmsg, " with 2fis unconfounded with blocks")
if (!is.null(design))
stopmsg <- c(stopmsg, paste(" in design", design))
else {
if (!is.null(estimable) && !full){
stopmsg <- c(stopmsg, paste(" in design", names(cand)))
}
if (!is.null(estimable) && !full){
if (ignore.dom)
stopmsg <- c(stopmsg, " which is the first suitable element of select.catlg")
else
stopmsg <- c(stopmsg, " which is the first suitable dominating element of select.catlg")
if (!useV && !nfactors==log2(nruns))
stopmsg <- c(stopmsg,
" without trying to reshuffle map from unblocked fraction",
" (useV=TRUE might be worth a try)")
}
}
stop(stopmsg)
}
}
}
if (is.list(blocks)) {
# can be a pre-treated automatic situation or a manual specification
hilf.gen <- c(2^(0:(k-1)), cand[[1]]$gen) ### cand[[1]] exists
## obtain Yates column numbers for block generators
hilf.block.gen <- sapply(blocks, function(obj)
as.intBase(paste(rowSums(do.call(cbind,
lapply(obj, function(obj2)
digitsBase(hilf.gen[obj2],2,k))))%%2, collapse=""))
)
## hilf.block.gen holds Yates matrix column numbers
## number of original factors that are manually declared block factors
k.block.add <- length(intersect(hilf.block.gen, hilf.gen))
if (is.null(block.gen)) {
## manual allocation
ntreat <- nfactors - k.block.add
block.gen <- hilf.block.gen
## hilf.gen still contains generators for block factors
## these must be kept for the automatic case
}
## c makes matrix into vector (list remains list)
## blockfull works with any of blocks or block.gen or hilf.block.gen
bf <- blockfull(blocks, k, hilf.gen) ### obtain all block contrasts
### as Yates column numbers
### check that manual choices for block entries contain independent entries only
if (k.block > 1) {if (length(unique(bf)) < 2^k.block - 1)
stop("specified blocks is invalid (dependencies)")}
## was done with the code below before July 26 2019
#{hilf <- hilf.block.gen
#for (i in 2:k.block){
# sel <- combn(k.block,i)
# for (j in 1:ncol(sel)){
# neu <- as.intBase(paste(rowSums(do.call(cbind,
# lapply(sel[,j], function(obj) digitsBase(hilf.block.gen[obj],2,k))))%%2,
# collapse=""))
# if (neu %in% hilf) stop("specified blocks is invalid (dependencies)")
# else hilf <- c(hilf, neu)
# }
# }
#rm(hilf)
#}
### check for implied confounding of main effects (26 July 2019)
if (length(intersect(bf, hilf.gen)) > k.block.add){
if (alias.block.2fis && length(bf) > 4)
warning(paste("Main effects of factors",
paste(names(factor.names)[hilf.gen %in% bf], collapse=", "),
"are confounded with blocks.",
"The design is a split-plot design",
"and has to be analyzed as such",
"(only recommended in case of many blocks).",
"Preferrably, construct it with arguments WPs and WPfacs.",
"You may also want to try using function FF_from_X",
"for obtaining a better block structure."))
else stop("main effects confounded with blocks")
}
### prepare alias information
### remove extra columns for blocks from hilf.gen
hilf.gen <- setdiff(hilf.gen, block.gen)
sel <- combn(ntreat, 2)
nam2fis <- sapply(1:ncol(sel),
function(obj) ifelse(ntreat<=50, paste0(Letters[sel[,obj]], collapse=":"),
paste0("F",sel[,obj], collapse=":")))
twoficols <- sapply(1:ncol(sel),
function(obj)
as.intBase(paste(rowSums(do.call(cbind,
lapply(sel[,obj], function(obj2)
digitsBase(hilf.gen[obj2],2,k))))%%2, collapse=""))
)
names(twoficols) <- nam2fis
## check for implied confounding with 2fis, if forbidden (July 26 2019)
if (!alias.block.2fis)
if (length(intersect(bf, twoficols)) > 0){
if (force.godolphin) stop("blocks aliased with 2-factor interactions, ",
"although alias.block.2fis=FALSE; ",
"force.godolphin=TRUE does not attempt ",
"to avoid confounding of non-clear 2fis")
else
stop("blocks aliased with 2-factor interactions, ", "although alias.block.2fis=FALSE")
}
if (alias.info == 3){
sel <- combn(ntreat, 3)
nam3fis <- sapply(1:ncol(sel),
function(obj) ifelse(ntreat<=50, paste0(Letters[sel[,obj]], collapse=":"),
paste0("F",sel[,obj], collapse=":")))
threeficols <- sapply(1:ncol(sel),
function(obj)
as.intBase(paste(rowSums(do.call(cbind,
lapply(sel[,obj], function(obj2)
digitsBase(hilf.gen[obj2],2,k))))%%2, collapse=""))
)
names(threeficols) <- nam3fis
}
if (is.null(generators)) generators <- gen.check(k, hilf.gen[-(1:k)]) ## April 4 2020; extract of Yates (list)
} ## end of is.list(blocks) case
## automatic treatment of split-plot designs
if (WPs > 1){
WP.auto <- FALSE
map <- 1:k
orignew <- WPsorig ## orignew will be changed according to map later
## for cases without WPfacs
## this is for orig.fac.order element of design.info,
## not for re-arranging columns in design
if (is.null(WPfacs)){
WP.auto <- TRUE
## max.res.5 is the max number of factors for resolution 5,
## if k (or k.WP is of size ...
max.res.5 <- c(1,2,3, 5, 6, 8, 11, 17)
for (i in 1:length(cand)){
## prevent wasting search time on impossible setups
if (is.null(generators)){
if (cand[[i]]$res>=5 & nfac.WP > max.res.5[k.WP]) next
if (cand[[i]]$res>=4 & nfac.WP > WPs/2) next
}
if (nfac.WP > WPs/2 || nfac.WP <= k.WP)
splitpick.out <- try(splitpick(k, cand[[i]]$gen, k.WP=k.WP, nfac.WP=nfac.WP, show=1),TRUE)
else splitpick.out <- try(splitpick(k, cand[[i]]$gen, k.WP=k.WP, nfac.WP=nfac.WP,
show=check.WPs),TRUE)
if (!"try-error" %in% class(splitpick.out)) {
WPfacs <- 1:k.WP
if (nfac.WP > k.WP) WPfacs <- c(WPfacs, (k + 1):(k+nfac.WP-k.WP))
cand <- cand[i]
cand[[1]]$gen <- splitpick.out$gen[1,]
res.WP <- splitpick.out$res.WP[1]
map <- splitpick.out$perms[1,]
break
}
}
if (is.null(res.WP)){
# if (nruns >= 2^nfactors) stop("currently, splitplot designs for full factorials are not covered.")
if (nruns >= 2^nfactors) {
res.WP <- Inf
WP.auto <- TRUE
WPfacs <- 1:k.WP
if (!k.WP == nfac.WP) stop(nfac.WP, " whole plot factors cannot be accomodated in ", (2^k.WP),
" whole plots for a full factorial. Please request smaller design with replication instead.")
cand <- list(list(gen=numeric(0))) ## in order to be treatable below
}
else stop("no adequate splitplot design found")
}
# WPsorig <- WPsnum <- WPfacs ## this was a mistake, leading to other than the first nfac.WP factors being WP factors
orignew <- WPsnum <- WPfacs
WPfacs <- paste("F",WPfacs,sep="") ## treat with manual below
}
}
## next closing brace for !(nfactors<=k & identical(blocks,1) & identical(WPs,1))
}
### next closing brace for !is.null(nruns)
}
else {
## nruns not given and not already assigned for estimable
## find smallest FrF2 that fulfills the requirements regarding resolution/estimability
if (is.null(resolution) && is.null(estimable))
stop("At least one of nruns or resolution or estimable must be given.")
if (!is.null(resolution)){
cand <- select.catlg[which(res.catlg(select.catlg)>=resolution &
nfac.catlg(select.catlg)==nfactors)]
if (length(cand)==0) {
message("full factorial design needed")
aus <- fac.design(2, nfactors, factor.names=factor.names,
replications=replications, repeat.only=repeat.only,
randomize=randomize, seed=seed)
for (i in 1:nfactors)
if (is.factor(aus[[i]])) contrasts(aus[[i]]) <- contr.FrF2(2)
## add center points, if requested
if (ncenter>0) aus <- add.center(aus, ncenter, distribute=center.distribute)
return(aus)
}
}
else{ cand <- select.catlg[which(nfac.catlg(select.catlg)==nfactors)]
## no prior restriction by resolution
if (length(cand)==0)
stop("No design listed in catalogue ", deparse(substitute(select.catlg)),
" fulfills all requirements.")
}
}
## standard FrF2 situations
## maximize clear 2fis among maximum resolution designs (res3=FALSE)
## or among all designs (res3=TRUE)
## changed 28 01 2011 from always maximum resolution
if (MaxC2 && is.null(estimable) && is.null(generators) ) {
if (!res3)
cand <- cand[which.max(sapply(cand[which(sapply(cand,
function(obj) obj$res)==max(sapply(cand, function(obj) obj$res)))],
function(obj) obj$nclear.2fis))]
else
cand <- cand[which.max(sapply(cand,
function(obj) obj$nclear.2fis))]
}
### creation of actual design
if (is.null(nruns)) {nruns <- cand[[1]]$nruns
k <- round(log2(nruns))
g <- nfactors - k}
if (is.null(estimable) || is.list(blocks)){
### that is, blocks with or without estimable,
### and anything else without estimable (e.g. WP)
### for estimable with blocks, map has already been processed
destxt <- "expand.grid(c(-1,1)"
for (i in 2:k) destxt <- paste(destxt,",c(-1,1)",sep="")
destxt <- paste("as.matrix(",destxt,"))",sep="")
desmat <- eval(parse(text=destxt))
if (is.character(WPfacs) | is.list(blocks)) {
desmat <- desmat[,k:1] ## slow first rather than fast first
##rownames(desmat) <- slowfast(k) ## 17 Feb 2013; this would make the
## run numbers refer to the Yates matrix row order with A changing fastest
## but would also change row order of the resulting design
## therefore not done;
}
if (!is.null(hard)) {
desmat <- rep(c(-1,1),each=nruns/2)
for (i in 2:k) desmat <- cbind(desmat,rep(c(1,-1,-1,1),times=(2^i)/4,each=nruns/(2^i)))
}
if (g>0)
for (i in 1:g)
desmat <- cbind(desmat, sign(cand[[1]]$gen[i][1])*apply(desmat[,unlist(Yates[abs(cand[[1]]$gen[i])])],1,prod))
if (WPs > 1) {
if (!WP.auto) {
hilf <- apply(desmat[,WPsorig,drop=FALSE],1,paste,collapse="")
if (!length(table(hilf))==WPs)
stop("The specified design creates ",
length(table(hilf)), " and not ", WPs, " whole plots.")
for (j in setdiff(1:nfactors,WPsorig))
if (!length(table(paste(hilf,desmat[,j],sep="")))>WPs)
stop("Factor ", names(factor.names)[j], " is also a whole plot factor.")
## added 19 Feb 2013
if (nfac.WP<3) res.WP <- Inf
else res.WP <- GR((3-desmat[,WPsorig,drop=FALSE])%/%2)$GR%/%1
}
}
## slow changing order, if required
# if ((!is.character(WPfacs)) & !is.null(hard) )
# desmat <- desmat[,order(c(2^(0:(k-1)),abs(cand[[1]]$gen)))]
## make sure matrix desmat has rownames (14 Feb 2013)
if (is.null(rownames(desmat))) rownames(desmat) <- 1:nruns
if (is.list(blocks)) {
## manually blocked designs and continuation of automatically blocked designs
## including the estimable case (July 2019)
if (is.null(block.gen)) block.gen <- blocks
hilf <- blocks
for (i in 1:k.block) hilf[[i]] <- apply(desmat[,hilf[[i]],drop=FALSE],1,prod)
Blocks <- factor(as.numeric(factor(apply(matrix(as.character(unlist(hilf)),
ncol=k.block), 1, paste, collapse=""))))
hilf <- order(Blocks, as.numeric(rownames(desmat))) ## rownames(desmat) added 17 Feb 2013
desmat <- desmat[hilf,]
Blocks <- Blocks[hilf]
contrasts(Blocks) <- contr.FrF2(levels(Blocks))
nblocks <- 2^length(blocks)
blocksize <- nruns / nblocks
block.no <- paste(Blocks,rep(1:blocksize,nblocks),sep=".")
}
if (is.character(WPfacs)) {
## make WP factor columns the first ones
## make factor.names match this order
#### for automatic selection the first WPs factors are WP factors !!!
#if (nfac.WP > k.WP){
## are WPsnum is the current factor numbering
## WPsorig is the original numbering before column permutations
desmat <- desmat[,c(WPsnum,setdiff(1:nfactors,WPsnum))]
factor.names <- factor.names[c(WPsorig,setdiff(1:nfactors,WPsorig))]
plotsize <- round(nruns/WPs)
if (is.null(hard)){
hilf <- ord(cbind(desmat[,1:nfac.WP],as.numeric(rownames(desmat)))) ## as.numeric(rownames) added 17 Feb 2013
desmat <- desmat[hilf,]
}
wp.no <- paste(rep(1:WPs,each=plotsize),rep(1:plotsize,WPs),sep=".")
}
}
## until Feb 14 2013, rownames(desmat) were defined here,
## which did not make sense, especially since they should be available
## in already resorted form above for block and wp
## 14 Feb 2013: auskommentiert
## rownames(desmat) <- 1:nruns
## handle randomization and replication
if (randomize & !is.null(seed)) set.seed(seed)
if (!(is.list(blocks) || WPs > 1)){
## simple randomization situations
rand.ord <- rep(1:nruns,replications)
if (replications > 1 & repeat.only) rand.ord <- rep(1:nruns,each=replications)
if (randomize & !repeat.only) for (i in 1:replications)
rand.ord[((i-1)*nruns+1):(i*nruns)] <- sample(nruns)
if (randomize & repeat.only) rand.ord <- rep(sample(1:nruns), each=replications)
}
else {
if (is.list(blocks)){
#### implement randomization and replication for blocks
## bbreps=replications, wbreps=1
## if ((!repeat.only) & !randomize)
rand.ord <- rep(1:nruns, bbreps * wbreps)
if ((!repeat.only) & !randomize)
for (i in 0:(nblocks-1))
for (j in 1:wbreps)
rand.ord[(i*blocksize*wbreps+(j-1)*blocksize+1):((i+1)*blocksize*wbreps+j*blocksize)] <-
(i*blocksize+1):((i+1)*blocksize)
rand.ord <- rep(rand.ord[1:(nruns*wbreps)],bbreps)
if (repeat.only & !randomize)
for (j in 1:wbreps)
rand.ord[(i*blocksize*wbreps + (j-1)*blocksize + 1) :
(i*blocksize*wbreps + j*blocksize)] <-
sample((i%%nblocks*blocksize+1):(i%%nblocks*blocksize+blocksize))
if (wbreps > 1 & repeat.only) rand.ord <- rep(1:nruns,bbreps, each=wbreps)
if ((!repeat.only) & randomize)
for (i in 0:(nblocks*bbreps-1))
for (j in 1:wbreps)
rand.ord[(i*blocksize*wbreps + (j-1)*blocksize + 1) :
(i*blocksize*wbreps + j*blocksize)] <-
sample((i%%nblocks*blocksize+1):(i%%nblocks*blocksize+blocksize))
if (repeat.only & randomize)
for (i in 0:(nblocks*bbreps-1))
rand.ord[(i*blocksize*wbreps + 1) :
((i+1)*blocksize*wbreps)] <- rep(sample((((i%%nblocks)*blocksize)+1):
((i%%nblocks+1)*blocksize)),each=wbreps)
}
else {
#### implement randomization and replication for split-plots
#### standard approach; replications replicate complete plots
#### repeat.only generate repeated measurements within plots
rand.ord <- rep(1:nruns,replications)
if (replications > 1 & repeat.only)
rand.ord <- rep(1:nruns,each=replications)
if ((!repeat.only) & randomize){
## whole plots are replicated
## might be more wise to use larger design
## randomization on two levels
## first: randomization within each whole plot
for (i in 1:(WPs*replications))
rand.ord[((i-1)*plotsize+1):(i*plotsize)] <-
sample(rand.ord[((i-1)*plotsize+1):(i*plotsize)])
## second: randomization of whole plots (in blocks per replication)
for (i in 1:replications){
## only if not hard to change
if (is.null(hard)){
WPsamp <- sample(WPs)
WPsamp <- (rep(WPsamp,each=plotsize)-1)*plotsize + rep(1:plotsize,WPs)
rand.ord[((i-1)*plotsize*WPs+1):(i*plotsize*WPs)] <-
rand.ord[(i-1)*plotsize*WPs + WPsamp]
}
}
}
if (repeat.only & randomize){
## repeated measurements within whole plots
## repetition of complete whole plots is not covered,
## as I don't think that this makes sense
## first: randomization within each whole plot
for (i in 1:WPs)
rand.ord[((i-1)*plotsize*replications+1):(i*plotsize*replications)] <-
rand.ord[(i-1)*plotsize*replications +
rep(replications*(sample(plotsize)-1),each=replications) +
rep(1:2,each=plotsize)]
## second: randomization of whole plots
## only if not hard to change
if (is.null(hard)){
WPsamp <- sample(WPs)
WPsamp <- (rep(WPsamp,each=plotsize*replications)-1)*plotsize*replications +
rep(1:(plotsize*replications),WPs)
rand.ord <- rand.ord[WPsamp]
}
}
}
}
orig.no <- rownames(desmat)
orig.no <- orig.no[rand.ord]
## row added 27 01 2011 (for proper ordering of factor levels)
orig.no.levord <- sort(as.numeric(orig.no),index=TRUE)$ix
rownames(desmat) <- NULL
desmat <- desmat[rand.ord,]
if (is.list(blocks)) {
Blocks <- Blocks[rand.ord]
block.no <- block.no[rand.ord]
}
if (WPs > 1) wp.no <- wp.no[rand.ord]
colnames(desmat) <- names(factor.names)
## adapt original number to replications
if (is.list(blocks)) orig.no <- paste(orig.no,block.no,sep=".")
if (WPs > 1) orig.no <- paste(orig.no,wp.no,sep=".")
orig.no.rp <- orig.no
if (bbreps * wbreps > 1){
if (bbreps > 1) {
## !repeat.only covers all blocked cases and the repeat.only standard cases
## since bbreps stands in for replications
if (repeat.only & !is.list(blocks))
orig.no.rp <- paste(orig.no.rp, rep(1:bbreps,nruns),sep=".")
else
orig.no.rp <- paste(orig.no.rp, rep(1:bbreps,each=nruns*wbreps),sep=".")
}
if (wbreps > 1){
## blocked with within block replications
if (repeat.only)
orig.no.rp <- paste(orig.no.rp, rep(1:wbreps,nruns*bbreps),sep=".")
else orig.no.rp <- paste(orig.no.rp, rep(1:wbreps,each=blocksize,nblocks*bbreps),sep=".")
}
}
desdf <- data.frame(desmat)
quant <- rep(FALSE,nfactors)
for (i in 1:nfactors) {
## make all variables into factors
desdf[,i] <- des.recode(desdf[,i],"-1=factor.names[[i]][1];1=factor.names[[i]][2]")
quant[i] <- is.numeric(desdf[,i])
desdf[,i] <- factor(desdf[,i],levels=factor.names[[i]])
contrasts(desdf[,i]) <- contr.FrF2(2)
}
if (is.list(blocks)) {
desdf <- cbind(Blocks, desdf, stringsAsFactors=TRUE)
## make sure that experimental factors are assigned to those
## columns that reflect their estimability needs
## blocking makes approach analogous to function map2design more complicated
## reassign levels for Blocks to concatenation of manual build factors
## if they are built from only single factors
## !!! it is important to maintain the original order of numbered blocks factor
## for more than four blocks (because e.g. grouping 1,2,3,7 vs. 4,5,6,8 not
## orthogonal to everything else !
hilf <- blocks
if (all(sapply(hilf,length)==1) && !block.auto) {
hilf <- as.numeric(hilf) + 1
levels(desdf$Blocks) <- unique(apply(desdf[,hilf,drop=FALSE],1,paste,collapse=""))
}
colnames(desdf)[1] <- block.name
## delete any single block generator columns
hilf <- blocks
hilf <- as.numeric(hilf[which(sapply(hilf,length)==1)])
if (length(hilf)>0) {
desdf <- desdf[,-(hilf+1)]
desmat <- desmat[,-hilf]
factor.names <- factor.names[-hilf]
}
if (!is.null(estimable)) {
## April 2020
#factor.names <- factor.names[map]
factor.names <- factor.names[invperm(map)]
names(desdf) <- c(block.name, names(factor.names))
}
## prepend block model matrix to desmat (not only generators but all block main effects)
desmat <- cbind(model.matrix(~desdf[,1])[,-1],desmat)
colnames(desmat)[1:(2^k.block-1)] <- paste(block.name,1:(2^k.block-1),sep="")
## new alias approach, July 26 2019
MEcols <- hilf.gen
## remove single factor block generators ? via -hilf
## but what to do with twoficols in that case ?
## also remove related twoficols ?
if (ntreat<=50) names(MEcols) <- Letters[1:ntreat] else names(MEcols) <- paste0("F",1:ntreat)
effs <- c(MEcols, twoficols)
if (alias.info==3) effs <- c(effs, threeficols)
aliased.with.blocks <- names(effs[effs %in% bf])
effs <- effs[!effs %in% bf] ## only those effects that are not aliased with blocks
aliased <- split(names(effs), effs) ### list of effects on the same non-block Yates matrix column
aliased <- aliased[lengths(aliased) > 1] ## columns with more than one effect
### code before July 26 2019: this part was really slow for large designs or many blocks
# if (alias.info==3)
# hilf <- aliases(lm((1:nrow(desmat))~(.)^3,data=data.frame(desmat)))
# else
# hilf <- aliases(lm((1:nrow(desmat))~(.)^2,data=data.frame(desmat)))
## check against blockpick.out here, if possible?
## blockpick.out$alias.2fis.block
## delete all aliases of Block factors themselves
## with or without "-"
## as these are not interesting
# if (length(hilf$aliases) > 0)
# for (i in 1:length(hilf$aliases)) {
# txt <- hilf$aliases[[i]]
# if (length(grep(paste("^-?",block.name,sep=""),txt)) > 0)
# txt <- txt[-grep(paste("^-?",block.name,sep=""),txt)]
# if (length(txt)==length(grep("^-",txt))) txt <- sub("-","",txt)
# hilf$aliases[[i]] <- txt
# }
# ## determine treatment effects that are aliased with blocks
# aliased.with.blocks <- hilf$aliases[1:(2^k.block-1)]
# aliased.with.blocks <- unlist(aliased.with.blocks)
# ## interim result for updating alias information
if (nfactors<=50) leg <- paste(Letters[1:ntreat],names(factor.names),sep="=")
else leg <- paste(paste("F",1:ntreat,sep=""),names(factor.names),sep="=")
if (length(aliased.with.blocks)==0) aliased.with.blocks <- "none"
else {
## recalc.alias.blocked destroys the structure,
## if factor.names deviates from factor letters
aliased.with.blocks <- recalc.alias.block.new(aliased.with.blocks, leg)
#aliased.with.blocks <- recalc.alias.block(aliased.with.blocks, leg)
aliased.with.blocks <- aliased.with.blocks[ord(data.frame(nchar(aliased.with.blocks),aliased.with.blocks))]
if (nfactors <= 50) aliased.with.blocks <- gsub(":","",aliased.with.blocks)
}
## determine treatment effects that are aliased with each other
# aliased <- hilf$aliases[-(1:(2^k.block-1))]
# aliased <- aliased[which(sapply(aliased,length)>1)]
## update: same format like aliased element of unblocked designs
## July 2019: adapt to new blocking strategy
# if (length(aliased)>0) aliased <- struc.aliased.new(recalc.alias.block(aliased, leg),
if (length(aliased) > 0) aliased <- struc.aliased.new(struc=recalc.alias.block.new(aliased, leg),
nk=nfactors, order=alias.info)
## prepare design info for blocked designs
ntreat <- ncol(desdf) - 1
if (block.auto) factor.names <- factor.names[1:ntreat]
# if (block.auto) factor.names <- factor.names[setdiff(1:nfactors,blocks)]
## up to version 0.96-1 nfactors was ntreat+1
# design.info <- list(type="FrF2.blocked", block.name=block.name,
# nruns=nruns, nfactors=ntreat+1, nblocks=nblocks, blocksize=blocksize,
# ntreat=ntreat,factor.names=factor.names,
# aliased.with.blocks=aliased.with.blocks, aliased=aliased,
# bbreps=bbreps, wbreps=wbreps)
## create new type FrF2.blocked.estimable ??? decided against this
design.info <- list(type="FrF2.blocked", block.name=block.name,
nruns=nruns, nfactors=ntreat, nblocks=nblocks, block.gen=block.gen, blocksize=blocksize,
ntreat=ntreat,factor.names=factor.names,
aliased.with.blocks=aliased.with.blocks, aliased=aliased,
bbreps=bbreps, wbreps=wbreps,
FrF2.version = sessionInfo(package="FrF2")$otherPkgs$FrF2$Version)
if (!is.null(generators) && genspec) {## April 2020 added genspec
if (g>0)
design.info <- c(design.info,
list(base.design=paste("generator columns:", paste(setdiff(cand[[1]]$gen, block.gen), collapse=", "))))
else
design.info <- c(design.info,
list(base.design="full factorial"))
}
else design.info <- c(design.info, list(catlg.name = catlg.name, base.design=names(cand[1])))
if (!is.null(estimable)) design.info <- c(design.info, list(map=map))
if (bbreps>1) {
hilflev <- paste(rep(levels(desdf[,1]), each=bbreps), rep(1:bbreps, nblocks), sep=".")
desdf[,1] <- factor(paste(desdf[,1], rep(1:bbreps, each=nruns*wbreps),sep="."), levels=hilflev)
}
## make block names reflect the between block replication
} ## end of blocked designs
if (WPs > 1){
## output for split-plot designs
if (alias.info==3)
aliased <- aliases(lm((1:nrow(desmat))~(.)^3,data=data.frame(desmat)))$aliases
else
aliased <- aliases(lm((1:nrow(desmat))~(.)^2,data=data.frame(desmat)))$aliases
aliased <- aliased[which(sapply(aliased,length)>1)]
## update: same format with aliased entry of other FrF2 designs
if (length(aliased) > 0){
if (nfactors<=50) leg <- paste(Letters[1:nfactors],names(factor.names),sep="=")
else leg <- paste(paste("F",1:nfactors,sep=""),names(factor.names),sep="=")
aliased <- struc.aliased(recalc.alias.block(aliased, leg), nfactors, alias.info)
}
design.info <- list(type="FrF2.splitplot",
nruns=nruns, nfactors=nfactors, nfac.WP=nfac.WP, nfac.SP=nfactors-nfac.WP,
factor.names=factor.names,
nWPs=WPs, plotsize=nruns/WPs,
res.WP=res.WP, aliased=aliased, FrF2.version = sessionInfo(package="FrF2")$otherPkgs$FrF2$Version)
## below: changed entry in base.design to original generators, combined with map
## instead of cand[[1]]$gen from before
## bug fix July 2019:
## provide the columns for character generators
## and provide them in original order instead of resorted for all cases
## (was wrong use of which)
if (!is.null(generators) && genspec){
gennam <- names(generators) ## generator names can only refer to basic factors
if (is.null(gennam))
if (is.list(generators))
gennam <- sapply(generators, function(obj) paste0(Letters[sort(obj)], collapse=""))
else if(is.character(generators)) gennam <- generators
gencols <- sapply(gennam, function(obj) which(names(Yates)[1:(nruns-1)] == obj))
design.info <- c(design.info,
list(base.design=paste("generator columns:", paste(gencols, collapse=", ")),
map=map,
orig.fac.order = c(orignew, setdiff(1:nfactors,orignew))))
}
else design.info <- c(design.info, list(catlg.name = catlg.name,
base.design=names(cand[1]),
map=map,
orig.fac.order = c(orignew, setdiff(1:nfactors,orignew))))
} ## end of WPs > 1
## should this be changed to omit the condition on estimable ? July 30 2019
# if (is.null(generators) && !(is.list(blocks) || WPs > 1))
if (is.null(estimable) && is.null(generators) && !(is.list(blocks) || WPs > 1))
design.info <- list(type="FrF2", nruns=nruns, nfactors=nfactors, factor.names=factor.names,
catlg.name = catlg.name,
catlg.entry=cand[1], aliased = alias3fi(k,cand[1][[1]]$gen,order=alias.info),
FrF2.version = sessionInfo(package="FrF2")$otherPkgs$FrF2$Version)
## incorporate reasonable further info (blocks, WPs etc.)
if ((!is.null(generators)) && !is.list(blocks) && !WPs > 1) {
if (nfactors <= 50)
names(generators) <- Letters[(k+1):nfactors]
else names(generators) <- paste("F",(k+1):nfactors, sep="")
gen.display <- paste(names(generators),sapply(generators,function(obj){
if (nfactors <= 50)
paste(if (obj[1]<0) "-" else "", paste(Letters[abs(obj)],collapse=""),sep="")
else
paste(if (obj[1]<0) "-" else "", paste(paste("F",abs(obj),sep=""),collapse=":"),sep="")}), sep="=")
design.info <- list(type="FrF2.generators", nruns=nruns, nfactors=nfactors, factor.names=factor.names, generators=gen.display,
aliased = alias3fi(k,generators,order=alias.info),
FrF2.version = sessionInfo(package="FrF2")$otherPkgs$FrF2$Version)
}
aus <- desdf
rownames(aus) <- rownames(desmat) <- 1:nrow(aus)
class(aus) <- c("design","data.frame")
attr(aus,"desnum") <- desmat
## change 27 Jan 2011: leave orig.no as a factor, but with better-ordered levels
orig.no <- factor(orig.no, levels=unique(orig.no[orig.no.levord]))
## added 14 Feb 2013
orig.no.rp <- factor(orig.no.rp, levels=unique(orig.no.rp[orig.no.levord]))
if (!(is.list(blocks) || WPs > 1))
attr(aus,"run.order") <- data.frame("run.no.in.std.order"=orig.no,"run.no"=1:nrow(desmat),
"run.no.std.rp"=orig.no.rp, stringsAsFactors=TRUE)
else attr(aus,"run.order") <- data.frame("run.no.in.std.order"=orig.no,"run.no"=1:nrow(desmat),
"run.no.std.rp"=orig.no.rp, stringsAsFactors=TRUE)
## make repeat.only reflect the calculated status instead of the status requested by the user
## (which can be seen in the creator element)
if (design.info$type=="FrF2.blocked") {
if (design.info$wbreps==1) repeat.only <- FALSE
design.info$block.old <- block.old ## April 4 2020
nfactors <- ntreat
}
if (nfactors<=50) design.info$aliased <- c(list(legend=paste(Letters[1:nfactors],names(factor.names),sep="=")),
design.info$aliased)
else design.info$aliased <- c(list(legend=paste(paste("F",1:nfactors,sep=""),names(factor.names),sep="=")),
design.info$aliased)
attr(aus,"design.info") <- c(design.info, list(replications=replications, repeat.only=repeat.only,
randomize=randomize, seed=seed, creator=creator))
## add center points, if requested
if (ncenter>0) aus <- add.center(aus, ncenter, distribute=center.distribute)
aus
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.