Scoping problem when assigning functions in a loop - r

I would like to create a bunch of functions with a particular structure in the variable name as a crude workaround for what should be one function with multiple arguments (this I cannot do directly). Let's consider the following analogous example:
for(i in 1:3){
for(j in 1:2){
temp_fun <- function(x){
(x+i)^j
}
assign(paste0("fun", paste0("_plus_", i, "_pow_", j)), temp_fun)
}
}
This loop creates 6 functions that have x as dependent variable only
fun_plus_1_pow_1
fun_plus_1_pow_2
fun_plus_2_pow_1
fun_plus_2_pow_2
fun_plus_3_pow_1
fun_plus_3_pow_2
For instance fun_plus_2_pow_1(2) should return (2+2)^1 = 4, however it returns 25. I know what happens here, the values for i and j get updated while the loop is running and eventually i=3 and j=2are taken resulting in (2+3)^2 = 25.
But how can I make them local?

Here is one option. I also changed that assign stuff (creating a bunch of systematically named objects in the global environment is a clear sign to use a list instead).
funs <- matrix(list(), 3, 2, dimnames = list(paste0("plus", 1:3),
paste0("pow", 1:2)))
for(i in 1:3){
for(j in 1:2){
create_fun <- function(i, j){
#force evaluation so that the values are stored in the closure
force(i); force(j)
function(x) (x+i)^j
}
funs[i, j][[1]] <- create_fun(i, j)
}
}
funs["plus2", "pow1"][[1]](2)
#[1] 4

Why do you need to do this? Would it be sufficient to just define one function fun(x, i, j) and then use partial application:
library(pryr)
fun <- function(x, i, j) (x + i)^j
partial(fun, i = 2, j = 1)(2)
## [1] 4
# an example of passing partial(...) as a function to another function, i.e. to sapply
sapply(1:10, partial(fun, i = 2, j = 1))
## [1] 3 4 5 6 7 8 9 10 11 12
Note that partial(fun, i = i, j = j) for particular values of i and j is a function of x alone.

Related

How to create matrix of all 2^n binary sequences of length n using recursion in R?

I know I can use expand.grid for this, but I am trying to learn actual programming. My goal is to take what I have below and use a recursion to get all 2^n binary sequences of length n.
I can do this for n = 1, but I don't understand how I would use the same function in a recursive way to get the answer for higher dimensions.
Here is for n = 1:
binseq <- function(n){
binmat <- matrix(nrow = 2^n, ncol = n)
r <- 0 #row counter
for (i in 0:1) {
r <- r + 1
binmat[r,] <- i
}
return(binmat)
}
I know I have to use probably a cbind in the return statement. My intuition says the return statement should be something like cbind(binseq(n-1), binseq(n)). But, honestly, I'm completely lost at this point.
The desired output should basically recursively produce this for n = 3:
binmat <- matrix(nrow = 8, ncol = 3)
r <- 0 # current row of binmat
for (i in 0:1) {
for (j in 0:1) {
for (k in 0:1) {
r <- r + 1
binmat[r,] <- c(i, j, k)}
}
}
binmat
It should just be a matrix as binmat is being filled recursively.
I quickly wrote this function to generate all N^K permutations of length K for given N characters. Hope it will be useful.
gen_perm <- function(str=c(""), lst=5, levels = c("0", "1", "2")){
if (nchar(str) == lst){
cat(str, "\n")
return(invisible(NULL))
}
for (i in levels){
gen_perm(str = paste0(str,i), lst=lst, levels=levels)
}
}
# sample call
gen_perm(lst = 3, levels = c("x", "T", "a"))
I will return to your problem when I get more time.
UPDATE
I modified the code above to work for your problem. Note that the matrix being populated lives in the global environment. The function also uses the tmp variable to pass rows to the global environment. This was the easiest way for me to solve the problem. Perhaps, there are other ways.
levels <- c(0,1)
nc <- 3
m <- matrix(numeric(0), ncol = nc)
gen_perm <- function(row=numeric(), lst=nc, levels = levels){
if (length(row) == lst){
assign("tmp", row, .GlobalEnv)
with(.GlobalEnv, {m <- rbind(m, tmp); rownames(m) <- NULL})
return(invisible(NULL))
}
for (i in levels){
gen_perm(row=c(row,i), lst=lst, levels=levels)
}
}
gen_perm(lst=nc, levels=levels)
UPDATE 2
To get the expected output you provided, run
m <- matrix(numeric(0), ncol = 3)
gen_perm(lst = 3, levels = c(0,1))
m
levels specifies a range of values to generate (binary in our case) to generate permutations, m is an empty matrix to fill up, gen_perm generates rows and adds them to the matrix m, lst is a length of the permutation (matches the number of columns in the matrix).

A problem with wrapping array algorithm into a function

I just started programming in R. I'm working at code which execute operations on arrays. It works when I put there a variable but if i wrap it into a function something is wrong. When I try to recall list_matrices[i] i got NULL.
F <- function(x){
list_matrices=c()
for(i in 1:dim(x)[1]){
list_matrices[[i]] <- t(rbind(x[i,1:dim(x)[2],1:dim(x)[3]]))}
}
It has already been pointed out in the comments that the problem is that the function does not return list_matrices so here we will point out that there is some question of whether you really need to do this in the first place. If the reason to create the list is to later iterate over it with some function g, it would be possible to do that directly over 'x' using apply. These two are the same:
# test inputs
x <- array(1:24, 2:4)
g <- function(x) sum(x*x)
# 1
f <- function(x) {
list_matrices <- c()
for(i in 1:dim(x)[1]) {
list_matrices[[i]] <- t(rbind(x[i,1:dim(x)[2],1:dim(x)[3]]))
}
list_matrices
}
L <- f(x)
sapply(L, g)
## [1] 2300 2600
# 2
apply(x, 1, g)
## [1] 2300 2600
Also note that F is used for FALSE in R and could result in subtle errors if used as the name of an object so above we have renamed the function f.

Incrementing i when assigning functions?

I'm trying to create functions containing i in a loop, but i isn't been evaluated.
For example, the loop:
func <- list(0)
for (i in 1:3) {
func[[i]] <- function(x) i*x
}
produces:
> func[[1]]
function(x) i * x
<bytecode: 0x0000000011316b08>
when I actually need 1 * x, 2 * x, 3 * x
Write a function that returns a function. Be sure to use force() to force the evaluation of the lazy parameter.
func <- list(0)
makefun <- function(i) {
force(i)
function(x) i*x
}
func <- Map(makefun, 1:3)
func[[1]](5)
# [1] 5
func[[2]](5)
# [1] 10
func[[3]](5)
# [1] 15
You could do this in a for loop with the help of local().
func <- list(0)
for (i in 1:3) {
func[[i]] <- local({i<-i; function(x) i*x})
}
In both cases the definition still looks like "function(x) i*x" but the environment where the i value is coming from is different.
The issue is that your function refers to i, but there's only one i.MrFlick's answer is one way to force a local environment to be created to hold different copies of i with different values; another is to use local(), e.g.
func <- list()
for (i in 1:3) {
func[[i]] <- local(
{
j <- i # make a local copy of the current value
function(x) j*x
} )
}
func[[1]](5)
# [1] 5
func[[2]](5)
# [1] 10
func[[3]](5)
# [1] 15

Variable matrix index and row/column as indices in a single function argument

How to handle a variable matrix index and row/column as indices in a single function argument?
m <- matrix(1:9, 3)
fn <- function(m, subsetArg) {
stopifnot(m[subsetArg] == 6)
}
I'd like to be able to use both situations:
a <- matrix(FALSE, 3, 3)
a[2,3] <- TRUE
# yielding
# F F F
# F F T
# F F F
fn(m, subsetArgument = a) # works
and
fn(m, subsetArgument = tuple(2,3)) # <- does not work logically
Note that I would also be after using a range, for example tuple(2, 1:3)
I understand this could be done very explicitly by testing for either 1 or 2 variables given, but I feel there might be an easier way.
Just slurp all the arguments up and pass them into a call to [:
fn <- function(...) {
stopifnot(do.call(`[`, list(...)) == 6)
}
Everything in R is a function, including subsetting :-)
You can subset a matrix using an integer matrix. For example, instead of
m <- matrix(1:9, 3)
fn <- function(m, subsetArg) {
(m[subsetArg])
}
a <- matrix(FALSE, 3, 3)
a[2,3] <- TRUE
fn(m,subsetArg=a)
You could simply write:
n <- matrix(ncol=2, byrow=TRUE, c(2,3))
m[n]
Which would also work in your function, and returns the same result:
fn(m,subsetArg=n)
If you create your index matrix correct you can get the result that you're looking for in the tuple example:
n.tuple <- as.matrix(expand.grid(x=2, y=1:3))
m[n.tuple]
Of course you could write a tuple function which does it for you, which would work as expected:
tuple <- function(x,y) {
as.matrix(expand.grid(x=x, y=y))
}
fn(m, subsetArg = tuple(2,3)) # 8
fn(m, subsetArg = tuple(2,1:3)) # 2 5 8

How to efficiently implement function iteration in R

In R, what is the most efficient way of implementing
y[1] = x[1]
for (i in 2:length(x)) {
y[i] = f (y[i-1], x[i])
}
where x is my input and f is a given function?
Ideally I would have liked to be able to say
y[1] = x[1]
y[2:N] = sapply (2:N, function (i) {f(y[i-1], x[i])}) # WRONG of course!
But this is of course wrong. Is there a built-in looping function that will do this for me?
Reduce will reduce the number of keystrokes needed to do this sort of operation:
Reduce(f, x, accumulate=TRUE)
For instance, let's consider a simple case where you are just adding the elements (of course cumsum(x) would be more efficient in this case):
x <- c(1, 2, 4, 5)
Reduce("+", x, accumulate=TRUE)
# [1] 1 3 7 12

Resources