For (t in T:1)

We programmed a for loop in Stan with indexing going down rather than up. In R that would work, but it doesn’t work in Stan. That’s fine, but maybe San could return a warning when this occurs? Or is there a way for Stan to do reverse loops? No big deal but we just spend 30 minutes debugging until we realized what was happening.

2 Likes

I agree it would be good to have an informative warning/message about this. What happens currently? Does it just silently ignore the loop or throw some error that isn’t clear?

I think to do a reverse loop you need to create an integer array with the elements in the order you want and then loop over that, e.g., for (i in ids) where ids is an integer array with elements in descending order.

There are also some sorting functions that could be useful if you already have something in ascending order and need to sort it in descending order before looping.

It just didn’t execute the loop because the lower bound was higher than the upper bound so the loop was empty.
I guess you could hack a reverse loop using “while” or something like that.

Oh I see, yeah I think a message about the loop being ignored is a good idea. And yeah you could hack it with while(), or loop over an integer array sorted in descending order.

But actually, if what you have is an object whose whose elements you want to loop over in reverse order (not sure if that’s the case here), then there’s a nice way to do that using sort_indices_desc(). For example:

  vector[3] x = [0.1, 0.2, 0.3]';
  for (i in sort_indices_desc(x)) print(x[i]);

will loop over x in reverse order and print (or whatever you want) the elements from last to first.

3 Likes

I’m not sure it is possible for Stan to throw a warning in this case because it generally does not know what T is in advance. If T is 0 or 1, then

for (t in T:1) {
 ...
}

does something but not if T is greater than 1. The C++ gets translated as

for (int t = T; t <= 1; ++t) {
...
}

which is valid C++ syntax even though it won’t do anything if T > 1.

One option would be to do what R does and translate “for (t in 5:1)” to “for (t in c(5, 4, 3, 2, 1))” and then it would work in a natural way.

for( j in 1:0) is a common way to tell code to skip a loop. R is unusual in looping backwards. Matlab’s solution is to have a reverse sequence indicated as T:-1:1

That makes sense. I guess the right way to do it in Stan would be for (j in seq(5,1,-1)) or however such a sequence is constructed in Stan.

Does this work?

for (t in reverse(1:10)) {
 ...
}
2 Likes

I guess that the T variable would often be data and have a lower bound. So for the case of

int<lower=1> T;
...
for(i in T:1) {}

A warning of “For loop will be executed at most one time. If you want to iterate in reverse use …” is possible. (And obviously we could detect that the loop will never be executed)

In pedantic mode we could maybe even have a warning when the bounds allow (but do not ensure) starting index strictly larger than end index.

But this all feels low priority to me.

2 Likes

Just ended up here after an hour or so of debugging, just to ‘+1’ the original post. To me, for(i in ncategories:2){ etc etc seems pretty natural code, some kind of indication that things were going wrong would have been neat ;)

1 Like