Skip to content

Commit

Permalink
Fix regime-switching code to avoid assuming regimes has the :value ke…
Browse files Browse the repository at this point in the history
…y. Fix counting algorithm of n_parameters_regime_switching.
  • Loading branch information
chenwilliam77 committed Jun 22, 2020
1 parent 6042f9e commit 3db62cb
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/ModelConstructors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module ModelConstructors
# abstractmodel.jl
AbstractModel, description,
n_states, n_states_augmented, n_shocks_exogenous, n_shocks_expectational,
n_equilibrium_conditions, n_observables, n_parameters, n_parameters_steady_states,
n_equilibrium_conditions, n_observables, n_parameters, n_parameters_regime_switching, n_parameters_steady_states,
n_parameters_free, n_pseudo_observables, get_dict, get_key,
spec, subspec, saveroot, dataroot,
data_vintage, data_id, cond_vintage,
Expand Down
8 changes: 1 addition & 7 deletions src/abstractmodel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,7 @@ n_parameters_steady_state(m::AbstractModel) = length(m.steady_state)
n_parameters_free(m::AbstractModel) = sum([!α.fixed for α in m.parameters])

function n_parameters_regime_switching(m::AbstractModel)
base_num = n_parameters(m)
for para in m.parameters
if !isempty(para.regimes)
base_num += length(para.regimes[:value])
end
end
return base_num
return n_parameters_regime_switching(m.parameters)
end

"""
Expand Down
55 changes: 39 additions & 16 deletions src/parameters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1029,12 +1029,14 @@ function update!(pvec::ParameterVector, values::Vector{T};
i = length(pvec)
for para in pvec
if !isempty(para.regimes)
for key in keys(para.regimes[:value])
if key == 1
set_regime_val!(para, key, para.value)
else
i += 1
set_regime_val!(para, key, values[i])
if haskey(para.regimes, :value)
for key in keys(para.regimes[:value])
if key == 1
set_regime_val!(para, key, para.value)
else
i += 1
set_regime_val!(para, key, values[i])
end
end
end
end
Expand Down Expand Up @@ -1211,19 +1213,21 @@ function rand_regime_switching(p::Vector{AbstractParameter{Float64}})
end
for para in p
if !isempty(para.regimes)
for regime in keys(para.regimes[:value])
if regime != 1
one_draw = if para.fixed
para.value
else
# Resample until all prior draws are within the value bounds
prio = rand(para.prior.value)
while !(para.valuebounds[1] < prio < para.valuebounds[2])
if haskey(para.regimes, :value)
for regime in keys(para.regimes[:value])
if regime != 1
one_draw = if para.fixed
para.value
else
# Resample until all prior draws are within the value bounds
prio = rand(para.prior.value)
while !(para.valuebounds[1] < prio < para.valuebounds[2])
prio = rand(para.prior.value)
end
prio
end
prio
push!(draw, one_draw)
end
push!(draw, one_draw)
end
end
end
Expand Down Expand Up @@ -1298,3 +1302,22 @@ function describe_prior(param::Parameter)
error("Parameter must either be fixed or have non-null prior: " * string(param.key))
end
end

"""
```
function n_parameters_regime_switching(p::ParameterVector)
```
calculates the total number of parameters in `p` across all regimes.
"""
function n_parameters_regime_switching(p::ParameterVector)
base_num = length(p)
for para in p
if !isempty(para.regimes)
if haskey(para.regimes, :value)
base_num += length(para.regimes[:value]) - 1 # first regime is already counted
end
end
end
return base_num
end
49 changes: 49 additions & 0 deletions src/regimes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,52 @@ function toggle_regime!(p::Parameter{S}, i::Int64) where S <: Float64
end
end
end

"""
```
get_values(pvec::ParameterVector{S}; regime_switching::Bool = true) where {S <: Real}
```
constructs a vector of the underlying values in a `ParameterVector`, including
if there are regime-switching values.
"""
function get_values(pvec::ParameterVector{S}; regime_switching::Bool = true) where {S <: Real}

if regime_switching # Check if regime switching occurs
np_reg = n_parameters_regime_switching(pvec)
np = length(pvec)
if np == np_reg # No regime-switching
vals = map(x -> x.value, pvec.parameters)
else
vals = Vector{S}(undef, np_reg)

# An initial pass to find regime 1 values
for i in 1:np
if isempty(pvec[i].regimes)
vals[i] = pvec[i].value
elseif haskey(pvec[i].regimes, :value)
vals[i] = pvec[i].regimes[:value][1]
end
end

# A second loop to add in the extra regimes
ct = np # a counter to assist us
for i in 1:np
if !isempty(pvec[i].regimes)
if haskey(pvec[i].regimes, :value)
for j in 1:length(pvec[i].regimes[:value])
if j > 1
ct += 1
vals[ct] = pvec[i].regimes[:value][j]
end
end
end
end
end
end
else # Regime switching doesn't occur, so just directly map
vals = map(x -> x.value, pvec)
end

return vals
end
10 changes: 9 additions & 1 deletion test/regimes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ using Test, ModelConstructors

u = parameter(:bloop, 2.5230, (1e-8, 5.), (1e-8, 5.), ModelConstructors.SquareRoot(); fixed = true)
ModelConstructors.set_regime_val!(u, 1, 2.5230)

# CURRENTLY ONLY TESTS VALUE SWITCHING, NO REGIME SWITCHING IN OTHER CASES
@info "The following error 'get_regime_val(), Input Error: No regime 3' is expected."
@testset "Regime switching with parameters" begin
@test_throws ParamBoundsError ModelConstructors.set_regime_val!(u, 2, 0.)
ModelConstructors.set_regime_val!(u, 2, 0.; override_bounds = true)
uvec = ParameterVector{Float64}(undef, 2)
uvec[1] = u
uvec[2] = u

@test !isempty(u.regimes)
@test u.regimes[:value][1] == 2.5230
Expand All @@ -23,6 +26,11 @@ ModelConstructors.set_regime_val!(u, 1, 2.5230)
@test u.value == 2.5230
@test ModelConstructors.regime_val(u, 1) == 2.5230
@test ModelConstructors.regime_val(u, 2) == 0.

@test n_parameters_regime_switching(uvec) == 4
ModelConstructors.toggle_regime!(u, 1)
@test ModelConstructors.get_values(uvec; regime_switching = false) == [2.5230, 2.5230]
@test ModelConstructors.get_values(uvec) == [2.5230, 2.5230, 0., 0.]
end

nothing

0 comments on commit 3db62cb

Please sign in to comment.