Skip to content

Commit

Permalink
updated docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
bbejanov committed May 27, 2024
1 parent 7e2f434 commit 6f47062
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 6 deletions.
36 changes: 32 additions & 4 deletions src/simulate.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
##################################################################################
# This file is part of StateSpaceEcon.jl
# BSD 3-Clause License
# Copyright (c) 2020-2023, Bank of Canada
# Copyright (c) 2020-2024, Bank of Canada
# All rights reserved.
##################################################################################

Expand Down Expand Up @@ -92,16 +92,44 @@ Run a simulation for the given model, simulation plan and exogenous data.
deviation from the steady state. Default value is `false`.
* `anticipate::Bool` - set to `false` to instruct the solver that all shocks
are unanticipated by the agents. Default value is `true`.
* `solver::Symbol` - specify the simulation solver. Available options are
:stackedtime and :firstorder. If not given, default is :stackedtime.
* `verbose::Bool` - control whether or not to print progress information.
Default value is taken from `model.options`.
* `tol::Float64` - set the desired accuracy. Default value is taken from
`model.options`.
* `maxiter::Int` - algorithm fails if the desired accuracy is not reached
within this maximum number of iterations. Default value is taken from
`model.options`.
* `linesearch::Bool` - When `true` the Newton-Raphson is modified to include a
search along the descent direction for a sufficient decrease in f. It will
do this at each iteration. Default is `false`.
The following options are specific to the `:stackedtime` solver
* `sim_solver` - specify the non-linear solver to use. Available options are
- `:sim_nr` : (default) Newton-Raphson, with possible damping, see below.
- `:sim_lm` : Levenberg–Marquardt
- `:sim_gn` : Gauss-Newton
* `linesearch::Bool` - When `true` the Newton-Raphson is modified to include
a search along the descent direction for a sufficient decrease in f. It
will do this at each iteration. Default is `false`. (Superseded by the
`damping` option described below)
* `damping` - Specifies the style of damping that can be applied to the
Newton non-linear solver. Available options are:
- if not given the default behaviour is no damping, i.e. the damping
coefficient is set to 1.0 in each iteration.
- number: the damping coefficient will be set to the given number (rather than 1)
- vector of numbers: the damping coefficient in each iteration will be set
the number in the corresponding entry of the given vector. If there are
more Newton iterations than the length of the vector, the last entry
will be used until in the remaining iterations.
- `:linesearch` or `:armijo` : same as setting `linesearch=true`. The
Armijo rule is taken from "C.T.Kelly, Iterative Methods for Linear and
Nonlinear Equations, ch.8.1, p.137"
- `(:armijo, :sigma => 0.5, :alpha => 1e-4)` - override the default
parameters of the Armijo rule.
- `:br81` : (experimental) implements the damping algorithm in "Bank, R.E.,
Rose, D.J. Global approximate Newton methods. Numer. Math. 37, 279–295
(1981)."
- `(:br81, :rateK => 10, :delta => 0.1)` : override the default parameters
of the Bank & Rose (1981) algorithm.
"""
function simulate end
export simulate
Expand Down
41 changes: 41 additions & 0 deletions src/stackedtime/sim_nr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,47 @@ Solve the simulation problem using a Newton iteration with damping.
based on the Armijo rule
- `damping_bank_rose(delta=0.1, rateK=10.0)` implements a the damping
algorithm of Bank and Rose 1980
##### Conventions for custom damping function.
The `damping` callback function is expected to have the following signature:
function custom_damping(k::Int, λ::Float64, nR::Float64, R::AbstractVector{Float64},
J::Union{Nothing,Factorization,AbstractMatrix{Float64}}=nothing,
Δx::Union{Nothing,AbstractVector{Float64}}=nothing
)::Tuple{Bool, Float64}
# <your code goes here>
end
The first call will be with `k=0`, before the solver enters the Newton
iterations loop. This should allow any initialization and defaults to be setup.
In this call, the values of `R` and `nR` will equal the residual and its norm at
the initial guess. The norm used is `nR = norm(R, Inf)`. The `J` and `Δx` are
not available.
Each subsequent call will be with `k` between 1 and `maxiter` (possibly multiple
calls with the same `k`) will have the current `λ` (which equals the one returned by the
previous call), the current `R` (and its Inf-norm `nR`), the Jacobian `J` and
the Newton direction `Δx`.
The damping function must return a tuple `(accept, λ)`. The same Newton
iteration `k` will continue until the damping function returns `accept=true`,
after which will begin the next Newton iteration (`k=k+1``).
All calls with the same `k` will have the same `J` and `Δx` but different `R`
and `nR`. These equal the Jacobian (possibly factorized), computed at the
iteration guess, `xₖ` (not provided), and the Newton direction for the
iteration.
The first time the damping function is called for a given `k`, the `R` equals
the residual at `xₖ` and the Newton direction is `Δx = J \\ R` for the `R` at
this time.
Each subsequent call with the same `k` will have the residual, `R`, (and its
norm) computed at `xₖ - λ Δx` (not provided). Your callback must decide whether
to accept this step, by returning `(true, λ)`, or reject it and propose a new λ
to try, by returning `(false, new_λ)`. Don't return `(false, λ)` because this
will make it an infinite loop. Good luck!
"""
function sim_nr!(x::AbstractArray{Float64}, sd::StackedTimeSolverData,
maxiter::Int64, tol::Float64, verbose::Bool, damping::Function
Expand Down
5 changes: 3 additions & 2 deletions test/sim_solver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ rng = Random.default_rng()
issssolved(m) && (0 == check_sstate(m))
end
p01 = Plan(m, 1:100)
Random.seed!(rng, 0x1230ABCF)
data01 = steadystatedata(m, p01)
data01[begin:0U, m.variables] .+= randn(rng, m.maxlag, m.nvars)
data01[1U:10U, m.shocks] .+= randn(rng, 10, m.nshks)
Expand Down Expand Up @@ -48,6 +49,7 @@ end

rngsim = 2024Q1:2049Q4
p = Plan(m, rngsim)
Random.seed!(rng, 0x65439876)
exog = steadystatedata(m, p)
exog[firstdate(p).+(0:m.maxlag-1), m.variables] .*= exp.(0.5 * randn(rng, m.maxlag, m.nvars))
exog[rngsim[1:8], m.shocks] .= 0.8 * randn(rng, 8, m.nshks)
Expand Down Expand Up @@ -109,11 +111,10 @@ end
issssolved(m) && (0 == check_sstate(m))
end
exog = steadystatedata(m, p)
Random.seed!(rng, 0o007)
Random.seed!(rng, 0o007) #! this seed has been carefully selected!
exog[firstdate(p).+(0:m.maxlag-1), m.variables] .*= exp.(17 * randn(rng, m.maxlag, m.nvars))
exog[rngsim[1:8], m.shocks] .= 15 * randn(rng, 8, m.nshks)

# outp = @capture_err @test_throws SingularException simulate(m, p, exog, verbose=true, fctype=fcnatural)
outp = @capture_err sim = simulate(m, p, exog, verbose=true, fctype=fcnatural)
lines = split(outp, "\n"; keepempty=false)
# foreach(println, lines)
Expand Down

0 comments on commit 6f47062

Please sign in to comment.