# Help with multi-threading with random effects

I’m trying to write a slightly more complicated model than the one I used in my previous question. This is the stan code without multi-threading:

``````data {
int N;
int n_redcards[N];
int n_games[N];
real rating[N];
int<lower=0> N_leagues;
int<lower=1,upper=N_leagues> idx_league[N];
int<lower=0> N_positions;
int<lower=1,upper=N_positions> idx_position[N];
}
parameters {
vector[2] beta;
vector[N_leagues] league_std;
real<lower=0> sigma_league;
vector[N_positions] position_std;
real<lower=0> sigma_position;

}

transformed parameters{
vector[N_leagues] league = sigma_league* league_std;
vector[N_positions] position = sigma_position* position_std;
}

model {
beta ~ std_normal();
league_std ~ std_normal();
sigma_league ~ std_normal();
position_std ~ std_normal();
sigma_position ~ std_normal();
n_redcards ~ binomial_logit( n_games , beta[1] + beta[2] * to_vector(rating) +
league[idx_league] + position[idx_position] );
}
``````

First I want to create shards by just splitting the data without blocking everyone from a league together. I also want to avoid hardcoding the number of shards. To do this, I wrote the following code:

``````functions {
vector lp_reduce( vector beta_common , vector theta , real[] xr , int[] xi ) {
int n = size(xr);
int y[n] = xi[1:n];
int m[n] = xi[(n+1):(2*n)];

int idx_league[n] = xi[(2*n+1):(3*n)];
int idx_position[n] = xi[(3*n+1):(4*n)];

real beta_1 = beta_common[1];
real beta_2 = beta_common[2];
vector[4] league_std = beta_common[3:6];
real sigma_league =  beta_common[7];
vector[13] position_std =  beta_common[8:20];
real sigma_position =  beta_common[21];

vector[4] league =  sigma_league* league_std;
vector[13] position = sigma_position* position_std;

real lp = binomial_logit_lpmf( y | m , beta_1 + to_vector(xr) * beta_2 +
league[idx_league] + position[idx_position]);
return [lp]';
}
}

data {
int N;
int n_redcards[N];
int n_games[N];
real rating[N];
int<lower=1,upper=4> idx_league[N];
int<lower=1,upper=13> idx_position[N];
int n_shards;
}

transformed data {
int modulo = N % n_shards;
int n_per_shard = N/n_shards;
int n_padded = n_per_shard + modulo;
int s_pad = n_per_shard + 1;
int s_games = n_padded + 1;
int e_games = s_games + n_per_shard - 1;

int s_idx_league = e_pad_games + 1;
int e_idx_league = s_idx_league + n_per_shard - 1;

int s_idx_position = e_pad_idx_league + 1;
int e_idx_position = s_idx_position + n_per_shard - 1;

int xi[n_shards, 4*n_padded];  // 4 because 4 variables, and they get stacked in array
// an empty set of per-shard parameters
vector[0] theta[n_shards];

// split into shards
int pos = 1;
//Shards 1 to n_shards - 1 (these ones are padded with zeros)
for ( i in 1:(n_shards-1) ) {
int end = pos + n_per_shard - 1;

xr[i,1:n_per_shard] = rating[pos:end];

xi[i,1:n_per_shard] = n_redcards[pos:end];

xi[i,s_games:e_games] = n_games[pos:end];

xi[i,s_idx_league:e_idx_league] = idx_league[pos:end];

xi[i,s_idx_position:e_idx_position] = idx_position[pos:end];

pos = end + 1;
}

// last shard (this one has no padding)

}

parameters {
vector[2] beta;
vector[4] league_std;
real<lower=0> sigma_league;
vector[13] position_std;
real<lower=0> sigma_position;
}

model {
beta ~ std_normal();
league_std ~ std_normal();
sigma_league ~ std_normal();
position_std ~ std_normal();
sigma_position ~ std_normal();
target += sum( map_rect( lp_reduce ,
append_row(append_row(append_row(append_row(beta, league_std), sigma_league), position_std), sigma_position) , theta , xr , xi ) );
}

``````

Alas, this code only works if I don’t have to pad my shards with zeros. If the data is padded with zeros, then I end up with things like `position[idx_position=0]` which is not defined and therefore the code does not work. Any suggestion for how to avoid this problem?

I believe the following would work, but it is also very very slow:

``````functions {
vector lp_reduce( vector beta_common , vector theta , real[] xr , int[] xi ) {
int n = size(xr);
int y[n] = xi[1:n];
int m[n] = xi[(n+1):(2*n)];

int idx_league[n] = xi[(2*n+1):(3*n)];
int idx_position[n] = xi[(3*n+1):(4*n)];

real beta_1 = beta_common[1];
real beta_2 = beta_common[2];
vector[4] league_std = beta_common[3:6];
real sigma_league =  beta_common[7];
vector[13] position_std =  beta_common[8:20];
real sigma_position =  beta_common[21];

vector[4] league = sigma_league* league_std;
vector[13] position = sigma_position* position_std;

vector[n] lp;

for (i in 1:n) {
if(idx_league[i]==0){
lp[i]=0;
}else{
lp[i] = binomial_logit_lpmf( y[i] | m[i] , beta_1 + xr[i] * beta_2 +
league[idx_league[i]] + position[idx_position[i]]);
}
}

return lp;
}
}

data {
int N;
int n_redcards[N];
int n_games[N];
real rating[N];
int<lower=1,upper=4> idx_league[N];
int<lower=1,upper=13> idx_position[N];
int n_shards;
}

transformed data {
int modulo = N % n_shards;
int n_per_shard = N/n_shards;
int n_padded = n_per_shard + modulo;
int s_pad = n_per_shard + 1;
int s_games = n_padded + 1;
int e_games = s_games + n_per_shard - 1;

int s_idx_league = e_pad_games + 1;
int e_idx_league = s_idx_league + n_per_shard - 1;

int s_idx_position = e_pad_idx_league + 1;
int e_idx_position = s_idx_position + n_per_shard - 1;

int xi[n_shards, 4*n_padded];  // 4 because 4 variables, and they get stacked in array
// an empty set of per-shard parameters
vector[0] theta[n_shards];

// split into shards
int pos = 1;
//Shards 1 to n_shards - 1 (these ones are padded with zeros)
for ( i in 1:(n_shards-1) ) {
int end = pos + n_per_shard - 1;

xr[i,1:n_per_shard] = rating[pos:end];

xi[i,1:n_per_shard] = n_redcards[pos:end];

xi[i,s_games:e_games] = n_games[pos:end];

xi[i,s_idx_league:e_idx_league] = idx_league[pos:end];

xi[i,s_idx_position:e_idx_position] = idx_position[pos:end];

pos = end + 1;
}

// last shard (this one has no padding)

}

parameters {
vector[2] beta;
vector[4] league_std;
real<lower=0> sigma_league;
vector[13] position_std;
real<lower=0> sigma_position;
}

model {
beta ~ std_normal();
league_std ~ std_normal();
sigma_league ~ std_normal();
position_std ~ std_normal();
sigma_position ~ std_normal();
target += sum( map_rect( lp_reduce ,
append_row(append_row(append_row(append_row(beta, league_std), sigma_league), position_std), sigma_position) , theta , xr , xi ) );
}

``````