-
-
Notifications
You must be signed in to change notification settings - Fork 479
/
Copy pathprobit-multi-good.stan
52 lines (52 loc) · 1.48 KB
/
probit-multi-good.stan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
data {
int<lower=1> K;
int<lower=1> D;
int<lower=0> N;
array[N, D] int<lower=0, upper=1> y;
array[N] vector[K] x;
}
parameters {
matrix[D, K] beta;
cholesky_factor_corr[D] L_Omega;
array[N, D] real<lower=0, upper=1> u; // nuisance that absorbs inequality constraints
}
model {
L_Omega ~ lkj_corr_cholesky(4);
to_vector(beta) ~ normal(0, 5);
// implicit: u is iid standard uniform a priori
{
// likelihood
for (n in 1 : N) {
vector[D] mu;
vector[D] z;
real prev;
mu = beta * x[n];
prev = 0;
for (d in 1 : D) {
// Phi and inv_Phi may overflow and / or be numerically inaccurate
real bound; // threshold at which utility = 0
bound = Phi(-(mu[d] + prev) / L_Omega[d, d]);
if (y[n, d] == 1) {
real t;
t = bound + (1 - bound) * u[n, d];
z[d] = inv_Phi(t); // implies utility is positive
target += log1m(bound); // Jacobian adjustment
} else {
real t;
t = bound * u[n, d];
z[d] = inv_Phi(t); // implies utility is negative
target += log(bound); // Jacobian adjustment
}
if (d < D) {
prev = L_Omega[d + 1, 1 : d] * head(z, d);
}
// Jacobian adjustments imply z is truncated standard normal
// thus utility --- mu + L_Omega * z --- is truncated multivariate normal
}
}
}
}
generated quantities {
corr_matrix[D] Omega;
Omega = multiply_lower_tri_self_transpose(L_Omega);
}