######################## ## Check a bugs model ## bugsCheck = function(model, categorize=TRUE) { if (!is.character(model) || length(model)!=1) stop("The argument must be a model in a string or a file name") if (substring(model,1,7)!="model {" && substring(model,1,6)!="model{" && model!="model") { if (!file.exists(model)) stop("File ", model, " not found!") model = readLines(model) } else { model = strsplit(model,"\n")[[1]] } # Remove comments and blank lines require(gdata) comments = grep("#", model, value=TRUE) comPos = grep("#", model) if (length(comPos)>0) { model[comPos] = sapply(strsplit(comments,"#"),function(x)x[1]) } model = trim(model) model = model[model!=""] # Basic syntax and removal of "model{" and "}" if (substring(model[1],1,6)!="model{" && substring(model[1],1,7)!="model {" && model[1]!="model") stop("model should start with \"model {\"") N = length(model) if (model[1]=="model") { if (N<2 && substring(model[2],1,1)!="{") stop("model should start with \"model {\"") if (nchar(model[2])==1) { model = model[-2] N = N - 1 } else { model[2] = trim(substring(model[2],2)) } } last = model[N] if (substring(last,nchar(last))!="}") stop("model must end with \"}\"") tmp = strsplit(model[1], "\\{")[[1]] if (length(tmp)>2) stop("syntax too complex for bugsCheck()") if (length(tmp)==1) { model = model[-1] N = N - 1 } else { model[1] = tmp[2] } if (nchar(last)==1) { model = model[-N] N = N - 1 } else { model[N] = trim(substring(model[N],1,nchar(model[N])-1)) } # Checking of parentheses, brackets and braces # Braces assumed to be only one per line!! lefts = length(grep("\\{", model)) rights = length(grep("\\}", model)) problems = NULL if (lefts!=rights) { problems=c(problems, paste("Possible braces mismatch (", lefts, " left braces and ", rights, " right braces) or syntax too complex for bugsCheck()",sep="")) } # Parentheses and brackets only counted in toto singlesList = strsplit(model,"") singles = unlist(singlesList) lefts = sum(singles=="(") rights = sum(singles==")") if (lefts!=rights) { problems=c(problems, paste("Parentheses mismatch (", lefts, " left parentheses and ", rights, " right parentheses)",sep="")) } lefts = sum(singles=="[") rights = sum(singles=="]") if (lefts!=rights) { problems=c(problems, paste("Bracket mismatch (", lefts, " left brackets and ", rights, " right brackets)",sep="")) } # Checking for reverse "<-" tmp = grep("->", model, fixed=TRUE) if (length(tmp)>0) { problems=c(problems, paste(">- found on line(s)", paste(tmp,sep=", "), "; did you mean <-?.")) } # Checking for equal signs tmp = sapply(singlesList, function(x) any(x=="=")) if (any(tmp)) { problems=c(problems, paste("Equal sign(s) found on line(s) ", paste(which(tmp), sep=", "), "; this is wrong except in the \"const\" statement.", sep="")) } # Checking for valid functions funcs = grep("[a-zA-Z]+[\\(]", model, value=T) funcN = grep("[a-zA-Z]+[\\(]", model) alpha = c(letters,LETTERS) validFunctions = c("abs","cloglog","cos","cut","equals","exp","inprod", "interp.lin","inverse","log","logdet","logfact","loggam", "logit","max","mean","min","phi","pow","sin","probit", "sd","sqrt","step","sum","rank","ranked","round","trunc", "I","for", "dbern","dbin","dnegbin","dcat","dmulti","dchisq", "ddexp","dlogis","dlnorm","ddirch","dexp","dgamma", "dmnorm","dnorm","dpar","dpois","dt","dunif", "dweib","dwish") for (i in seq(along=funcN)) { tmp = funcs[i] parens = NULL for (j in 2:nchar(tmp)) { if (substring(tmp,j,j)=="(") parens=c(parens,j) } # for each (likely) function: for (j in seq(along=parens)) { for (k in (parens[j]-1):1) { if (!any(substring(tmp,k,k)==alpha)) { k = k + 1 break } } if (k==parens[j]) next if (!any(substring(tmp,k,k)==alpha)) { problems = c(problems, paste("At line ", offset+funcN[i], ", ", tmp, " looks weird.", sep="")) } else if (!any(substring(tmp,k,parens[j]-1)==validFunctions)) { problems = c(problems, paste("At line ", offset+funcN[i], ", ", substring(tmp,k,parens[j]-1), " is not on the valid function list.", sep="")) } } # next function on this line } # next line with functions ## Get a full variable list varList = gsub("[", "[ ", model, fixed=TRUE) special = c("+","-","*","/",",","]","~","<",">","-","(",")","{","}",":") varList = unique(unlist(strsplit(varList, " ", fixed=T))) for (i in 1:length(special)) { varList = unique(unlist(strsplit(varList, special[i], fixed=T))) varList = varList[varList!=""] } varList = sort(varList) varList = varList[substring(varList,1,1)%in%alpha] varList = varList[!varList%in%c("in","for",validFunctions)] varListOut = varList mult = substring(varList,nchar(varList))=="[" if (length(mult)>0) { varListOut[mult] = paste(varList[mult],"]",sep="") varList[mult] = substring(varList[mult],1,nchar(varList[mult])-1) } # Categorize variables, categorize is TRUE if (categorize) { if (!file.exists("data.txt")) { warning("data.txt not found") data = NULL } else { tmp = dget("data.txt") Ns = sapply(tmp,length) data = names(tmp) tmp = match(data, varList) Bad = is.na(tmp) if (any(Bad)) { problems = c(problems, paste("In data but not in model: ", paste(data[Bad],sep=", "), sep="")) data = data[!Bad] Ns = data[!Bad] } if (any(mult)) { dataMult = match(varList[mult], data) dataMult = dataMult[!is.na(dataMult)] if (length(dataMult)>0) { Bad = Ns[dataMult]==1 if (any(Bad)) { problems = c(problems, paste("Vector in model, but single in data: ", paste(data[Bad],sep=", "), sep="")) } } } else if (any(!mult)) { dataMult = match(varList[!mult], data) dataMult = dataMult[!is.na(dataMult)] if (length(dataMult)>0) { Bad = Ns[dataMult]!=1 if (any(Bad)) { problems = c(problems, paste("Vector in model, but single in data: ", paste(data[Bad],sep=", "), sep="")) } } } # end if any mult or not mult } # end if data found # Handle inits if (!file.exists("inits1.txt")) { warning("inits1.txt not found") inits = NULL } else { initVals = dget("inits1.txt") Ns = sapply(initVals,length) inits = names(initVals) tmp = match(inits, varList) Bad = is.na(tmp) if (any(Bad)) { problems = c(problems, paste("In inits but not in model: ", paste(inits[Bad],sep=", "), sep="")) inits = inits[!Bad] Ns = inits[!Bad] } if (any(mult)) { initsMult = match(varList[mult], inits) initsMult = initsMult[!is.na(initsMult)] if (length(initsMult)>0) { Bad = Ns[initsMult]==1 if (any(Bad)) { problems = c(problems, paste("Vector in model, but single in inits: ", paste(inits[Bad],sep=", "), sep="")) } } } else if (any(!mult)) { initsMult = match(varList[!mult], inits) initsMult = initsMult[!is.na(initsMult)] if (length(initsMult)>0) { Bad = Ns[initsMult]!=1 if (any(Bad)) { problems = c(problems, paste("Vector in model, but single in inits: ", paste(inits[Bad],sep=", "), sep="")) } } } # end if any mult or not mult #Sel = match(inits, names(initVals)) #One = sapply(initVals[Sel],length)==1 #inits[!One] = paste(inits[!One],"[]",sep="") #browser() } # end if inits found } if (is.null(problems)) problems = "No problems detected!" return(list(problems=problems, modelVarList=varListOut, data=data, inits=inits, uninitialized=setdiff(setdiff(varList,data),inits))) }