Hi, @aammd. Thanks for sharing everything here. I don’t see how this code could run without s and n being the same value, because x is an n-vector and it is being drawn multi-normal with a covariance matrix vcv_x that is s x s. I also see that the data simulation did not involve the variable s. It’s also unusual to have only a single observation for a multi-normal as it’s hard to infer things like variance. Are you going to use this in a situation where there would be more x and y values to sample? Otherwise, your priors are going to have a huge effect on the posterior with just a single data point. Imagine taking y ~ normal(mu, sigma), where y is only a single data point and mu and sigma have priors—it’s not enough data to get a good handle on either mu or sigma, so the prior has a huge effect.
The code was fine as you wrote it. I pulled out a factor in the covariance and added offsets and multipliers to move the normal distributions back closer to standard normal on the unconstrained scale. And I used compound declare and define to shorten things. I would’ve added the constraint cov_matrix to phyvcv but I didn’t have the patience to work out whether it’s required to be symmetric positive definite in order for the result to be—if you add enough to the diagonal, anything’s positive semi-definite.
data {
int<lower=0> n;
int<lower=0> s;
vector[n] x;
vector[n] y;
matrix[s, s] phyvcv;
}
transformed data {
vector[n] zero_vec = rep_vector(0, n);
}
parameters {
real b0;
real<offset=0.5, multiplier=0.5> b1;
real sigma_x;
real sigma_y;
real<offset=3, multiplier=0.2> logit_lambda_x;
real<multiplier=0.2> logit_lambda_y;
}
transformed parameters {
real<lower=0, upper=1> lambda_x = inv_logit(logit_lambda_x);
real<lower=0, upper=1> lambda_y = inv_logit(logit_lambda_y);
}
model {
b0 ~ std_normal();
b1 ~ normal(0.5, 0.5);
sigma_x ~ exponential(1);
sigma_y ~ exponential(1);
logit_lambda_x ~ normal(3, 0.2);
logit_lambda_y ~ normal(0, 0.2);
matrix[s, s] vcv_x
= sigma_x^2 * add_diag(lambda_x * phyvcv, 1 - lambda_x);
matrix[s, s] vcv_y
= sigma_y^2 * add_diag(lambda_y * phyvcv, 1 - lambda_y);
x ~ multi_normal(zero_vec, vcv_x);
y ~ multi_normal(b0 + b1 * x, vcv_y);
}
A way you could make this faster is to parameterize the covariance matrix as a Cholesky factor. The multiplication is easy, but I’m not sure how to do the equivalent of add_diag.
For simplicity, I’d be inclined to just define lambda_x and lambda_y as parameters and give them beta priors that closely mimic your normal(3, 0.2) and normal(0, 0.2), both of which are unimodal once transformed with inverse logit.