1
1
"""
2
- MetropolisHastings{P<:ProposalStyle, T, D}
2
+ MetropolisHastings{D}
3
3
4
- Fields:
4
+ `MetropolisHastings` has one field, `proposal`.
5
+ `proposal` is a `Proposal`, `NamedTuple` of `Proposal`, or `Array{Proposal}` in the shape of your data.
6
+ For example, if you wanted the sampler to return a `NamedTuple` with shape
5
7
6
- - `init_params` is the vector form of the parameters needed for the likelihood function.
7
- - `proposal` is a function that dynamically constructs a conditional distribution.
8
+ ```julia
9
+ x = (a = 1.0, b=3.8)
10
+ ```
8
11
9
- Example:
12
+ The proposal would be
10
13
11
14
```julia
12
- MetropolisHastings([0.0, 0.0], x -> MvNormal(x, 1.0 ))
15
+ proposal = (a=Proposal(Static(), Normal(0,1)), b=Proposal(Static(), Normal(0,1) ))
13
16
````
17
+
18
+ Other allowed proposal styles are
19
+
20
+ ```
21
+ p1 = Proposal(Static(), Normal(0,1))
22
+ p2 = Proposal(Static(), [Normal(0,1), InverseGamma(2,3)])
23
+ p3 = Proposal(Static(), (a=Normal(0,1), b=InverseGamma(2,3)))
24
+ p4 = Proposal(Static(), (x=1.0) -> Normal(x, 1))
25
+ ```
26
+
27
+ The sampler is constructed using
28
+
29
+ ```julia
30
+ spl = MetropolisHastings(proposal)
31
+ ```
14
32
"""
15
- mutable struct MetropolisHastings{P<: ProposalStyle , D, T} <: Metropolis
16
- proposal_type :: P
33
+ mutable struct MetropolisHastings{D} <: Metropolis
17
34
proposal :: D
18
- init_params :: T
35
+ end
36
+
37
+ StaticMH (d) = MetropolisHastings (Proposal (Static (), d))
38
+ RWMH (d) = MetropolisHastings (Proposal (RandomWalk (), d))
39
+
40
+ # Propose from a vector of proposals
41
+ function propose (
42
+ spl:: MetropolisHastings{<:AbstractArray} ,
43
+ model:: DensityModel
44
+ )
45
+ proposal = map (i -> propose (spl. proposal[i], model), 1 : length (spl. proposal))
46
+ return Transition (model, proposal)
47
+ end
48
+
49
+ function propose (
50
+ spl:: MetropolisHastings{<:AbstractArray} ,
51
+ model:: DensityModel ,
52
+ params_prev:: Transition
53
+ )
54
+ proposal = map (i -> propose (spl. proposal[i], model, params_prev. params[i]), 1 : length (spl. proposal))
55
+ return Transition (model, proposal)
56
+ end
57
+
58
+ # Make a proposal from one Proposal struct.
59
+ function propose (
60
+ spl:: MetropolisHastings{<:Proposal} ,
61
+ model:: DensityModel
62
+ )
63
+ proposal = propose (spl. proposal, model)
64
+ return Transition (model, proposal)
65
+ end
66
+
67
+ function propose (
68
+ spl:: MetropolisHastings{<:Proposal} ,
69
+ model:: DensityModel ,
70
+ params_prev:: Transition
71
+ )
72
+ proposal = propose (spl. proposal, model, params_prev. params)
73
+ return Transition (model, proposal)
74
+ end
75
+
76
+ # Make a proposal from a NamedTuple of Proposal.
77
+ function propose (
78
+ spl:: MetropolisHastings{<:NamedTuple} ,
79
+ model:: DensityModel
80
+ )
81
+ proposal = _propose (spl. proposal, model)
82
+ return Transition (model, proposal)
83
+ end
84
+
85
+ @generated function _propose (
86
+ proposals:: NamedTuple{names} ,
87
+ model:: DensityModel
88
+ ) where {names}
89
+ expr = Expr (:tuple )
90
+ map (names) do f
91
+ push! (expr. args, Expr (:(= ), f, :(propose (proposals.$ f, model)) ))
92
+ end
93
+ return expr
94
+ end
95
+
96
+ function propose (
97
+ spl:: MetropolisHastings{<:NamedTuple} ,
98
+ model:: DensityModel ,
99
+ params_prev:: Transition
100
+ )
101
+ proposal = _propose (spl. proposal, model, params_prev. params)
102
+ return Transition (model, proposal)
103
+ end
104
+
105
+ @generated function _propose (
106
+ proposals:: NamedTuple{names} ,
107
+ model:: DensityModel ,
108
+ params_prev:: NamedTuple
109
+ ) where {names}
110
+ expr = Expr (:tuple )
111
+ map (names) do f
112
+ push! (expr. args, Expr (:(= ), f, :(propose (proposals.$ f, model, params_prev.$ f)) ))
113
+ end
114
+ return expr
115
+ end
116
+
117
+
118
+ # Evaluate the likelihood of t conditional on t_cond.
119
+ function q (
120
+ spl:: MetropolisHastings{<:AbstractArray} ,
121
+ t:: Transition ,
122
+ t_cond:: Transition
123
+ )
124
+ return sum (map (i -> q (spl. proposal[i], t. params[i], t_cond. params[i]), 1 : length (spl. proposal)))
125
+ end
126
+
127
+ function q (
128
+ spl:: MetropolisHastings{<:Proposal} ,
129
+ t:: Transition ,
130
+ t_cond:: Transition
131
+ )
132
+ return q (spl. proposal, t. params, t_cond. params)
133
+ end
134
+
135
+ function q (
136
+ spl:: MetropolisHastings{<:NamedTuple} ,
137
+ t:: Transition ,
138
+ t_cond:: Transition
139
+ )
140
+ ks = keys (t. params)
141
+ total = 0.0
142
+
143
+ for k in ks
144
+ total += q (spl. proposal[k], t. params[k], t_cond. params[k])
145
+ end
146
+
147
+ return total
19
148
end
20
149
21
150
# Define the first step! function, which is called at the
@@ -28,7 +157,7 @@ function step!(
28
157
N:: Integer ;
29
158
kwargs...
30
159
)
31
- return Transition (model, spl . init_params )
160
+ return propose (spl, model )
32
161
end
33
162
34
163
# Define the other step functions. Returns a Transition containing
@@ -50,7 +179,7 @@ function step!(
50
179
q (spl, params_prev, params) - q (spl, params, params_prev)
51
180
52
181
# Decide whether to return the previous params or the new one.
53
- if log (rand (rng)) < min (α, 0.0 )
182
+ if log (rand (rng)) < min (0.0 , α )
54
183
return params
55
184
else
56
185
return params_prev
0 commit comments