Reputation: 618
I am attempting to build a function which can accept a list of formula as an argument.
I begin by defining the variables that will be input as the arguments into the function. The first two variables are named vectors that contain boolean information.
named_variable_vector <- c(0, 1, 1)
names(named_variable_vector) <- c("M", "E", "L")
named_variable_vector
named_parameter_vector <- c(0, 0)
names(named_parameter_vector) <- c("G_e", "L_e")
named_parameter_vector
The third argument is a list of formula objects. Formula is a "language" class object that doesn't get evaluated until explicitly told to do so using the f_eval() function.
logic_list <- list(~((G_e + 1)*(L + L_e + L*L_e))%%2, ~M , ~((G_e + 1)*E*L_e)%%2)
Ok, time to build the function. First step is to create local variables within the function. These local variables will be named after the names of the named_vector arguments.
Boolean_state_space <- function(variables, parameters, logic) {
variable_names <- names(variables)
parameter_names <- names(parameters)
####generate local variables
#assign variable values to variable names
for (i in 1:length(variables)) {
assign(variable_names[i], variables[i])
}
#assign parameter values to parameter names
for (j in 1:length(parameters)) {
assign(parameter_names[j], parameters[j])
}
Then I initialize a matrix. After that, I print out the local variables to test if they were successfully made. This is just a test line and wouldn't be in the final version of the function.
#initialize matrix
state_space_matrix <- matrix(nrow = 4, ncol = length(c(variable_names, parameter_names)))
colnames(state_space_matrix) <- c(variable_names, parameter_names)
rownames(state_space_matrix) <- c(1:nrow(state_space_matrix))
row.names(state_space_matrix)[1] <- c("t")
state_space_matrix[1,] <- c(variables, parameters)
state_space_matrix[,c(ncol(state_space_matrix) - 1, ncol(state_space_matrix) )] <-parameters
print(state_space_matrix) #test to see if matrix was initialized succesfully
print(c(M, E, L, G_e, L_e)) #test to see if local variables were successfully defined within the function
Finally, time to use the logic argument! The goal here is to have the function use the equations provided in the logic argument to "update" the next row of the matrix by using the values available in the previous row.
This first line evaluates the equations in order, then assigns those values to the next row in the matrix. This is where the error occurs.
for (k in 2:nrow(state_space_matrix)) {
for (h in 1:length(variable_names)) {
state_space_matrix[k, variable_names[h]] <- f_eval(logic[[h]])
print("test")
}
The second line now reassigns the values for the variables, using the values in the most recently updated row of the matrix.
for (g in 1:length(variable_names)) {
assign(variable_names[g], state_space_matrix[k, g])
}
}
print(state_space_matrix)
} #end of function
Ok, when I ran the function with the arguments I had set in the beginning:
Boolean_state_space(named_variable_vector, named_parameter_vector, logic_list)
I get the following error:
Error in eval(expr, data, expr_env) : object 'G_e' not found
I can't for the life of me figure out why. Why is the function not seeing the local variables I had defined in it earlier? Those variables need to be used to evaluate the formula.
P.S. I am sure there may be a better/more elegant way of writing this function using a similar argument format and I would love to know them. But for learning purposes, I really want to know if my method of writing this function can work.
P.P.S. My method works great when I run the internals of the function separately (AKA in the global environment). Results look like this:
Upvotes: 0
Views: 138
Reputation: 497
I solved this by being explicit about the data using a parameter list instead of relying on the correct environments.
Boolean_state_space <- function(variables, parameters, logic) {
variable_names <- names(variables)
parameter_names <- names(parameters)
####generate local variables
#assign variable values to variable names
for (i in 1:length(variables)) {
assign(variable_names[i], variables[i])
}
print(variable_names)
#assign parameter values to parameter names
for (j in 1:length(parameters)) {
assign(parameter_names[j], parameters[j])
}
#initialize matrix
state_space_matrix <- matrix(nrow = 4, ncol = length(c(variable_names, parameter_names)))
colnames(state_space_matrix) <- c(variable_names, parameter_names)
rownames(state_space_matrix) <- c(1:nrow(state_space_matrix))
row.names(state_space_matrix)[1] <- c("t")
state_space_matrix[1,] <- c(variables, parameters)
state_space_matrix[,c(ncol(state_space_matrix) - 1, ncol(state_space_matrix) )] <-parameters
print(state_space_matrix) #test to see if matrix was initialized succesfully
print(c(M, E, L, G_e, L_e)) #test to see if local variables were successfully defined within the function
## CREATE PARAMETER LIST
param_list <- split(unname(parameters), names(parameters))
param_list <- c(split(unname(variables), names(variables)), param_list)
cols <- names(variables)
for (k in 2:nrow(state_space_matrix)) {
for (h in 1:length(variable_names)) {
state_space_matrix[k, cols[h]] <- lazyeval::f_eval(logic[[h]], param_list)
print("test")
}
## UPDATE PARAMETER LIST WITH CURRENT VALUES
for (g in 1:length(variable_names)) {
param_list[variable_names[g]] <- state_space_matrix[k, g]
}
}
print(state_space_matrix)
}
Boolean_state_space(named_variable_vector, named_parameter_vector, logic_list)
Boolean_state_space <- function(variables, parameters, logic) {
variable_names <- names(variables)
parameter_names <- names(parameters)
####generate local variables
#assign variable values to variable names
for (i in 1:length(variables)) {
assign(variable_names[i], variables[i])
}
#assign parameter values to parameter names
for (j in 1:length(parameters)) {
assign(parameter_names[j], parameters[j])
}
state_space_matrix <- matrix(nrow = 4, ncol = length(c(variable_names, parameter_names)))
colnames(state_space_matrix) <- c(variable_names, parameter_names)
rownames(state_space_matrix) <- c(1:nrow(state_space_matrix))
row.names(state_space_matrix)[1] <- c("t")
state_space_matrix[1,] <- c(variables, parameters)
state_space_matrix[,c(ncol(state_space_matrix) - 1, ncol(state_space_matrix) )] <-parameters
print(state_space_matrix) #test to see if matrix was initialized succesfully
print(c(M, E, L, G_e, L_e)) #test to see if local variables were successfully defined within the function
print(parent.frame())
# Get correct environment
env <- pryr::where(variable_names[1])
for (k in 2:nrow(state_space_matrix)) {
for (h in 1:length(variable_names)) {
# Set environment to evaluate functions in
rlang::f_env(logic[[h]]) <- env
state_space_matrix[k, variable_names[h]] <- lazyeval::f_eval(logic[[h]])
print("test")
}
for (g in 1:length(variable_names)) {
assign(variable_names[g], state_space_matrix[k, g])
}
}
print(state_space_matrix)
}
Boolean_state_space(named_variable_vector, named_parameter_vector, logic_list)
Upvotes: 1