forked from tomov/chunking
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsample.m
More file actions
148 lines (122 loc) · 4.03 KB
/
Copy pathsample.m
File metadata and controls
148 lines (122 loc) · 4.03 KB
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
function [samples, post] = sample(D, h, nsamples, burnin, lag)
%
% Draw samples from posterior P(H|D) using Metropolis-Hastings-within-Gibbs sampling.
% hierarchy H = (c, p, q, p', p", E', V')
% data D = (G, tasks)
% graph G = (E, V)
% tasks = (task_1, task_2 ...)
% task = (s, g)
%
% Generative model:
%
% P(H):
% state chunks = c ~ CRP
% within-cluster density = p ~ Beta
% across-cluster density = pq, q ~ Beta
% H graph density = p' = hp ~ Beta
% probability goal state is in different chunk from starting state = p" = tp ~ Beta
%
% P(G|H):
% E(i,j) ~ Bern(p) if c(i) == c(j)
% E(i,j) ~ Bern(pq) if c(i) != c(j)
%
% P(tasks|G,H) = product P(task|G,H)
% P(task|G,H):
% starting state = s ~ Cat(all vertices in G)
% goal state = g ~ Cat(1,1,1,1... for all i s.t. c(i) == c(s), ... p", p", p"... for all i s.t. c(i) != c(s)
%
if ~exist('nsamples', 'var')
nsamples = 10000;
end
if ~exist('burnin', 'var')
burnin = 1; % no burn-in
end
if ~exist('lag', 'var')
lag = 1;
end
H = init_H(D, h);
% Roberts & Rosenthal (2009)
for n = 1:nsamples * lag + burnin
for i = 1:D.G.N
logp = @(c_i) logpost_c_i(c_i, i, H, D, h);
proprnd = @(c_i_old) proprnd_c_i(c_i_old, i, H, D, h);
logprop = @(c_i_new, c_i_old) logprop_c_i(c_i_new, c_i_old, i, H, D, h);
[c_i, accept] = mhsample(H.c(i), 1, 'logpdf', logp, 'proprnd', proprnd, 'logproppdf', logprop);
H.c(i) = c_i;
end
logp = @(p) logpost_p(p, H, D, h);
proprnd = @(p_old) proprnd_p(p_old, H, D, h);
logprop = @(p_new, p_old) logprop_p(p_new, p_old, H, D, h);
[p, accept] = mhsample(H.p, 1, 'logpdf', logp, 'proprnd', proprnd, 'logproppdf', logprop); % TODO adaptive
H.p = p;
[q, accept] = mhsample(H.q, 1, 'logpdf', logp, 'proprnd', proprnd, 'logproppdf', logprop);
H.q = q;
[tp, accept] = mhsample(H.tp, 1, 'logpdf', logp, 'proprnd', proprnd, 'logproppdf', logprop);
H.tp = tp;
[hp, accept] = mhsample(H.hp, 1, 'logpdf', logp, 'proprnd', proprnd, 'logproppdf', logprop);
H.hp = hp;
% TODO bridges
samples(n) = H;
post(n) = logpost(H,D,h);
end
samples = samples(burnin:lag:end);
end
% P(H|D) up to proportionality constant
%
function logp = logpost(H, D, h)
logp = loglik(H, D, h) + logprior(H, D, h);
end
% P(H|D) for updates of c_i
% i.e. with new c's up to c_i, the candidate c_i, then old c's after (and old rest of H)
%
function logp = logpost_c_i(c_i, i, H, D, h)
H.c(i) = c_i;
logp = logpost(H, D, h);
end
% proposal PMF for c_i
% inspired by Algorithm 5 from Neal 1998: MCMC for DP mixtures
%
function P = propP_c_i(c_i_old, i, H, D, h)
cnt = get_H_cnt(H, D);
cnt(H.c(i)) = cnt(H.c(i)) - 1;
z = find(cnt == 0); % reuse empty bins TODO is this legit?
if isempty(z)
cnt = [cnt h.alpha];
else
cnt(z) = h.alpha;
end
P = cnt / sum(cnt);
end
% propose c_i
%
function c_i_new = proprnd_c_i(c_i_old, i, H, D, h)
P = propP_c_i(c_i_old, i, H, D, h);
c_i_new = find(mnrnd(1, P));
% TODO bridges
end
function [logP, P] = logprop_c_i(c_i_new, c_i_old, i, H, D, h) % TODO merge w/ proprnd
P = propP_c_i(c_i_old, i, H, D, h);
logP = log(P(c_i_new));
end
% P(H|D) for updates of p
%
function logp = logpost_p(p, H, D, h)
H.p = p;
logp = logpost(H, D, h);
end
% proposals for p; random walk
%
function p_new = proprnd_p(p_old, H, D, h)
while true % TODO can use universality of uniform inverse CDF thingy
p_new = normrnd(p_old, 0.1); % TODO const TODO adaptive
if p_new <= 1 && p_new >= 0
break; % keep params within bounds
end
end
end
% account for truncating that keeps params within bounds
%
function logp = logprop_p(p_new, p_old, H, D, h)
Z = normcdf(1, p_old, 0.1) - normcdf(0, p_old, 0.1); % TODO consts TODO adaptive
logp = log(normpdf(p_new, p_old, 1)) - log(Z);
end