Assign sequence to integer array

Minute syntax question. Let’ say I want to create a sequence of integers. The following doesn’t work:

int sequence[n] = 1:n;

and the error message is the following

SYNTAX ERROR, MESSAGE(S) FROM PARSER:
Variable definition base type mismatch, variable declared as base type int[ ] variable definition has base type intVariable definition dimensions mismatch, definition specifies 1, declaration specifies 0 error in 'model873b2e593919_monster_reparm_par' at line 215, column 34
  -------------------------------------------------
   213:   real C_inh[N_exh];
   214:   
   215:   int exp_index[N_experiments] = 1:N_experiments;  // for reduce_sum
                                         ^
   216: 
  -------------------------------------------------

Error in stanc(filename, allow_undefined = TRUE) : 
  failed to parse Stan model 'monster_reparm_par' due to the above error.

It’s easy to do this in a for loop, but I was wondering if the above syntax is expected to work.

I don’t think it is. Unless something has changed in the latest stan versions, Stan doesn’t use range-expressions like R does. E.g., R takes 1:10 and expands it to c(1,2,3,4,...,10). Stan does not do this. It’s really just some syntactic sugar. E.g., the for(n in 1:N) does not expand out to 1,2,…,10; but rather something like for(int n = 1; n <= N; ++n); so A:B is really just another way of setting a starting value and a condition.

Does that make sense?

That’s something I’ve wanted to do before, and would make for a nice convenience function.

I can add this to the Math library pretty easily, @rok_cesnovar would this be difficult for the parser? In other words, would it be difficult to deduce the different meanings of 1:N between:

int seq[N] = 1:N;

and

for(i in 1:N)
1 Like

As of 2.24 there are some utility construction utilities like

real[] linspaced_array(int, real, real)
row_vector linspaced_row_vector(int, real, real)
vector linspaced_vector(int, real, real)

All arguments here are only allowed to be data.

linspaced_array(K, low, high) produces an array from low to high (included) with elements spaced as (high - low) / (K - 1). For K=1, the array will contain the high value, for K=0 it returns an empty array.

These were added both in Math (PR) and stanc3 (PR) but is unfortunately missing docs: https://github.com/stan-dev/docs/issues/206

We might be able to parse 1:N to linspaced_*(N,1,N). I am however not an expert on parsing to say that with much authority. Please open a stanc3 issue if you would prefer 1:N to linspaced_array.

Yeah that’s what I was thinking. It just needs to be tweaked because the current implementation will only return an array of doubles (i.e., std::vector<double> / real[]) which can’t be used for indexing or assigned to an integer array.

But that just needs some simple templating added to make that work

Ohh yeah, skimmed this to fast. If int is important then yes, we would need to make int[] linspaced_int_array(int, int, int), or int[] linspaced_array(int, int, int)

The colon is allowed in both for-loops and index expressions. In both cases an integer array is also a valid expressions but the ambiguity does not change behaviour; either interpretation does the same thing.

vector[N] svec = vec[1:N];
for (i in 1:N) {
int seq[N] = (1:N);
vector[N] svec = vec[seq];
for (i in seq) {

linspaced does not quite work with integers. For example, linspaced_array(3,1,2) should be {1.0,1.5,2.0} but those aren’t integers.
Instead you want something like int[] unitspaced_array(int low, int high).

1 Like

Oh is this already available?:

int seq[N] = (1:N);

Doh, of course. Silly me. Good call

No. but we could make it available and remove the other uses of : and no one would notice.