@@ -12,16 +12,16 @@ x = (a = 1.0, b=3.8)
12
12
The proposal would be
13
13
14
14
```julia
15
- proposal = (a=Proposal(Static(), Normal(0,1)), b=Proposal(Static(), Normal(0,1)))
15
+ proposal = (a=StaticProposal( Normal(0,1)), b=StaticProposal( Normal(0,1)))
16
16
````
17
17
18
- Other allowed proposal styles are
18
+ Other allowed proposals are
19
19
20
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))
21
+ p1 = StaticProposal( Normal(0,1))
22
+ p2 = StaticProposal( [Normal(0,1), InverseGamma(2,3)])
23
+ p3 = StaticProposal( a=Normal(0,1), b=InverseGamma(2,3))
24
+ p4 = StaticProposal( (x=1.0) -> Normal(x, 1))
25
25
```
26
26
27
27
The sampler is constructed using
@@ -41,98 +41,92 @@ used if `chain_type=Chains`.
41
41
types are `chain_type=Chains` if `MCMCChains` is imported, or
42
42
`chain_type=StructArray` if `StructArrays` is imported.
43
43
"""
44
- mutable struct MetropolisHastings{D} <: Metropolis
45
- proposal :: D
44
+ struct MetropolisHastings{D} <: Metropolis
45
+ proposal:: D
46
46
end
47
47
48
- StaticMH (d) = MetropolisHastings (Proposal (Static (), d))
49
- RWMH (d) = MetropolisHastings (Proposal (RandomWalk (), d))
48
+ StaticMH (d) = MetropolisHastings (StaticProposal (d))
49
+ RWMH (d) = MetropolisHastings (RandomWalkProposal (d))
50
+
51
+ # default function without RNG
52
+ propose (spl:: MetropolisHastings , args... ) = propose (Random. GLOBAL_RNG, spl, args... )
50
53
51
54
# Propose from a vector of proposals
52
55
function propose (
56
+ rng:: Random.AbstractRNG ,
53
57
spl:: MetropolisHastings{<:AbstractArray} ,
54
58
model:: DensityModel
55
59
)
56
- proposal = map (i -> propose (spl . proposal[i], model), 1 : length ( spl. proposal) )
60
+ proposal = map (p -> propose (rng, p, model), spl. proposal)
57
61
return Transition (model, proposal)
58
62
end
59
63
60
64
function propose (
65
+ rng:: Random.AbstractRNG ,
61
66
spl:: MetropolisHastings{<:AbstractArray} ,
62
67
model:: DensityModel ,
63
68
params_prev:: Transition
64
69
)
65
- proposal = map (i -> propose (spl. proposal[i], model, params_prev. params[i]), 1 : length (spl. proposal))
70
+ proposal = map (spl. proposal, params_prev. params) do p, params
71
+ propose (rng, p, model, params)
72
+ end
66
73
return Transition (model, proposal)
67
74
end
68
75
69
76
# Make a proposal from one Proposal struct.
70
77
function propose (
78
+ rng:: Random.AbstractRNG ,
71
79
spl:: MetropolisHastings{<:Proposal} ,
72
80
model:: DensityModel
73
81
)
74
- proposal = propose (spl. proposal, model)
82
+ proposal = propose (rng, spl. proposal, model)
75
83
return Transition (model, proposal)
76
84
end
77
85
78
86
function propose (
87
+ rng:: Random.AbstractRNG ,
79
88
spl:: MetropolisHastings{<:Proposal} ,
80
89
model:: DensityModel ,
81
90
params_prev:: Transition
82
91
)
83
- proposal = propose (spl. proposal, model, params_prev. params)
92
+ proposal = propose (rng, spl. proposal, model, params_prev. params)
84
93
return Transition (model, proposal)
85
94
end
86
95
87
96
# Make a proposal from a NamedTuple of Proposal.
88
97
function propose (
98
+ rng:: Random.AbstractRNG ,
89
99
spl:: MetropolisHastings{<:NamedTuple} ,
90
100
model:: DensityModel
91
101
)
92
- proposal = _propose (spl. proposal, model)
93
- return Transition (model, proposal)
94
- end
95
-
96
- @generated function _propose (
97
- proposals:: NamedTuple{names} ,
98
- model:: DensityModel
99
- ) where {names}
100
- expr = Expr (:tuple )
101
- map (names) do f
102
- push! (expr. args, Expr (:(= ), f, :(propose (proposals.$ f, model)) ))
102
+ proposal = map (spl. proposal) do p
103
+ propose (rng, p, model)
103
104
end
104
- return expr
105
+ return Transition (model, proposal)
105
106
end
106
107
107
108
function propose (
109
+ rng:: Random.AbstractRNG ,
108
110
spl:: MetropolisHastings{<:NamedTuple} ,
109
111
model:: DensityModel ,
110
112
params_prev:: Transition
111
113
)
112
- proposal = _propose (spl. proposal, model, params_prev. params)
113
- return Transition (model, proposal)
114
- end
115
-
116
- @generated function _propose (
117
- proposals:: NamedTuple{names} ,
118
- model:: DensityModel ,
119
- params_prev:: NamedTuple
120
- ) where {names}
121
- expr = Expr (:tuple )
122
- map (names) do f
123
- push! (expr. args, Expr (:(= ), f, :(propose (proposals.$ f, model, params_prev.$ f)) ))
114
+ proposal = map (spl. proposal, params_prev. params) do p, params
115
+ propose (rng, p, model, params)
124
116
end
125
- return expr
117
+ return Transition (model, proposal)
126
118
end
127
119
128
-
129
120
# Evaluate the likelihood of t conditional on t_cond.
130
121
function q (
131
122
spl:: MetropolisHastings{<:AbstractArray} ,
132
123
t:: Transition ,
133
124
t_cond:: Transition
134
125
)
135
- return sum (map (i -> q (spl. proposal[i], t. params[i], t_cond. params[i]), 1 : length (spl. proposal)))
126
+ # mapreduce with multiple iterators requires Julia 1.2 or later
127
+ return mapreduce (+ , 1 : length (spl. proposal)) do i
128
+ q (spl. proposal[i], t. params[i], t_cond. params[i])
129
+ end
136
130
end
137
131
138
132
function q (
@@ -148,21 +142,17 @@ function q(
148
142
t:: Transition ,
149
143
t_cond:: Transition
150
144
)
151
- ks = keys (t. params)
152
- total = 0.0
153
-
154
- for k in ks
155
- total += q (spl. proposal[k], t. params[k], t_cond. params[k])
145
+ # mapreduce with multiple iterators requires Julia 1.2 or later
146
+ return mapreduce (+ , keys (t. params)) do k
147
+ q (spl. proposal[k], t. params[k], t_cond. params[k])
156
148
end
157
-
158
- return total
159
149
end
160
150
161
151
# Define the first step! function, which is called at the
162
152
# beginning of sampling. Return the initial parameter used
163
153
# to define the sampler.
164
154
function AbstractMCMC. step! (
165
- rng:: AbstractRNG ,
155
+ rng:: Random. AbstractRNG ,
166
156
model:: DensityModel ,
167
157
spl:: MetropolisHastings ,
168
158
N:: Integer ,
@@ -171,7 +161,7 @@ function AbstractMCMC.step!(
171
161
kwargs...
172
162
)
173
163
if init_params === nothing
174
- return propose (spl, model)
164
+ return propose (rng, spl, model)
175
165
else
176
166
return Transition (model, init_params)
177
167
end
@@ -181,22 +171,22 @@ end
181
171
# either a new proposal (if accepted) or the previous proposal
182
172
# (if not accepted).
183
173
function AbstractMCMC. step! (
184
- rng:: AbstractRNG ,
174
+ rng:: Random. AbstractRNG ,
185
175
model:: DensityModel ,
186
176
spl:: MetropolisHastings ,
187
177
:: Integer ,
188
178
params_prev:: Transition ;
189
179
kwargs...
190
180
)
191
181
# Generate a new proposal.
192
- params = propose (spl, model, params_prev)
182
+ params = propose (rng, spl, model, params_prev)
193
183
194
184
# Calculate the log acceptance probability.
195
- α = logdensity (model, params) - logdensity (model, params_prev) +
185
+ logα = logdensity (model, params) - logdensity (model, params_prev) +
196
186
q (spl, params_prev, params) - q (spl, params, params_prev)
197
187
198
188
# Decide whether to return the previous params or the new one.
199
- if log ( rand ( rng)) < min ( 0.0 , α)
189
+ if - Random . randexp ( rng) < logα
200
190
return params
201
191
else
202
192
return params_prev
0 commit comments