-
Notifications
You must be signed in to change notification settings - Fork 0
/
changepoint.stan
66 lines (57 loc) · 1.58 KB
/
changepoint.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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Built with stan 2.11
data {
int<lower=1> N;
real D[N];
}
parameters {
real mu1;
real mu2;
real<lower=0> sigma1;
real<lower=0> sigma2;
}
// Marginalize out tau and
// calculate log_p(D | mu1, sd1, mu2, sd2)
// Quadratic time solution
//transformed parameters {
// vector[N] log_p;
// real mu;
// real sigma;
// log_p = rep_vector(-log(N), N);
// for (tau in 1:N)
// for (i in 1:N) {
// mu = i < tau ? mu1 : mu2;
// sigma = i < tau ? sigma1 : sigma2;
// log_p[tau] = log_p[tau] + normal_lpdf(D[i] | mu, sigma);
// }
//}
// Linear time solution, as suggested by @idontgetoutmuch
// https://github.com/gmodena/bayesian-changepoint/issues/1
transformed parameters {
vector[N] log_p;
{
vector[N+1] log_p_e;
vector[N+1] log_p_l;
log_p_e[1] = 0;
log_p_l[1] = 0;
for (i in 1:N) {
log_p_e[i + 1] = log_p_e[i] + normal_lpdf(D[i] | mu1, sigma1);
log_p_l[i + 1] = log_p_l[i] + normal_lpdf(D[i] | mu2, sigma2);
}
log_p = rep_vector(-log(N) + log_p_l[N + 1], N) + head(log_p_e, N) - head(log_p_l, N);
}
}
model {
mu1 ~ normal(0, 10);
mu2 ~ normal(0, 10);
// scale parameters need to be > 0;
// we constrained sigma1, sigma2 to be positive
// so that stan interprets the following as half-normal priors
sigma1 ~ normal(0, 10);
sigma2 ~ normal(0, 10);
target += log_sum_exp(log_p);
}
//Draw the discrete parameter tau. This is highly inefficient
generated quantities {
int<lower=1,upper=N> tau;
tau = categorical_rng(softmax(log_p));
}