Beginner reduce_sum question: incompatible type

I’m trying to get the hang of the new reduce_sum parallelization in cmdstanr, and I’m getting what is probably a very basic error that I can’t seem to crack. I’m just trying to run a very simple OLS with 2 predictors–no hierarchical structure, no non-linear effects–as a proof of concept before I start building in anything fancy. But I keep getting an “incompatible type” error with reduce_sum. The problem is definitely in the code–it doesn’t even map to real data yet. (I can get it to compile just fine if I remove the reduce_sum functionality.)

The code is

functions {
  real partial_sum(vector slice_Y,
                   int start, int end,
                   matrix X,
                   real alpha,
                   vector beta,
                   real sigma) {
    return normal_id_glm_lpdf(slice_Y | X[start:end], alpha, beta, sigma);
  }
}
data {
  int<lower=0> N;
  vector[N] Y;
  matrix[N,2] X;
  int<lower=1> grainsize;
}
parameters {
  real alpha;
  vector[2] beta;
  real sigma;
}
model {

  alpha ~ normal(0,10);
  beta[1] ~ normal(0, 10);
  beta[2] ~ normal(0, 10);

  target += reduce_sum(partial_sum, grainsize, Y,
                       X, alpha, beta, sigma);
}

and the error message is:

Semantic error in '/var/folders/b_/hwc8hm2n6sq1twhhg4jv53_w0000gp/T/RtmpBGz51k/model-161ea232bb1c1.stan', line 28, column 12 to line 29, column 45:
   -------------------------------------------------
    26:    beta[2] ~ normal(0, 10);
    27:  
    28:    target += reduce_sum(partial_sum, grainsize, Y,
                     ^
    29:                         X, alpha, beta, sigma);
    30:  }
   -------------------------------------------------

Ill-typed arguments supplied to function 'reduce_sum'. Available arguments:
(T[], int, int, ...) => real, T[], int, ...
(T[,], int, int, ...) => real, T[,], int, ...
(T[,,], int, int, ...) => real, T[,,], int, ...
(T[,,,], int, int, ...) => real, T[,,,], int, ...
(T[,,,,], int, int, ...) => real, T[,,,,], int, ...
(T[,,,,,], int, int, ...) => real, T[,,,,,], int, ...
(T[,,,,,,], int, int, ...) => real, T[,,,,,,], int, ...
Where T is any one of int, real, vector, row_vector or matrix.
Instead supplied arguments of incompatible type: (vector, int, int, matrix, real, vector, real) => real, int, vector, matrix, real, vector, real

make: *** [/var/folders/b_/hwc8hm2n6sq1twhhg4jv53_w0000gp/T/RtmpBGz51k/model-161ea232bb1c1.hpp] Error 1
Error: An error occured during compilation! See the message above for more information.

Any help would be greatly appreciated. I ultimately have some much more complex models running on large data sets that I’m hoping would benefit from the within-chain parallelization of reduce_sum. Thanks!

1 Like

Hi @emcghee73, I believe you’ve found a bug, the compiler isn’t recognizing a vector type for your slice_Y, even though the signature indicates it’s ok. @bbbales2? You can work around this by either changing,

vector[N] Y;

to

real Y[N];

or creating a dummy array of size N to replace the slicing variable.

1 Like

Thanks, @ssp3nc3r! I tried what I think implements the first idea, and it didn’t work. I changed the code to

functions {
  real partial_sum(real[] slice_Y,
                   int start, int end,
                   matrix X,
                   real alpha,
                   vector beta,
                   real sigma) {
    return normal_id_glm_lpdf(slice_Y | X[start:end], alpha, beta, sigma);
  }
}
data {
  int<lower=0> N;
  real Y[N];
  matrix[N,2] X;
  int<lower=1> grainsize;
}
parameters {
  real alpha;
  vector[2] beta;
  real sigma;
}
model {

  alpha ~ normal(0,10);
  beta[1] ~ normal(0, 10);
  beta[2] ~ normal(0, 10);

  target += reduce_sum(partial_sum, grainsize, Y,
                       X, alpha, beta, sigma);
}

and I got this error

Semantic error in '/var/folders/b_/hwc8hm2n6sq1twhhg4jv53_w0000gp/T/RtmpBGz51k/model-161ea69e39c21.stan', line 8, column 11 to column 73:
   -------------------------------------------------
     6:                     vector beta,
     7:                     real sigma) {
     8:      return normal_id_glm_lpdf(slice_Y | X[start:end], alpha, beta, sigma);
                    ^
     9:    }
    10:  }
   -------------------------------------------------

Ill-typed arguments supplied to function 'normal_id_glm_lpdf'. Available signatures: 
(real, matrix, real, vector, vector) => real
(real, matrix, vector, vector, vector) => real
(vector, row_vector, real, vector, vector) => real
(vector, row_vector, vector, vector, vector) => real
(vector, matrix, real, vector, real) => real
(vector, matrix, vector, vector, real) => real
Instead supplied arguments of incompatible type: real[], matrix, real, vector, real.

make: *** [/var/folders/b_/hwc8hm2n6sq1twhhg4jv53_w0000gp/T/RtmpBGz51k/model-161ea69e39c21.hpp] Error 1
Error: An error occured during compilation! See the message above for more information.

Could you describe a little more about the second idea? Would I declare a new array of type real and then set it equal to Y? And where would I do this declaration? In the function? Or would I feed the dummy into the function? Thanks again for your help!

Hi,

in the first example, the issue is that the first argument should be vector[] not vector. That is because a sliced array will always stay an array type, even if its sliced to single array elements.
So:

real partial_sum(vector[] slice_Y,
                       int start, int end,...

Then you need to rewrite the normal_id_glm_lpdf call a bit.

p.s.:

If the normal_id_glm_lpdf will be a big part of your model you might also consider using a GPU. We have seen speedups of up to 30 for normal_id_glm. But obviously depends on the size of the problem. y and X in your case are data, which makes it a great candidate for the GPU.

@rok_cesnovar, can we change the messaging of the signature to say an array of, e.g.,

Where T is an array of int, real, vector, row_vector or matrix.

or

Where T is any one of int[], real[], vector[], row_vector[] or matrix[].

Check the signatures for these functions…

normal_id_glm_lpdf

only takes a real or vector, but you can convert the array to a vector:

to_vector(slice_Y)

Also, I think your arguments for reduce_sum are in the wrong order. Swap Y with grainsize.

If you ever need this, you can just declare, for example,

transformed data {
real dummy[N];
}

and then use it for the slicing variable. In your case,

target += reduce_sum(partial_sum, dummy, grainsize, Y, X, alpha, beta, sigma);

Then, in the partial_sum function, dummy does not do anything but you’ll then need to slice Y with start:end.

Ill-typed arguments supplied to function 'reduce_sum'. Available arguments:
(T, int, int, ...) => real, T, int, ...
Where T is an array of int, real, vector, row_vector or matrix.

Something like this?

2 Likes

Perfect.

1 Like

Thanks for the tips! What finally worked was to define Y as a real and then use the to_vector() command on slice_Y:

functions {
  real partial_sum(real[] slice_Y,
                   int start, int end,
                   matrix X,
                   real alpha,
                   vector beta,
                   real sigma) {
    return normal_id_glm_lpdf(to_vector(slice_Y) | X[start:end], alpha, beta, sigma);
  }
}
data {
  int<lower=0> N;
  real Y[N];
  matrix[N,2] X;
  int<lower=1> grainsize;
}
parameters {
  real alpha;
  vector[2] beta;
  real sigma;
}
model {

  alpha ~ normal(0,10);
  beta[1] ~ normal(0, 10);
  beta[2] ~ normal(0, 10);

  target += reduce_sum(partial_sum, Y, grainsize,
                       X, alpha, beta, sigma);
}

@rok_cesnovar, when you suggest using a GPU, are you referring to the opencl feature in cmdstan?

Thanks again to you both!

1 Like

Clearly, I also swapped Y and grainsize, so thanks for that tip, too

Yes, see figure 6 on page 17 here https://arxiv.org/pdf/1907.01063.pdf to see what you could gain depending on your n and k. The speedups will off course vary depending on your CPU and GPU.

Thanks!