From 3db62cb331b871765421a7c62b2ecafd7f6634c0 Mon Sep 17 00:00:00 2001 From: William Chen Date: Mon, 22 Jun 2020 16:30:52 -0400 Subject: [PATCH] Fix regime-switching code to avoid assuming regimes has the :value key. Fix counting algorithm of n_parameters_regime_switching. --- src/ModelConstructors.jl | 2 +- src/abstractmodel.jl | 8 +----- src/parameters.jl | 55 ++++++++++++++++++++++++++++------------ src/regimes.jl | 49 +++++++++++++++++++++++++++++++++++ test/regimes.jl | 10 +++++++- 5 files changed, 99 insertions(+), 25 deletions(-) diff --git a/src/ModelConstructors.jl b/src/ModelConstructors.jl index e521ad3..6ce43c7 100644 --- a/src/ModelConstructors.jl +++ b/src/ModelConstructors.jl @@ -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, diff --git a/src/abstractmodel.jl b/src/abstractmodel.jl index 6a95838..6afdfb0 100644 --- a/src/abstractmodel.jl +++ b/src/abstractmodel.jl @@ -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 """ diff --git a/src/parameters.jl b/src/parameters.jl index 8bd4bca..e5ee208 100644 --- a/src/parameters.jl +++ b/src/parameters.jl @@ -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 @@ -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 @@ -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 diff --git a/src/regimes.jl b/src/regimes.jl index aab5242..caf4270 100644 --- a/src/regimes.jl +++ b/src/regimes.jl @@ -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 diff --git a/test/regimes.jl b/test/regimes.jl index f1d4c50..51b5ab9 100644 --- a/test/regimes.jl +++ b/test/regimes.jl @@ -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 @@ -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