R/dump.list.format.R

Defines functions list.format dump.format

Documented in dump.format list.format

#' @title Conversion Between a Named List and a Character String in the R Dump Format
#' @name dump.list.format
#' @aliases dump.format list.format

#' @description
#'    Convert a named list of numeric vector(s) or array(s) of data or initial values to a character string in the correct format to be read directly by JAGS as either data or initial values.

#' @details
#' The 'dump.format' function creates a character string of the supplied variables in the same way that dump() would, except that the result is returned as a character string rather than written to file.  Additionally, dump.format() will look for any variable with the name '.RNG.name' and double quote the value if not already double quoted (to ensure compatibility with JAGS).

#' @return
#' Either a character string in the R dump format (for dump.format), or a named list (for list.format).

#' @keywords methods

#' @examples
#' # A named list:
#' namedlist1 <- list(N=10, Count=c(4,2,7,0,6,9,1,4,12,1))
#' # Convert to a character vector:
#' chardata <- dump.format(namedlist1)
#' # And back to a named list:
#' namedlist2 <- list.format(chardata)
#' # These should be the same:
#' stopifnot(identical(namedlist1, namedlist2))

#' @seealso
#' \code{\link{run.jags}} and \code{\link[base]{dump}}

#' @param namedlist a named list of numeric or integer (or something that can be coerced to numeric) vectors, matrices or arrays.  The name of each list item will be used as the name of the resulting dump.format variables.
#' @param data a character string in the R dump format, such as that produced by dump.format.
#' @param checkvalid option to ensure that the object returned from the function does not contain any values that would be invalid for import into JAGS, such as Inf, -Inf or character values etc.
#' @param convertfactors option to automatically convert any factor variables to numeric (otherwise the presence of factors will create an error if checkvalid==TRUE).
NULL

#' @rdname dump.list.format
#' @export
dump.format <- function(namedlist=list(), checkvalid=TRUE, convertfactors=TRUE){

	data <- namedlist

	if(identical(data, list()))
		return('')

	if(length(data)==2 & is.null(names(data)) & is.character(data[[1]]) & length(data[[1]])==1){  # allows old style dump.format (length = 1)
		names <- data
		data <- list(data[[2]])
		names(data) <- names[[1]]
	}

	if(inherits(data, 'data.frame'))
		data <- as.list(data)
	if(!inherits(data,"list") || length(data)==0) stop("Data must be provided as a named list or data frame", call.=FALSE)
	if(any(names(data)=="") || is.null(names(data))) stop("Data must be provided as a named list or data frame", call.=FALSE)
	if(length(unique(names(data)))!=length(data)) stop('All elements in the data list must have unique names', call.=FALSE)

	if(convertfactors){
		for(c in which(sapply(data,inherits,what='factor')))
			data[[c]] <- as.numeric(data[[c]])
	}

	if(checkvalid){
		valid <- checkvalidforjags(data)
		if(!valid$valid) stop(paste("The following problem was identified in the data provided:  ", valid$probstring, sep=""))
	}

	variable = names(data)
	value <- data

	if(any(variable==".RNG.name")){
		n <- which(variable==".RNG.name")
		split <- strsplit(value[[n]], split="")[[1]]
		if(split[1]!="\"" & split[length(split)]!="\""){
			split <- c("\"", split, "\"")
			value[[n]] <- paste(split, collapse="")
		}
	}

	output.string <- ""
	for(i in 1:length(variable)){
		if(length(value[[i]])==1 && length(dim(value[[i]]))==0){
			value.string <- as.character(value[[i]])
		}else{
			dims <- dim(value[[i]])
			if(length(dims) > 1){
				value.string <- "structure(c("
			}else{
				value.string <- "c("
			}
			value.string <- paste(value.string, paste(value[[i]], collapse=", "), ")", sep="")
			if(length(dims) > 1){
				value.string <- paste(value.string, ", .Dim = c(", paste(dims, collapse=", "), "))", sep="")
			}
		}
		output.string <- paste(output.string, "\"", variable[[i]], "\" <- ", value.string, "\n", sep="")
	}

	return(output.string)
}


#' @rdname dump.list.format
#' @export
list.format <- function(data=character(), checkvalid=TRUE){

	if(! inherits(data, c("character","runjagsdata","runjagsinits")) || length(data)==0) stop("Data must be provided as a character string in the R dump format")

	if(all(data=='' | data=='\n'))
		return(list())

	out <- vector('list', length=length(data))

	for(i in 1:length(data)){
		if(data[i]==""){
			out[[i]] <- list()
		}else{
			str <- data[i]
      # Remove anything following a comment:
      str <- gsub('#[^\n]*', '', str)
      # Remove leading and trailing white space:
			str <- gsub('^ *\n', '', str)
			str <- gsub('\n *\n$', '\n', str)

      str <- gsub("<-", "=", str)
			str <- gsub("`", "", str)
			str <- gsub("= \n", "=", str)
			str <- gsub("^\n", "", str)
			str <- gsub("\n\n", "\n", str)
			str <- gsub("\n\n", "\n", str)
			str <- gsub("\n\n", "\n", str)
      str <- gsub(",\n.Dim", ", .Dim", str, fixed=TRUE)
			str <- gsub("\n", ",", str)

			if(str!='' && strsplit(str, split="")[[1]][length(strsplit(str, split="")[[1]])] == ",") str <- paste(strsplit(str, split="")[[1]][1:(length(strsplit(str, split="")[[1]])-1)], collapse="")
			out[[i]] <- eval(parse(text=paste('list(', str, ')')))
		}
	}

	if(length(data)>1){
		names(out) <- paste('Chain.', 1:length(data), sep='')
	}else{
		out <- out[[1]]
	}

	if(checkvalid){
		valid <- checkvalidforjags(out)
		if(!valid$valid)
			stop(paste("The following problem was identified in the data provided:  ", valid$probstring, sep=""))
	}

	return(out)
}

Try the runjags package in your browser

Any scripts or data that you put into this service are public.

runjags documentation built on Aug. 21, 2023, 9:09 a.m.