0

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)
1
  • 1
    What is time doing there, despite being increase by 1? You really shouldn't use a for loop for this. It's very easy to use a vectorized approach here and it will be faster by some orders of magnitude. Commented Oct 13, 2013 at 9:19

2 Answers 2

1

(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
Sign up to request clarification or add additional context in comments.

2 Comments

Wow, two quick replies. Thanks lots. I will now pour a cup of coffee, put on a tinfoil hat and try to improve and correct. R is fun - but it takes some effort to forget old ways...
Don't forget to accept an answer if one of us did answer your question.
0

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"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.