-
-
Notifications
You must be signed in to change notification settings - Fork 303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add quadrature method #198
Changes from 8 commits
e47453f
57ac86b
c237c75
a57dfa7
482d6bc
cbbac78
5fc0915
1bb764f
1a711af
f69402e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ Compat 0.18.0 | |
StatsBase | ||
Optim 0.9.0 | ||
NLopt 0.3.4 | ||
FastGaussQuadrature 0.0.1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ https://lectures.quantecon.org/jl/finite_markov.html | |
|
||
import Optim | ||
import NLopt | ||
import FastGaussQuadrature: gausshermite | ||
import Distributions: pdf, Normal, quantile | ||
|
||
std_norm_cdf(x::T) where {T <: Real} = 0.5 * erfc(-x/sqrt(2)) | ||
|
@@ -232,7 +233,8 @@ types specifying the method for `discrete_var` | |
abstract type VAREstimationMethod end | ||
struct Even <: VAREstimationMethod end | ||
struct Quantile <: VAREstimationMethod end | ||
# immutable type Quadrature <: VAREstimationMethod end | ||
struct Quadrature <: VAREstimationMethod end | ||
|
||
|
||
doc""" | ||
|
||
|
@@ -263,9 +265,8 @@ P, X = discrete_var(b, B, Psi, Nm, n_moments, method, n_sigmas) | |
|
||
- `n_moments::Integer` : Desired number of moments to match. The default is 2. | ||
- `method::VAREstimationMethod` : Specify the method used to determine the grid | ||
points. Accepted inputs are `Even()` or `Quantile()`. | ||
Please see the paper for more details. | ||
NOTE: `Quadrature()` is not supported now. | ||
points. Accepted inputs are `Even()`, `Quantile()`, | ||
or `Quadrature()`. Please see the paper for more details. | ||
- `n_sigmas::Real` : If the `Even()` option is specified, `n_sigmas` is used to | ||
determine the number of unconditional standard deviations | ||
used to set the endpoints of the grid. The default is | ||
|
@@ -321,6 +322,9 @@ function discrete_var(b::Union{Real, AbstractVector}, | |
error("n_moments must be either 1 or a positive even integer") | ||
end | ||
|
||
# warning about persistency | ||
warn_persistency(B, method) | ||
|
||
# Compute polynomial moments of standard normal distribution | ||
gaussian_moment = zeros(n_moments) | ||
c = 1 | ||
|
@@ -333,7 +337,7 @@ function discrete_var(b::Union{Real, AbstractVector}, | |
A, C, mu, Sigma = standardize_var(b, B, Psi, M) | ||
|
||
# Construct 1-D grids | ||
y1D, y1Dbounds = construct_1D_grid(Sigma, Nm, M, n_sigmas, method) | ||
y1D, y1Dhelper = construct_1D_grid(Sigma, Nm, M, n_sigmas, method) | ||
|
||
# Construct all possible combinations of elements of the 1-D grids | ||
D = allcomb3(y1D')' | ||
|
@@ -355,7 +359,7 @@ function discrete_var(b::Union{Real, AbstractVector}, | |
for ii = 1:(Nm^M) | ||
|
||
# Construct prior guesses for maximum entropy optimizations | ||
q = construct_prior_guess(cond_mean[:, ii], Nm, y1D, y1Dbounds, method) | ||
q = construct_prior_guess(cond_mean[:, ii], Nm, y1D, y1Dhelper, method) | ||
|
||
# Make sure all elements of the prior are stricly positive | ||
q[q.<kappa] = kappa | ||
|
@@ -371,17 +375,17 @@ function discrete_var(b::Union{Real, AbstractVector}, | |
# Maximum entropy optimization | ||
if n_moments == 1 # match only 1 moment | ||
temp[:, jj], _, _ = discrete_approximation(y1D[jj, :], | ||
X -> (reshape(X, 1, Nm)-cond_mean[jj, ii])/scaling_factor[jj], | ||
X -> (X'-cond_mean[jj, ii])/scaling_factor[jj], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do ay of these operations need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmmm..., I don't think so. Does it answer your question? |
||
[0.0], q[jj, :], [0.0]) | ||
else # match 2 moments first | ||
p, lambda, moment_error = discrete_approximation(y1D[jj, :], | ||
X -> polynomial_moment(X, cond_mean[jj, ii], scaling_factor[jj], 2), | ||
[0; 1]./(scaling_factor[jj].^(1:2)), q[jj, :], lambda_guess) | ||
if norm(moment_error) > 1e-5 # if 2 moments fail, just match 1 moment | ||
if !(norm(moment_error) < 1e-5) # if 2 moments fail, just match 1 moment | ||
warn("Failed to match first 2 moments. Just matching 1.") | ||
temp[:, jj], _, _ = discrete_approximation(y1D[jj, :], | ||
X -> (X-cond_mean[jj,ii])/scaling_factor[jj], | ||
0, q[jj, :], 0) | ||
X -> (X'-cond_mean[jj, ii])/scaling_factor[jj], | ||
[0.0], q[jj, :], [0.0]) | ||
lambda_bar[(jj-1)*2+1:jj*2, ii] = zeros(2,1) | ||
elseif n_moments == 2 | ||
lambda_bar[(jj-1)*2+1:jj*2, ii] = lambda | ||
|
@@ -416,6 +420,27 @@ function discrete_var(b::Union{Real, AbstractVector}, | |
return MarkovChain(P, [X[:, i] for i in 1:Nm^M]) | ||
end | ||
|
||
""" | ||
check persistency when `method` is `Quadrature` and give warning if needed | ||
|
||
##### Arguments | ||
- `B::Union{Real, AbstractMatrix}` : impact coefficient | ||
- `method::VAREstimationMethod` : method for grid making | ||
|
||
##### Returns | ||
- `nothing` | ||
|
||
""" | ||
function warn_persistency(B::AbstractMatrix, ::Quadrature) | ||
if any(eig(B)[1] .> 0.9) | ||
warn("The quadrature method may perform poorly for highly persistent processes.") | ||
end | ||
return nothing | ||
end | ||
warn_persistency(B::Real, method::Quadrature) = warn_persistency(fill(B, 1, 1), method) | ||
warn_persistency(::Union{Real, AbstractMatrix}, ::Union{Even, Quantile}) = nothing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of |
||
|
||
|
||
""" | ||
|
||
return standerdized AR(1) representation | ||
|
@@ -508,6 +533,23 @@ construct_prior_guess(cond_mean::AbstractVector, Nm::Integer, | |
::AbstractMatrix, y1Dbounds::AbstractMatrix, method::Quantile) = | ||
cdf.(Normal.(repmat(cond_mean, 1, Nm), 1), y1Dbounds[:, 2:end]) - | ||
cdf.(Normal.(repmat(cond_mean, 1, Nm), 1), y1Dbounds[:, 1:end-1]) | ||
|
||
""" | ||
construct prior guess for quadrature grid method | ||
|
||
##### Arguments | ||
|
||
- `cond_mean::AbstractVector` : conditional Mean of each variable | ||
- `Nm::Integer` : number of grid points | ||
- `y1D::AbstractMatrix` : grid of variable | ||
- `weights::AbstractVector` : weights of grid `y1D` | ||
- `method::Quadrature` : method for grid making | ||
|
||
""" | ||
construct_prior_guess(cond_mean::AbstractVector, Nm::Integer, | ||
y1D::AbstractMatrix, weights::AbstractVector, method::Quadrature) = | ||
(pdf.(Normal.(repmat(cond_mean, 1, Nm), 1), y1D) ./ pdf.(Normal(0, 1), y1D)).* | ||
(weights'/sqrt(pi)) | ||
""" | ||
|
||
construct one-dimensional evenly spaced grid of states | ||
|
@@ -526,7 +568,7 @@ construct one-dimensional evenly spaced grid of states | |
- `nothing` : `nothing` of type `Void` | ||
|
||
""" | ||
function construct_1D_grid(Sigma::ScalarOrArray, Nm::Integer, | ||
function construct_1D_grid(Sigma::Union{Real, AbstractMatrix}, Nm::Integer, | ||
M::Integer, n_sigmas::Real, method::Even) | ||
min_sigmas = sqrt(minimum(eigfact(Sigma).values)) | ||
y1Drow = collect(linspace(-min_sigmas*n_sigmas, min_sigmas*n_sigmas, Nm))' | ||
|
@@ -540,7 +582,7 @@ construct one-dimensional quantile grid of states | |
|
||
##### Argument | ||
|
||
- `Sigma::ScalarOrArray` : variance-covariance matrix of the standardized process | ||
- `Sigma::AbstractMatrix` : variance-covariance matrix of the standardized process | ||
- `Nm::Integer` : number of grid points | ||
- `M::Integer` : number of variables (`M=1` corresponds to AR(1)) | ||
- `n_sigmas::Real` : number of standard error determining end points of grid | ||
|
@@ -567,6 +609,31 @@ construct_1D_grid(Sigma::Real, Nm::Integer, | |
|
||
""" | ||
|
||
construct one-dimensional quadrature grid of states | ||
|
||
##### Argument | ||
|
||
- `::ScalarOrArray` : not used | ||
- `Nm::Integer` : number of grid points | ||
- `M::Integer` : number of variables (`M=1` corresponds to AR(1)) | ||
- `n_sigmas::Real` : not used | ||
- `method::Quadrature` : method for grid making | ||
|
||
##### Return | ||
|
||
- `y1D` : `M x Nm` matrix of variable grid | ||
- `weights` : weights on each grid | ||
|
||
""" | ||
function construct_1D_grid(::ScalarOrArray, Nm::Integer, | ||
M::Integer, ::Real, method::Quadrature) | ||
nodes, weights = gausshermite(Nm) | ||
y1D = repmat(sqrt(2)*nodes', M, 1) | ||
return y1D, weights | ||
end | ||
|
||
""" | ||
|
||
Return combinations of each column of matrix `A`. | ||
It is simiplifying `allcomb2` by using `gridmake` from QuantEcon | ||
|
||
|
@@ -687,6 +754,9 @@ function discrete_approximation(D::AbstractVector, T::Function, TBar::AbstractVe | |
moment_error = grad/minimum_value | ||
return p, lambda_bar, moment_error | ||
end | ||
# discrete_approximation(D::AbstractVector, T::Function, TBar::Real, | ||
# q::AbstractVector=ones(N)/N, lambda0::Real=0) = | ||
# discrete_approximation(D, T, [TBar], q, [lambda0]) | ||
|
||
""" | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should change this to
using FastGaussQuadrature: gausshermite
. Import has two uses:gausshermite
, so we should just callusing
instead ofimport
.