Olle Andrén
Olle Andrén

Reputation: 3

Get right output from for loop when in function

I know there may be more elegant to do this - but right now I just want to grok this logic... My problem is that when I do a typical Y[t]=Y[t-1]+i[t] thing for simulation it does not work when put in a function. I want to have a data frame out with the correct variable value on each row for time or t 1-10. Now the cat inside the loop reveals I am going wrong.

Here is my code:

iter <- 10; i <- rep(0.1,iter);  
i <- c(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0)
Y0 <- 0.25 ; O0 <- 4.16 
Y <- rep(0,iter); O <- rep(0,iter) 
Tot <- rep(0,iter)
t <- seq(1,iter) #start time and fill vector
Y[1]=Y0 #First iter
O[1]=O0
Tot[1]= Y0+O0
time<-rep(1,iter)#runtime unit

#This is a simplified version of the ICBM function, to test the logic and output
Isim <- function(i, h, Y0, O0,iter,time) {
  for (t in 2:iter) {
    time<- time+1
    Y[t]=(Y[t-1]+i[t-1]); O[t]=(O[t-1]+i[t-1]); Tot[t]=Y[t]+O[t];
    simout <- data.frame(i,Y0,O0,Y,O,Tot,time)
    cat(time)
  } 
  return(simout)
}

result <- Isim(i, h, Y0, O0,iter, time)

Upvotes: 0

Views: 96

Answers (2)

flodel
flodel

Reputation: 89097

(Let's make abstraction of the fact your code cannot run.) You have a scoping issue at the Y[t]=(Y[t-1]+i[t-1]) step. Let's look at a small reproducible example:

increment_a <- function() { a <- a + 1; print(a); }
a <- 0; print(a); increment_a(); print(a);
# [1] 0 # ok
# [1] 1 # ok
# [1] 0 # not what you expected

Inside increment_a, when R computes a + 1, it first looks for a in the function's environment. That environment being empty, it then looks for a in the environment from which the function was called: your global environment. It finds it there, with a value of 0. It adds 1 to that 0 and then goes to assign it (the a <- part of the statement) in the local environment, i.e. the function's environment.

How can you solve this? You could tell R to assign the result of a + 1 to the a found in the global environment: use <<- instead of <-:

increment_a <- function() { a <<- a + 1; print(a); }
a <- 0; print(a); increment_a(); print(a);
# [1] 0
# [1] 1
# [1] 1

BUT this is not recommended. It is dangerous and will cause you troubles down the line. Instead, you need to fully embrace the functional programming style. I suggest you read the first paragraph of http://en.wikipedia.org/wiki/Functional_programming, especially the part about functions not having side effects. This is how things work:

  1. make your function only use objects that are passed to it as arguments.
  2. make use of the function's output(s) via the return statement.
  3. Do not make your function have side-effect, in particular, do not use <<-.
  4. if your function needs to modify objects: pass them as arguments, make your function modify them and return them. Then re-assign the result as in:
increment <- function(x) { x <- x + 1; print(x); return(x); }
a <- 0; print(a); a <- increment(a); print(a);
# [1] 0
# [1] 1
# [1] 1

Upvotes: 1

alexis_laz
alexis_laz

Reputation: 13122

In your loop, instead of time<- time+1, try to use time[t] <- t..

When you increment time by 1 in each iteration, you end with the vector:

    time
    [1] 10 10 10 10 10 10 10 10 10 10

which is the final input in simout.

simout$time is altered in each iteration as follows:

    2 2 2 2 ... 
    3 3 3 3 ...
    ...
    10 10 10 ...

so you should change only a specific element of time in each iteration.

Now (you can see it from cat) simout$time changes as:

    1 1 1 1 ...
    1 2 1 1 ...
    1 2 3 1 ...
    ...
    1 2 3 4 5 6 7 8 9 10 #this is the final input in "simout"

Upvotes: 0

Related Questions