├── source ├── rst │ ├── _static │ ├── zreferences.rst │ ├── search.rst │ ├── index_classic_linear_models.rst │ ├── index_tools_and_techniques.rst │ ├── index_asset_pricing.rst │ ├── index_lq_control.rst │ ├── about_lectures.rst │ ├── index_multi_agent_models.rst │ ├── index_hs_recursive_models.rst │ ├── index_time_series_models.rst │ ├── index_dynamic_programming_squared.rst │ ├── 404.rst │ ├── status.rst │ ├── index_toc.rst │ ├── troubleshooting.rst │ ├── index.rst │ ├── .ipynb_checkpoints │ │ ├── Untitled-checkpoint.ipynb │ │ └── changethis-checkpoint.ipynb │ ├── lucas_asset_pricing_dles.rst │ ├── irfs_in_hall_model.rst │ ├── permanent_income_dles.rst │ ├── tax_smoothing_3.rst │ ├── rosen_schooling_model.rst │ ├── hs_invertibility_example.rst │ └── muth_kalman.rst └── _static │ ├── qe-logo-large.png │ ├── lecture_specific │ ├── amss3 │ │ ├── amss3_g1.png │ │ ├── amss3_g2.png │ │ └── amss3_g3.png │ ├── robustness │ │ ├── kg.png │ │ ├── kg0.png │ │ └── kg_small_theta.png │ ├── coase │ │ ├── allocation.png │ │ ├── subcontracting.png │ │ ├── allocation.tex │ │ └── subcontracting.tex │ ├── lqramsey │ │ └── firenze.pdf │ ├── estspec │ │ ├── periodogram1.png │ │ ├── window_smoothing.png │ │ └── ar_smoothed_periodogram.png │ ├── arma │ │ └── time_series_book.pdf │ ├── markov_perf │ │ ├── judd_fig1.png │ │ ├── judd_fig2.png │ │ ├── mpe_vs_monopolist.png │ │ └── duopoly_mpe.py │ ├── matsuyama │ │ ├── matsuyama_14.png │ │ └── matsuyama_18.png │ ├── troubleshooting │ │ └── launch.png │ ├── orth_proj │ │ ├── orth_proj_def1.png │ │ ├── orth_proj_def2.png │ │ ├── orth_proj_def3.png │ │ ├── orth_proj_thm1.png │ │ ├── orth_proj_thm2.png │ │ ├── orth_proj_thm3.png │ │ ├── orth_proj_def1.tex │ │ ├── orth_proj_def2.tex │ │ ├── orth_proj_def3.tex │ │ ├── orth_proj_thm1.tex │ │ ├── orth_proj_thm2.tex │ │ └── orth_proj_thm3.tex │ ├── arellano │ │ ├── arellano_bond_prices.png │ │ ├── arellano_time_series.png │ │ ├── arellano_value_funcs.png │ │ ├── arellano_bond_prices_2.png │ │ └── arellano_default_probs.png │ ├── lucas_model │ │ ├── solution_mass_ex2.png │ │ └── lucastree.py │ ├── stationary_densities │ │ ├── ECTA6180.pdf │ │ ├── solution_statd_ex1.png │ │ └── solution_statd_ex2.png │ ├── discrete_dp │ │ ├── finite_dp_simple_og.png │ │ └── finite_dp_simple_og2.png │ ├── opt_tax_recur │ │ ├── log_utility.py │ │ ├── crra_utility.py │ │ ├── sequential_allocation.py │ │ └── recursive_allocation.py │ ├── amss2 │ │ ├── log_utility.py │ │ ├── crra_utility.py │ │ ├── utilities.py │ │ ├── sequential_allocation.py │ │ └── recursive_allocation.py │ ├── amss │ │ └── recursive_allocation.py │ └── lu_tricks │ │ └── control_and_filter.py │ ├── includes │ ├── lecture_howto_py.raw │ └── header.raw │ └── downloads │ └── amss_environment.yml ├── requirements.txt ├── theme └── minimal │ ├── static │ ├── img │ │ ├── py-logo.png │ │ ├── qe-logo.png │ │ ├── search-icon.png │ │ ├── sloan_logo.png │ │ ├── code-block-fade.png │ │ └── powered-by-NumFOCUS-orange.svg │ ├── sloan_logo.png │ ├── css │ │ └── qe.python.css │ └── js │ │ └── base.js │ └── templates │ ├── error_report_template.html │ └── html.tpl ├── README.md ├── .gitignore ├── environment.yml ├── scripts ├── linkchecker-test.sh ├── execution-test.sh └── build-website.sh ├── .github └── workflows │ ├── ci.yml │ ├── coverage.yml │ ├── preview.yml │ └── cache.yml ├── LICENSE └── Makefile /source/rst/_static: -------------------------------------------------------------------------------- 1 | ../_static -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | sphinxcontrib-bibtex 2 | sphinxcontrib-jupyter 3 | quantecon -------------------------------------------------------------------------------- /source/_static/qe-logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/qe-logo-large.png -------------------------------------------------------------------------------- /theme/minimal/static/img/py-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/theme/minimal/static/img/py-logo.png -------------------------------------------------------------------------------- /theme/minimal/static/img/qe-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/theme/minimal/static/img/qe-logo.png -------------------------------------------------------------------------------- /theme/minimal/static/sloan_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/theme/minimal/static/sloan_logo.png -------------------------------------------------------------------------------- /theme/minimal/static/img/search-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/theme/minimal/static/img/search-icon.png -------------------------------------------------------------------------------- /theme/minimal/static/img/sloan_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/theme/minimal/static/img/sloan_logo.png -------------------------------------------------------------------------------- /source/rst/zreferences.rst: -------------------------------------------------------------------------------- 1 | .. _references: 2 | 3 | ********** 4 | References 5 | ********** 6 | 7 | .. bibliography:: /_static/quant-econ.bib 8 | :cited: 9 | -------------------------------------------------------------------------------- /theme/minimal/static/img/code-block-fade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/theme/minimal/static/img/code-block-fade.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/amss3/amss3_g1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/amss3/amss3_g1.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/amss3/amss3_g2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/amss3/amss3_g2.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/amss3/amss3_g3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/amss3/amss3_g3.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/robustness/kg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/robustness/kg.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/robustness/kg0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/robustness/kg0.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/coase/allocation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/coase/allocation.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/lqramsey/firenze.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/lqramsey/firenze.pdf -------------------------------------------------------------------------------- /source/_static/lecture_specific/coase/subcontracting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/coase/subcontracting.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/estspec/periodogram1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/estspec/periodogram1.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/arma/time_series_book.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/arma/time_series_book.pdf -------------------------------------------------------------------------------- /source/_static/lecture_specific/markov_perf/judd_fig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/markov_perf/judd_fig1.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/markov_perf/judd_fig2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/markov_perf/judd_fig2.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/matsuyama/matsuyama_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/matsuyama/matsuyama_14.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/matsuyama/matsuyama_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/matsuyama/matsuyama_18.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/troubleshooting/launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/troubleshooting/launch.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/estspec/window_smoothing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/estspec/window_smoothing.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_def1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/orth_proj/orth_proj_def1.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_def2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/orth_proj/orth_proj_def2.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_def3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/orth_proj/orth_proj_def3.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_thm1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/orth_proj/orth_proj_thm1.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_thm2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/orth_proj/orth_proj_thm2.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_thm3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/orth_proj/orth_proj_thm3.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/robustness/kg_small_theta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/robustness/kg_small_theta.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/arellano/arellano_bond_prices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/arellano/arellano_bond_prices.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/arellano/arellano_time_series.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/arellano/arellano_time_series.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/arellano/arellano_value_funcs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/arellano/arellano_value_funcs.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/lucas_model/solution_mass_ex2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/lucas_model/solution_mass_ex2.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/markov_perf/mpe_vs_monopolist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/markov_perf/mpe_vs_monopolist.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/stationary_densities/ECTA6180.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/stationary_densities/ECTA6180.pdf -------------------------------------------------------------------------------- /source/_static/lecture_specific/arellano/arellano_bond_prices_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/arellano/arellano_bond_prices_2.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/arellano/arellano_default_probs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/arellano/arellano_default_probs.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/discrete_dp/finite_dp_simple_og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/discrete_dp/finite_dp_simple_og.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/discrete_dp/finite_dp_simple_og2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/discrete_dp/finite_dp_simple_og2.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/estspec/ar_smoothed_periodogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/estspec/ar_smoothed_periodogram.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lecture-python-advanced 2 | Source files for https://python-advanced.quantecon.org 3 | 4 | For a guide on contributing to this repository click [here](https://quantecon.org/contribute-lectures/) 5 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/stationary_densities/solution_statd_ex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/stationary_densities/solution_statd_ex1.png -------------------------------------------------------------------------------- /source/_static/lecture_specific/stationary_densities/solution_statd_ex2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/lecture-python-advanced/master/source/_static/lecture_specific/stationary_densities/solution_statd_ex2.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | dask-worker-space/ 3 | [._]*.s[a-v][a-z] 4 | [._]*.sw[a-p] 5 | [._]s[a-v][a-z] 6 | [._]sw[a-p] 7 | .DS_Store 8 | .DS_Store? 9 | **/.DS_Store 10 | venv/ 11 | theme/lecture-python-advanced.theme 12 | .prettierignore -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: lecture-python-advanced 2 | channels: 3 | - default 4 | dependencies: 5 | - pip 6 | - python=3.8 7 | - anaconda=2020.07 8 | - pip: 9 | - jupinx 10 | - sphinxcontrib-jupyter 11 | - sphinxcontrib-bibtex==1.0 12 | - quantecon 13 | - joblib 14 | -------------------------------------------------------------------------------- /source/_static/includes/lecture_howto_py.raw: -------------------------------------------------------------------------------- 1 | .. raw:: html 2 | 3 |
4 | 5 | QuantEcon 6 | 7 |
8 | -------------------------------------------------------------------------------- /source/_static/includes/header.raw: -------------------------------------------------------------------------------- 1 | .. raw:: html 2 | 3 |
4 | 5 | QuantEcon 6 | 7 |
8 | -------------------------------------------------------------------------------- /source/rst/search.rst: -------------------------------------------------------------------------------- 1 | .. _search: 2 | 3 | ********** 4 | Search 5 | ********** 6 | 7 | .. raw:: html 8 | 9 | 10 | 11 |
-------------------------------------------------------------------------------- /source/rst/index_classic_linear_models.rst: -------------------------------------------------------------------------------- 1 | .. _classic_linear_models: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | ********************************************** 6 | Classic Linear Models 7 | ********************************************** 8 | 9 | 10 | .. only:: html 11 | 12 | Lectures 13 | ******** 14 | 15 | 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | 20 | von_neumann_model 21 | -------------------------------------------------------------------------------- /source/rst/index_tools_and_techniques.rst: -------------------------------------------------------------------------------- 1 | .. _tools_and_techniques: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | *************************************** 6 | Tools and Techniques 7 | *************************************** 8 | 9 | .. only:: html 10 | 11 | Lectures 12 | ******** 13 | 14 | 15 | 16 | .. toctree:: 17 | :maxdepth: 2 18 | 19 | orth_proj 20 | stationary_densities 21 | muth_kalman 22 | discrete_dp 23 | -------------------------------------------------------------------------------- /source/rst/index_asset_pricing.rst: -------------------------------------------------------------------------------- 1 | .. _asset_pricing: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | ********************************************** 6 | Asset Pricing and Finance 7 | ********************************************** 8 | 9 | 10 | .. only:: html 11 | 12 | Lectures 13 | ******** 14 | 15 | 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | 20 | lucas_model 21 | black_litterman 22 | BCG_complete_mkts 23 | BCG_incomplete_mkts 24 | -------------------------------------------------------------------------------- /scripts/linkchecker-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MODIFIED_FILES="$1" 4 | 5 | RST_FILES="" 6 | for F in $MODIFIED_FILES 7 | do 8 | if [[ $F == *.rst ]] 9 | then 10 | RST_FILES="$RST_FILES $F" 11 | fi 12 | done 13 | echo "List of Changed RST Files: $RST_FILES" 14 | if [ -z "$RST_FILES" ]; then 15 | echo "No RST Files have changed -- nothing to do in this PR" 16 | else 17 | RST_FILES="$RST_FILES source/rst/index_toc.rst" 18 | make linkcheck FILES="$RST_FILES" 19 | fi -------------------------------------------------------------------------------- /source/rst/index_lq_control.rst: -------------------------------------------------------------------------------- 1 | .. _lq_dynamic_programming: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | ********** 6 | LQ Control 7 | ********** 8 | 9 | 10 | .. only:: html 11 | 12 | Lectures 13 | ******** 14 | 15 | 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | 20 | cons_news 21 | smoothing 22 | smoothing_tax 23 | robustness 24 | markov_jump_lq 25 | tax_smoothing_1 26 | tax_smoothing_2 27 | tax_smoothing_3 28 | lqramsey 29 | -------------------------------------------------------------------------------- /source/_static/downloads/amss_environment.yml: -------------------------------------------------------------------------------- 1 | name: amss 2 | channels: 3 | - default 4 | - conda-forge 5 | dependencies: 6 | - pip 7 | - python 8 | - jupyter 9 | - jupyterlab 10 | - nbconvert 11 | - pandoc 12 | - pandas 13 | - numba 14 | - scipy=1.4.1 15 | - numpy 16 | - matplotlib 17 | - networkx 18 | - sphinx=2.4.4 19 | - interpolation 20 | - seaborn 21 | - pip: 22 | - sphinxcontrib-jupyter 23 | - sphinxcontrib-bibtex 24 | - quantecon 25 | - joblib 26 | -------------------------------------------------------------------------------- /source/rst/about_lectures.rst: -------------------------------------------------------------------------------- 1 | .. _about_lectures: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | .. highlight:: python3 6 | 7 | ********************* 8 | About these Lectures 9 | ********************* 10 | 11 | This is one of a series of online texts on modern quantitative economics 12 | and programming with Python. This is the third text in the series, which 13 | focuses on advanced topics. 14 | 15 | For an overview of the series, see `this page `__ -------------------------------------------------------------------------------- /source/rst/index_multi_agent_models.rst: -------------------------------------------------------------------------------- 1 | .. _multi_agent_models: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | *************************************** 6 | Multiple Agent Models 7 | *************************************** 8 | 9 | These lectures look at important economic models that also illustrate common 10 | equilibrium concepts. 11 | 12 | .. only:: html 13 | 14 | Lectures 15 | ******** 16 | 17 | 18 | 19 | .. toctree:: 20 | :maxdepth: 2 21 | 22 | rob_markov_perf 23 | arellano 24 | matsuyama 25 | coase 26 | -------------------------------------------------------------------------------- /source/rst/index_hs_recursive_models.rst: -------------------------------------------------------------------------------- 1 | .. _HS_recursive_models: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | *************************** 6 | Dynamic Linear Economies 7 | *************************** 8 | 9 | 10 | .. only:: html 11 | 12 | Lectures 13 | ******** 14 | 15 | 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | 20 | hs_recursive_models 21 | growth_in_dles 22 | lucas_asset_pricing_dles 23 | irfs_in_hall_model 24 | permanent_income_dles 25 | rosen_schooling_model 26 | cattle_cycles 27 | hs_invertibility_example 28 | -------------------------------------------------------------------------------- /source/rst/index_time_series_models.rst: -------------------------------------------------------------------------------- 1 | .. include:: /_static/includes/header.raw 2 | 3 | *************************************** 4 | Time Series Models 5 | *************************************** 6 | 7 | These lectures look at important concepts in time series that are used in economics 8 | 9 | .. only:: html 10 | 11 | Lectures 12 | ******** 13 | 14 | 15 | 16 | .. toctree:: 17 | :maxdepth: 2 18 | 19 | arma 20 | estspec 21 | additive_functionals 22 | lu_tricks 23 | classical_filtering 24 | knowing_forecasts_of_others 25 | 26 | 27 | -------------------------------------------------------------------------------- /source/rst/index_dynamic_programming_squared.rst: -------------------------------------------------------------------------------- 1 | .. _topics_in_economic_dynamics: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | *************************************** 6 | Dynamic Programming Squared 7 | *************************************** 8 | 9 | Here we look at models in which a value function for one Bellman equation has as an argument the value function for another Bellman equation 10 | 11 | .. only:: html 12 | 13 | Lectures 14 | ******** 15 | 16 | 17 | 18 | .. toctree:: 19 | :maxdepth: 2 20 | 21 | dyn_stack 22 | calvo 23 | opt_tax_recur 24 | amss 25 | amss2 26 | amss3 27 | chang_ramsey 28 | chang_credible 29 | 30 | -------------------------------------------------------------------------------- /theme/minimal/templates/error_report_template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Jupyter Script Test Execution - Error Report 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Error Report - Generated {DATETIME}

11 | 12 |

13 | Overview 14 |

15 | 16 | {ERROR_SUMMARY} 17 | 18 | {NOTEBOOK_LOOP} 19 | 20 | 21 | -------------------------------------------------------------------------------- /source/rst/404.rst: -------------------------------------------------------------------------------- 1 | .. _404: 2 | 3 | *************** 4 | Page Not Found 5 | *************** 6 | 7 | .. raw:: html 8 | 9 | 10 | 11 | 12 | We couldn’t find the page you were looking for. 13 | 14 | Please check the URL or try a link below: 15 | 16 | * `Home `_ 17 | * `QuantEcon `_ 18 | * `Quantitative Economics with Python `_ 19 | * `Quantitative Economics with Julia `_ 20 | * `QuantEcon DataScience `_ 21 | * `Forum `_ 22 | * `Contact us `_ -------------------------------------------------------------------------------- /source/rst/status.rst: -------------------------------------------------------------------------------- 1 | .. _status: 2 | 3 | ************** 4 | Lecture Status 5 | ************** 6 | 7 | .. raw:: html 8 | 9 | 10 |

The badges below show which lectures are currently passing their execution test (i.e., executing without errors).

11 |

The lecture code checker was last run: N/A

12 |
13 |
14 |
15 |

The code checker is run on a t2.small Amazon EC2 instance. This is an instance with a single CPU and 2 GiB of Memory.

16 |

You should achieve faster run times on many common laptops and desktops.

-------------------------------------------------------------------------------- /source/_static/lecture_specific/opt_tax_recur/log_utility.py: -------------------------------------------------------------------------------- 1 | log_util_data = [ 2 | ('β', float64), 3 | ('ψ', float64) 4 | ] 5 | 6 | @jitclass(log_util_data) 7 | class LogUtility: 8 | 9 | def __init__(self, 10 | β=0.9, 11 | ψ=0.69): 12 | 13 | self.β, self.ψ = β, ψ 14 | 15 | # Utility function 16 | def U(self, c, l): 17 | return np.log(c) + self.ψ * np.log(l) 18 | 19 | # Derivatives of utility function 20 | def Uc(self, c, l): 21 | return 1 / c 22 | 23 | def Ucc(self, c, l): 24 | return -c**(-2) 25 | 26 | def Ul(self, c, l): 27 | return self.ψ / l 28 | 29 | def Ull(self, c, l): 30 | return -self.ψ / l**2 31 | 32 | def Ucl(self, c, l): 33 | return 0 34 | 35 | def Ulc(self, c, l): 36 | return 0 37 | -------------------------------------------------------------------------------- /scripts/execution-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CLEAN_BUILD=false 4 | MODIFIED_FILES="$1" 5 | 6 | RST_FILES="" 7 | for F in $MODIFIED_FILES 8 | do 9 | if [[ $F == environment.yml ]] 10 | then 11 | CLEAN_BUILD=true 12 | break 13 | fi 14 | #Extract List of RST Files 15 | if [[ $F == *.rst ]] 16 | then 17 | RST_FILES="$RST_FILES $F" 18 | fi 19 | done 20 | 21 | echo "List of Changed RST Files: $RST_FILES" 22 | echo "Clean Build Requested: $CLEAN_BUILD" 23 | 24 | if [ "$CLEAN_BUILD" = true ] 25 | then 26 | echo "Running Clean Build" 27 | make coverage 28 | elif [ -z "$RST_FILES" ] 29 | then 30 | echo "No RST Files have changed -- nothing to do in this PR" 31 | else 32 | RST_FILES="$RST_FILES source/rst/index_toc.rst" 33 | echo "Running Selecting Build with: $RST_FILES" 34 | make coverage FILES="$RST_FILES" 35 | fi -------------------------------------------------------------------------------- /source/_static/lecture_specific/amss2/log_utility.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class LogUtility: 4 | 5 | def __init__(self, 6 | β=0.9, 7 | ψ=0.69, 8 | π=0.5*np.ones((2, 2)), 9 | G=np.array([0.1, 0.2]), 10 | Θ=np.ones(2), 11 | transfers=False): 12 | 13 | self.β, self.ψ, self.π = β, ψ, π 14 | self.G, self.Θ, self.transfers = G, Θ, transfers 15 | 16 | # Utility function 17 | def U(self, c, n): 18 | return np.log(c) + self.ψ * np.log(1 - n) 19 | 20 | # Derivatives of utility function 21 | def Uc(self, c, n): 22 | return 1 / c 23 | 24 | def Ucc(self, c, n): 25 | return -c**(-2) 26 | 27 | def Un(self, c, n): 28 | return -self.ψ / (1 - n) 29 | 30 | def Unn(self, c, n): 31 | return -self.ψ / (1 - n)**2 -------------------------------------------------------------------------------- /scripts/build-website.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MODIFIED_FILES="$1" 4 | PRIVATE_THEME=$2 5 | 6 | RST_FILES="" 7 | for F in $MODIFIED_FILES 8 | do 9 | if [[ $F == *.rst ]] 10 | then 11 | RST_FILES="$RST_FILES $F" 12 | fi 13 | done 14 | echo "List of Changed RST Files: $RST_FILES" 15 | echo "Building with Private theme: $PRIVATE_THEME" 16 | if [ -z "$RST_FILES" ]; then 17 | echo "BUILD_NETLIFY=false" >> $GITHUB_ENV 18 | echo "No RST Files have changed -- nothing to do in this PR" 19 | else 20 | echo "BUILD_NETLIFY=true" >> $GITHUB_ENV 21 | RST_FILES="$RST_FILES source/rst/index_toc.rst" 22 | if [ "$PRIVATE_THEME" = true ]; then 23 | make website THEMEPATH=theme/lecture-python-advanced.theme FILES="$RST_FILES" 24 | else 25 | make website FILES="$RST_FILES" 26 | fi 27 | ls _build/website/jupyter_html/* #Ensure build files are created 28 | fi -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_def1.tex: -------------------------------------------------------------------------------- 1 | \documentclass[convert={density=300,size=1080x800,outext=.png}]{standalone} 2 | \usepackage{tikz} 3 | 4 | \usetikzlibrary{arrows.meta, arrows} 5 | 6 | \begin{document} 7 | 8 | %.. tikz:: 9 | \begin{tikzpicture} 10 | [scale=5, axis/.style={<->, >=stealth'}, important line/.style={thick}, dotted line/.style={dotted, thick,red}, every node/.style={color=black}]\coordinate(O) at (0,0); 11 | \coordinate (X) at (-0.2,0.3); 12 | \coordinate (Z) at (0.6,0.3); 13 | \draw[axis] (-0.4,0) -- (0.9,0) node(xline)[right] {}; 14 | \draw[axis] (0,-0.3) -- (0,0.7) node(yline)[above] {}; 15 | \draw[important line,blue, ->] (O) -- (X) node[left] {$x$}; 16 | \draw[important line,blue, ->] (O) -- (Z) node[right] {$z$}; 17 | \draw[dotted line] (-0.03,0.045) -- (0.03,0.075); 18 | \draw[dotted line] (0.06,0.03) -- (0.03,0.075); 19 | 20 | \end{tikzpicture} 21 | 22 | \end{document} -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_def2.tex: -------------------------------------------------------------------------------- 1 | \documentclass[convert={density=300,size=1080x800,outext=.png}]{standalone} 2 | \usepackage{tikz} 3 | \usetikzlibrary{arrows.meta, arrows} 4 | \begin{document} 5 | 6 | %.. tikz:: 7 | \begin{tikzpicture} 8 | [scale=5, axis/.style={<->, >=stealth'}, important line/.style={thick}, dotted line/.style={dotted, thick,red}, every node/.style={color=black} ] \coordinate(O) at (0,0); 9 | \coordinate (X) at (-0.2,0.3); 10 | \coordinate (Z1) at (-0.3,-0.15); 11 | \coordinate (Z2) at (0.8,0.4); 12 | \draw[axis] (-0.4,0) -- (0.9,0) node(xline)[right] {}; 13 | \draw[axis] (0,-0.3) -- (0,0.7) node(yline)[above] {}; 14 | \draw[important line,blue, ->] (O) -- (X) node[left] {$x$}; 15 | \draw[important line] (Z1) -- (Z2) node[right] {$S$}; 16 | \draw[dotted line] (-0.03,0.045) -- (0.03,0.075); 17 | \draw[dotted line] (0.06,0.03) -- (0.03,0.075); 18 | \end{tikzpicture} 19 | 20 | \end{document} 21 | 22 | 23 | -------------------------------------------------------------------------------- /theme/minimal/static/img/powered-by-NumFOCUS-orange.svg: -------------------------------------------------------------------------------- 1 | powered bypowered byNumFOCUSNumFOCUS -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Execution and Link Checks 2 | on: [pull_request] 3 | jobs: 4 | tests: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout 8 | uses: actions/checkout@v2 9 | - name: Setup Anaconda 10 | uses: conda-incubator/setup-miniconda@v2 11 | with: 12 | auto-update-conda: true 13 | auto-activate-base: true 14 | miniconda-version: 'latest' 15 | python-version: 3.8 16 | environment-file: environment.yml 17 | activate-environment: lecture-python-advanced 18 | - name: Get Changed Files 19 | id: files 20 | uses: jitterbit/get-changed-files@v1 21 | - name: Run Execution Tests 22 | shell: bash -l {0} 23 | run: bash scripts/execution-test.sh "${{ steps.files.outputs.added_modified }}" 24 | - name: Run Linkchecker 25 | shell: bash -l {0} 26 | run: bash scripts/linkchecker-test.sh "${{ steps.files.outputs.added_modified }}" -------------------------------------------------------------------------------- /source/_static/lecture_specific/markov_perf/duopoly_mpe.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import quantecon as qe 3 | 4 | # Parameters 5 | a0 = 10.0 6 | a1 = 2.0 7 | β = 0.96 8 | γ = 12.0 9 | 10 | # In LQ form 11 | A = np.eye(3) 12 | B1 = np.array([[0.], [1.], [0.]]) 13 | B2 = np.array([[0.], [0.], [1.]]) 14 | 15 | 16 | R1 = [[ 0., -a0 / 2, 0.], 17 | [-a0 / 2., a1, a1 / 2.], 18 | [ 0, a1 / 2., 0.]] 19 | 20 | R2 = [[ 0., 0., -a0 / 2], 21 | [ 0., 0., a1 / 2.], 22 | [-a0 / 2, a1 / 2., a1]] 23 | 24 | Q1 = Q2 = γ 25 | S1 = S2 = W1 = W2 = M1 = M2 = 0.0 26 | 27 | # Solve using QE's nnash function 28 | F1, F2, P1, P2 = qe.nnash(A, B1, B2, R1, R2, Q1, 29 | Q2, S1, S2, W1, W2, M1, 30 | M2, beta=β) 31 | 32 | # Display policies 33 | print("Computed policies for firm 1 and firm 2:\n") 34 | print(f"F1 = {F1}") 35 | print(f"F2 = {F2}") 36 | print("\n") 37 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_def3.tex: -------------------------------------------------------------------------------- 1 | \documentclass[convert={density=300,size=1080x800,outext=.png}]{standalone} 2 | \usepackage{tikz} 3 | \usetikzlibrary{arrows.meta, arrows} 4 | \begin{document} 5 | 6 | %.. tikz:: 7 | \begin{tikzpicture} 8 | [scale=5, axis/.style={<->, >=stealth'}, important line/.style={thick}, dotted line/.style={dotted, thick,red}, dashed line/.style={dashed, thin}, every node/.style={color=black}] \coordinate(O) at (0,0); 9 | \coordinate (S1) at (-0.4,-0.2); 10 | \coordinate (S2) at (0.8,0.4); 11 | \coordinate (S3) at (-0.25,0.5); 12 | \coordinate (S4) at (0.12,-0.24); 13 | \draw[axis] (-0.5,0) -- (0.9,0) node(xline)[right] {}; 14 | \draw[axis] (0,-0.3) -- (0,0.7) node(yline)[above] {}; 15 | \draw[important line, thick] (S1) -- (S2) node[right] {$S$}; 16 | \draw[important line, thick] (S4) -- (S3) node[left] {$S^{\perp}$}; 17 | \draw[dotted line] (-0.03,0.06) -- (0.03,0.09); 18 | \draw[dotted line] (0.06,0.03) -- (0.03,0.09); 19 | \end{tikzpicture} 20 | 21 | \end{document} -------------------------------------------------------------------------------- /source/_static/lecture_specific/amss2/crra_utility.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class CRRAutility: 5 | 6 | def __init__(self, 7 | β=0.9, 8 | σ=2, 9 | γ=2, 10 | π=0.5*np.ones((2, 2)), 11 | G=np.array([0.1, 0.2]), 12 | Θ=np.ones(2), 13 | transfers=False): 14 | 15 | self.β, self.σ, self.γ = β, σ, γ 16 | self.π, self.G, self.Θ, self.transfers = π, G, Θ, transfers 17 | 18 | # Utility function 19 | def U(self, c, n): 20 | σ = self.σ 21 | if σ == 1.: 22 | U = np.log(c) 23 | else: 24 | U = (c**(1 - σ) - 1) / (1 - σ) 25 | return U - n**(1 + self.γ) / (1 + self.γ) 26 | 27 | # Derivatives of utility function 28 | def Uc(self, c, n): 29 | return c**(-self.σ) 30 | 31 | def Ucc(self, c, n): 32 | return -self.σ * c**(-self.σ - 1) 33 | 34 | def Un(self, c, n): 35 | return -n**self.γ 36 | 37 | def Unn(self, c, n): 38 | return -self.γ * n**(self.γ - 1) -------------------------------------------------------------------------------- /source/_static/lecture_specific/opt_tax_recur/crra_utility.py: -------------------------------------------------------------------------------- 1 | crra_util_data = [ 2 | ('β', float64), 3 | ('σ', float64), 4 | ('γ', float64) 5 | ] 6 | 7 | @jitclass(crra_util_data) 8 | class CRRAutility: 9 | 10 | def __init__(self, 11 | β=0.9, 12 | σ=2, 13 | γ=2): 14 | 15 | self.β, self.σ, self.γ = β, σ, γ 16 | 17 | # Utility function 18 | def U(self, c, l): 19 | # Note: `l` should not be interpreted as labor, it is an auxiliary 20 | # variable used to conveniently match the code and the equations 21 | # in the lecture 22 | σ = self.σ 23 | if σ == 1.: 24 | U = np.log(c) 25 | else: 26 | U = (c**(1 - σ) - 1) / (1 - σ) 27 | return U - (1-l) ** (1 + self.γ) / (1 + self.γ) 28 | 29 | # Derivatives of utility function 30 | def Uc(self, c, l): 31 | return c ** (-self.σ) 32 | 33 | def Ucc(self, c, l): 34 | return -self.σ * c ** (-self.σ - 1) 35 | 36 | def Ul(self, c, l): 37 | return (1-l) ** self.γ 38 | 39 | def Ull(self, c, l): 40 | return -self.γ * (1-l) ** (self.γ - 1) 41 | 42 | def Ucl(self, c, l): 43 | return 0 44 | 45 | def Ulc(self, c, l): 46 | return 0 47 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: Execution and Link Testing (Nightly) 2 | on: 3 | schedule: 4 | - cron: '0 17 * * *' 5 | jobs: 6 | coverage: 7 | name: Run Coverage 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | - name: Setup Anaconda 13 | uses: conda-incubator/setup-miniconda@v2 14 | with: 15 | auto-update-conda: true 16 | auto-activate-base: true 17 | miniconda-version: 'latest' 18 | python-version: 3.8 19 | environment-file: environment.yml 20 | activate-environment: lecture-python-advanced 21 | - name: Run Execution Tests 22 | shell: bash -l {0} 23 | run: make coverage 24 | linkchecker: 25 | name: Run linkchecker 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v2 30 | - name: Setup Anaconda 31 | uses: goanpeca/setup-miniconda@v1 32 | with: 33 | auto-update-conda: true 34 | auto-activate-base: true 35 | miniconda-version: 'latest' 36 | python-version: 3.7 37 | environment-file: environment.yml 38 | activate-environment: qe-lectures 39 | - name: Run Linkchecker 40 | shell: bash -l {0} 41 | run: make linkcheck 42 | -------------------------------------------------------------------------------- /source/rst/index_toc.rst: -------------------------------------------------------------------------------- 1 | .. _toc: 2 | 3 | .. raw:: html 4 | 5 |

Powered by NumFOCUS logo

6 | 7 | .. only:: html 8 | 9 | Table of Contents 10 | ***************** 11 | 12 | 13 | .. toctree:: 14 | :maxdepth: 2 15 | :titlesonly: 16 | 17 | about_lectures 18 | index_tools_and_techniques 19 | index_lq_control 20 | index_multi_agent_models 21 | index_hs_recursive_models 22 | index_classic_linear_models 23 | index_time_series_models 24 | index_asset_pricing 25 | index_dynamic_programming_squared 26 | zreferences 27 | 28 | 29 | .. toctree:: 30 | :hidden: 31 | 32 | 404 33 | search 34 | status 35 | troubleshooting 36 | 37 | | 38 | 39 | .. image:: http://assets.quantecon.org/img/banner.png 40 | :scale: 30% 41 | :align: center 42 | 43 | .. only:: latex 44 | 45 | Acknowledgements: These lectures have benefitted greatly from comments and 46 | suggestion from our colleagues, students and friends. Special thanks go to 47 | Anmol Bhandari, Long Bui, Jeong-Hun Choi, Chase Coleman, David Evans, Shunsuke Hori, 48 | Chenghan Hou, Doc-Jin Jang, Spencer Lyon, Qingyin Ma, Akira Matsushita, 49 | Matthew McKay, Tomohito Okabe, Alex Olssen, Nathan Palmer and Yixiao Zhou. 50 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_thm1.tex: -------------------------------------------------------------------------------- 1 | \documentclass[convert={density=300,size=1080x800,outext=.png}]{standalone} 2 | \usepackage{tikz} 3 | \usetikzlibrary{arrows.meta, arrows} 4 | \begin{document} 5 | 6 | %.. tikz:: 7 | \begin{tikzpicture} 8 | [scale=5, axis/.style={<->, >=stealth'}, important line/.style={thick}, dotted line/.style={dotted, thick,red}, dashed line/.style={dashed, thin}, every node/.style={color=black}] \coordinate(O) at (0,0); 9 | \coordinate (y-yhat) at (-0.2,0.4); 10 | \coordinate (yhat) at (0.6,0.3); 11 | \coordinate (y) at (0.4,0.7); 12 | \coordinate (Z1) at (-0.4,-0.2); 13 | \coordinate (Z2) at (0.8,0.4); 14 | \draw[axis] (-0.5,0) -- (0.9,0) node(xline)[right] {}; 15 | \draw[axis] (0,-0.3) -- (0,0.7) node(yline)[above] {}; 16 | \draw[important line,blue,thick, ->] (O) -- (yhat) node[below] {$\hat y$}; 17 | \draw[important line,blue, ->] (O) -- (y-yhat) node[left] {$y - \hat y$}; 18 | \draw[important line, thick] (Z1) -- (O) node[right] {}; 19 | \draw[important line, thick] (yhat) -- (Z2) node[right] {$S$}; 20 | \draw[important line, blue,->] (O) -- (y) node[right] {$y$}; 21 | \draw[dotted line] (-0.03,0.06) -- (0.03,0.09); 22 | \draw[dotted line] (0.06,0.03) -- (0.03,0.09); 23 | \draw[dotted line] (0.54,0.27) -- (0.51,0.33); 24 | \draw[dotted line] (0.57,0.36) -- (0.51,0.33); 25 | \draw[dashed line, black] (y) -- (yhat); 26 | \draw[-latex, very thin] (0.5,0.4) to [out=210,in=50] (-0.1,0.2); 27 | 28 | \end{tikzpicture} 29 | 30 | \end{document} -------------------------------------------------------------------------------- /theme/minimal/static/css/qe.python.css: -------------------------------------------------------------------------------- 1 | /* Homepage */ 2 | .home-intro { 3 | display: flex; 4 | align-content: center; 5 | } 6 | .home-blurb { 7 | font-size: 1.1rem; 8 | line-height: 1.5; 9 | } 10 | .home-intro .sponsor { 11 | list-style: none; 12 | padding:0; 13 | flex-shrink: 0; 14 | margin:0 60px 0 4rem; 15 | text-align: center; 16 | } 17 | .home-intro .sponsor li { 18 | display: block; 19 | margin:1rem 0; 20 | padding:0; 21 | } 22 | .web-version { 23 | display:inline-block; 24 | padding: 2rem 0rem; 25 | } 26 | .web-version a { 27 | display: block; 28 | padding:1rem 40px 1rem 80px; 29 | position: relative; 30 | } 31 | .web-version a .thumb { 32 | position: absolute; 33 | left:0px; 34 | top:1rem; 35 | } 36 | .web-version a .thumb img { 37 | width:50px; 38 | } 39 | .web-version a h2 { 40 | line-height: 1; 41 | margin:0; 42 | font-size: 1.4rem; 43 | } 44 | .web-version a p { 45 | margin:10px 0 0 0; 46 | } 47 | .home-alternatives { 48 | padding: 1rem 0rem; 49 | } 50 | .home-alternatives ul { 51 | list-style: none; 52 | padding:0; 53 | margin:0 0; 54 | } 55 | .home-alternatives li { 56 | padding:0; 57 | margin:1rem 1rem; 58 | } 59 | .home-alternatives li a { 60 | display: block; 61 | } 62 | .home-alternatives li a h3 { 63 | line-height: 1; 64 | margin:0; 65 | font-size: 1.2rem; 66 | } 67 | .home-alternatives li a p { 68 | margin:10px 0 0 0; 69 | } 70 | @media only screen and (max-width: 768px) { 71 | .home-intro { 72 | display: block; 73 | } 74 | .home-intro .sponsor { 75 | margin:0 auto; 76 | } 77 | } 78 | 79 | /* Other */ 80 | #qe-notebook-header { 81 | display: none; 82 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, QuantEcon 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_thm2.tex: -------------------------------------------------------------------------------- 1 | \documentclass[convert={density=300,size=1080x800,outext=.png}]{standalone} 2 | \usepackage{tikz} 3 | \usetikzlibrary{arrows.meta, arrows} 4 | \begin{document} 5 | 6 | %.. tikz:: 7 | \begin{tikzpicture} 8 | [scale=5, axis/.style={<->, >=stealth'}, important line/.style={thick}, dotted line/.style={dotted, thick,red}, dashed line/.style={dashed, thin}, every node/.style={color=black}] \coordinate(O) at (0,0); 9 | \coordinate (y') at (-0.4,0.1); 10 | \coordinate (Py) at (0.6,0.3); 11 | \coordinate (y) at (0.4,0.7); 12 | \coordinate (Z1) at (-0.4,-0.2); 13 | \coordinate (Z2) at (0.8,0.4); 14 | \coordinate (Py') at (-0.28,-0.14); 15 | \draw[axis] (-0.5,0) -- (0.9,0) node(xline)[right] {}; 16 | \draw[axis] (0,-0.3) -- (0,0.7) node(yline)[above] {}; 17 | \draw[important line,blue,thick, ->] (O) -- (Py) node[anchor = north west, text width=2em] {$P y$}; 18 | \draw[important line,blue, ->] (O) -- (y') node[left] {$y'$}; 19 | \draw[important line, thick] (Z1) -- (O) node[right] {}; 20 | \draw[important line, thick] (Py) -- (Z2) node[right] {$S$}; 21 | \draw[important line, blue,->] (O) -- (y) node[right] {$y$}; 22 | \draw[dotted line] (0.54,0.27) -- (0.51,0.33); 23 | \draw[dotted line] (0.57,0.36) -- (0.51,0.33); 24 | \draw[dotted line] (-0.22,-0.11) -- (-0.25,-0.05); 25 | \draw[dotted line] (-0.31,-0.08) -- (-0.25,-0.05); 26 | \draw[dashed line, black] (y) -- (Py); 27 | \draw[dashed line, black] (y') -- (Py') node[anchor = north west, text width=5em] {$P y'$}; 28 | \end{tikzpicture} 29 | 30 | \end{document} -------------------------------------------------------------------------------- /source/_static/lecture_specific/orth_proj/orth_proj_thm3.tex: -------------------------------------------------------------------------------- 1 | \documentclass[convert={density=300,size=1080x800,outext=.png}]{standalone} 2 | \usepackage{tikz} 3 | \usetikzlibrary{arrows.meta, arrows} 4 | \begin{document} 5 | 6 | %.. tikz:: 7 | \begin{tikzpicture} 8 | [scale=5, axis/.style={<->, >=stealth'}, important line/.style={thick}, dotted line/.style={dotted, thick,red}, dashed line/.style={dashed, thin}, every node/.style={color=black}] \coordinate(O) at (0,0); 9 | \coordinate (uhat) at (-0.2,0.4); 10 | \coordinate (yhat) at (0.6,0.3); 11 | \coordinate (y) at (0.4,0.7); 12 | \coordinate (S1) at (-0.4,-0.2); 13 | \coordinate (S2) at (0.8,0.4); 14 | \coordinate (S3) at (-0.3,0.6); 15 | \coordinate (S4) at (0.12,-0.24); 16 | \draw[axis] (-0.5,0) -- (0.9,0) node(xline)[right] {}; 17 | \draw[axis] (0,-0.3) -- (0,0.7) node(yline)[above] {}; 18 | \draw[important line,blue,thick, ->] (O) -- (yhat) node[anchor = north west, text width=4em] {$P y$}; 19 | \draw[important line,blue, ->] (O) -- (uhat) node[anchor = north east, text width=4em] {$M y$}; 20 | \draw[important line,thick] (uhat) -- (S3) node [anchor = south east, text width=0.5em] {$S^{\perp}$}; 21 | \draw[important line,thick] (O) -- (S4); 22 | \draw[important line, thick] (S1) -- (O) node[right] {}; 23 | \draw[important line, thick] (yhat) -- (S2) node[right] {$S$}; 24 | \draw[important line, blue,->] (O) -- (y) node[right] {$y$}; 25 | \draw[dotted line] (-0.03,0.06) -- (0.03,0.09); 26 | \draw[dotted line] (0.06,0.03) -- (0.03,0.09); 27 | \draw[dotted line] (0.54,0.27) -- (0.51,0.33); 28 | \draw[dotted line] (0.57,0.36) -- (0.51,0.33); 29 | \draw[dotted line] (-0.17,0.34) -- (-0.11,0.37); 30 | \draw[dotted line] (-0.14,0.43) -- (-0.11,0.37); 31 | \draw[dashed line, black] (y) -- (yhat); 32 | \draw[dashed line, black] (y) -- (uhat); 33 | \end{tikzpicture} 34 | 35 | \end{document} -------------------------------------------------------------------------------- /source/_static/lecture_specific/amss2/utilities.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.interpolate import UnivariateSpline 3 | 4 | 5 | class interpolate_wrapper: 6 | 7 | def __init__(self, F): 8 | self.F = F 9 | 10 | def __getitem__(self, index): 11 | return interpolate_wrapper(np.asarray(self.F[index])) 12 | 13 | def reshape(self, *args): 14 | self.F = self.F.reshape(*args) 15 | return self 16 | 17 | def transpose(self): 18 | self.F = self.F.transpose() 19 | 20 | def __len__(self): 21 | return len(self.F) 22 | 23 | def __call__(self, xvec): 24 | x = np.atleast_1d(xvec) 25 | shape = self.F.shape 26 | if len(x) == 1: 27 | fhat = np.hstack([f(x) for f in self.F.flatten()]) 28 | return fhat.reshape(shape) 29 | else: 30 | fhat = np.vstack([f(x) for f in self.F.flatten()]) 31 | return fhat.reshape(np.hstack((shape, len(x)))) 32 | 33 | 34 | class interpolator_factory: 35 | 36 | def __init__(self, k, s): 37 | self.k, self.s = k, s 38 | 39 | def __call__(self, xgrid, Fs): 40 | shape, m = Fs.shape[:-1], Fs.shape[-1] 41 | Fs = Fs.reshape((-1, m)) 42 | F = [] 43 | xgrid = np.sort(xgrid) # Sort xgrid 44 | for Fhat in Fs: 45 | F.append(UnivariateSpline(xgrid, Fhat, k=self.k, s=self.s)) 46 | return interpolate_wrapper(np.array(F).reshape(shape)) 47 | 48 | 49 | def fun_vstack(fun_list): 50 | 51 | Fs = [IW.F for IW in fun_list] 52 | return interpolate_wrapper(np.vstack(Fs)) 53 | 54 | 55 | def fun_hstack(fun_list): 56 | 57 | Fs = [IW.F for IW in fun_list] 58 | return interpolate_wrapper(np.hstack(Fs)) 59 | 60 | 61 | def simulate_markov(π, s_0, T): 62 | 63 | sHist = np.empty(T, dtype=int) 64 | sHist[0] = s_0 65 | S = len(π) 66 | for t in range(1, T): 67 | sHist[t] = np.random.choice(np.arange(S), p=π[sHist[t - 1]]) 68 | 69 | return sHist 70 | -------------------------------------------------------------------------------- /.github/workflows/preview.yml: -------------------------------------------------------------------------------- 1 | name: 'Netlify Preview Deploy' 2 | on: 3 | pull_request: 4 | types: ['opened', 'edited', 'synchronize'] 5 | jobs: 6 | deploy-preview: 7 | name: 'Deploy' 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | - name: Setup Anaconda 13 | uses: conda-incubator/setup-miniconda@v2 14 | with: 15 | auto-update-conda: true 16 | auto-activate-base: true 17 | miniconda-version: 'latest' 18 | python-version: 3.8 19 | environment-file: environment.yml 20 | activate-environment: lecture-python-advanced 21 | - name: Get Changed Files 22 | id: files 23 | uses: jitterbit/get-changed-files@v1 24 | - name: Checkout QuantEcon theme 25 | if: github.event.pull_request.head.repo.full_name == github.repository 26 | uses: actions/checkout@v2 27 | with: 28 | repository: QuantEcon/lecture-python-advanced.theme 29 | token: ${{ secrets.ACTIONS_PAT }} 30 | path: theme/lecture-python-advanced.theme 31 | # - name: Get current date 32 | # id: date 33 | # run: echo "::set-output name=date::$(date +'%Y-%m-%d')" 34 | # - name: Check Sphinx Cache 35 | # id: cache 36 | # uses: actions/cache@v1 37 | # with: 38 | # path: _build 39 | # key: cache-sphinx 40 | # # key: cache-sphinx-${{ steps.date.outputs.date }} 41 | - name: Build website files 42 | shell: bash -l {0} 43 | run: | 44 | bash scripts/build-website.sh "${{ steps.files.outputs.added_modified }}" "${{ github.event.pull_request.head.repo.full_name == github.repository }}" 45 | - name: Preview Deploy to Netlify 46 | uses: nwtgck/actions-netlify@v1.1 47 | if: env.BUILD_NETLIFY == 'true' && github.event.pull_request.head.repo.full_name == github.repository 48 | with: 49 | publish-dir: './_build/website/jupyter_html' 50 | production-branch: master 51 | github-token: ${{ secrets.GITHUB_TOKEN }} 52 | deploy-message: "Preview Deploy from GitHub Actions" 53 | env: 54 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} 55 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} -------------------------------------------------------------------------------- /source/_static/lecture_specific/coase/allocation.tex: -------------------------------------------------------------------------------- 1 | \documentclass[convert={density=300,size=1080x800,outext=.png}]{standalone} 2 | 3 | \usepackage{tikz} 4 | \usetikzlibrary{decorations.pathreplacing} 5 | \usetikzlibrary{arrows,positioning} 6 | \tikzset{ 7 | %Define standard arrow tip 8 | >=stealth', 9 | %Define style for boxes 10 | punkt/.style={ 11 | rectangle, 12 | rounded corners, 13 | draw=black, very thick, 14 | text width=6.5em, 15 | minimum height=2em, 16 | text centered}, 17 | % Define arrow style 18 | pil/.style={ 19 | ->, 20 | thick} 21 | } 22 | 23 | 24 | \begin{document} 25 | 26 | \begin{tikzpicture}[scale=1] 27 | 28 | \def\linelen{12} 29 | \def\tone{0.66 * \linelen}; 30 | \def\ttwo{0.33 * \linelen}; 31 | 32 | \draw[thick] (0,0) -- (\linelen,0); 33 | 34 | \fill (0,0) circle (2pt) node [below] {$t_3 = 0$}; 35 | \fill (\linelen,0) circle (2pt) node [below] {$t_0 = 1$}; 36 | \fill (\tone,0) circle (2pt) node [below] {$t_1$}; 37 | \fill (\ttwo,0) circle (2pt) node [below] {$t_2$}; 38 | 39 | \draw [decorate,decoration={brace,amplitude=10pt},xshift=0pt,yshift=3pt] 40 | (0,0) -- (\ttwo,0) node [black,midway,yshift=0.8cm] {\footnotesize 41 | $\ell_3$}; 42 | 43 | \draw [decorate,decoration={brace,amplitude=10pt},xshift=0pt,yshift=3pt] 44 | (\ttwo,0) -- (\tone,0) node [black,midway,yshift=0.8cm] {\footnotesize 45 | $\ell_2$}; 46 | 47 | \draw [decorate,decoration={brace,amplitude=10pt},xshift=0pt,yshift=3pt] 48 | (\tone,0) -- (\linelen,0) node [black,midway,yshift=0.8cm] {\footnotesize 49 | $\ell_1$}; 50 | 51 | \node at (10, 0) [below] {\footnotesize firm 1}; 52 | \node at (6, 0) [below] {\footnotesize firm 2}; 53 | \node at (2, 0) [below] {\footnotesize firm 3}; 54 | 55 | % Notation on in-house production and firm boundaries 56 | \def\a{2}; 57 | \draw[->] (5.9, \a) -- (5.9, 1.15) ; 58 | \draw[->] (6, \a) node [above] {\footnotesize $\ell_i = $ range of tasks 59 | carried out by firm $i$} -- (9.5, 1.1) ; 60 | \draw[->] (5.8, \a) -- (2.5, 1.1) ; 61 | 62 | \def\b{-2}; 63 | \draw[->] (6, \b) -- (\tone, -0.8) ; 64 | \draw[->] (5.9, \b) node [below] {\footnotesize $t_i = $ upstream boundary 65 | of firm $i$} -- (\ttwo, -0.8) ; 66 | \draw[->] (5.8, \b) -- (0, -0.8) ; 67 | 68 | \end{tikzpicture} 69 | 70 | 71 | \end{document} 72 | -------------------------------------------------------------------------------- /source/rst/troubleshooting.rst: -------------------------------------------------------------------------------- 1 | .. _troubleshooting: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | .. highlight:: python3 6 | 7 | *************** 8 | Troubleshooting 9 | *************** 10 | 11 | .. contents:: :depth: 2 12 | 13 | This page is for readers experiencing errors when running the code from the lectures. 14 | 15 | Fixing Your Local Environment 16 | ============================== 17 | 18 | The basic assumption of the lectures is that code in a lecture should execute whenever 19 | 20 | #. it is executed in a Jupyter notebook and 21 | 22 | #. the notebook is running on a machine with the latest version of Anaconda Python. 23 | 24 | You have installed Anaconda, haven't you, following the instructions in `this lecture `__? 25 | 26 | Assuming that you have, the most common source of problems for our readers is that their Anaconda distribution is not up to date. 27 | 28 | `Here's a useful article `__ 29 | on how to update Anaconda. 30 | 31 | Another option is to simply remove Anaconda and reinstall. 32 | 33 | You also need to keep the external code libraries, such as `QuantEcon.py 34 | `__ up to date. 35 | 36 | For this task you can either 37 | 38 | * use `pip install --upgrade quantecon` on the command line, or 39 | 40 | * execute `!pip install --upgrade quantecon` within a Jupyter notebook. 41 | 42 | If your local environment is still not working you can do two things. 43 | 44 | First, you can use a remote machine instead, by clicking on the `Launch Notebook` icon available for each lecture 45 | 46 | .. image:: _static/lecture_specific/troubleshooting/launch.png 47 | 48 | Second, you can report an issue, so we can try to fix your local set up. 49 | 50 | We like getting feedback on the lectures so please don't hesitate to get in 51 | touch. 52 | 53 | Reporting an Issue 54 | =================== 55 | 56 | One way to give feedback is to raise an issue through our `issue tracker 57 | `__. 58 | 59 | Please be as specific as possible. Tell us where the problem is and as much 60 | detail about your local set up as you can provide. 61 | 62 | Another feedback option is to use our `discourse forum `__. 63 | 64 | Finally, you can provide direct feedback to contact@quantecon.org 65 | 66 | -------------------------------------------------------------------------------- /source/rst/index.rst: -------------------------------------------------------------------------------- 1 | .. _index: 2 | 3 | ******************************************** 4 | Advanced Quantitative Economics with Python 5 | ******************************************** 6 | 7 | .. toctree:: 8 | :hidden: 9 | 10 | index_toc 11 | 12 | 13 | .. raw:: html 14 | 15 |
16 |

Advanced Quantitative Economics with Python

17 |
18 |
19 |
20 |

This website presents a set of advanced lectures on quantitative economic modeling, designed and written by Thomas J. Sargent and John Stachurski.

21 |

Last compiled:
22 | View source | 23 | View commits | See all contributors

24 |
25 | 32 |
33 | 37 |
38 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/coase/subcontracting.tex: -------------------------------------------------------------------------------- 1 | \documentclass[convert={density=300,size=1080x800,outext=.png}]{standalone} 2 | 3 | \usepackage{tikz} 4 | \usetikzlibrary{decorations.pathreplacing} 5 | \usetikzlibrary{arrows,positioning} 6 | \tikzset{ 7 | %Define standard arrow tip 8 | >=stealth', 9 | %Define style for boxes 10 | punkt/.style={ 11 | rectangle, 12 | rounded corners, 13 | draw=black, very thick, 14 | text width=6.5em, 15 | minimum height=2em, 16 | text centered}, 17 | % Define arrow style 18 | pil/.style={ 19 | ->, 20 | thick} 21 | } 22 | 23 | 24 | \begin{document} 25 | 26 | \begin{tikzpicture}[scale=1] 27 | 28 | \def\linelen{12} 29 | \def\tone{0.66 * \linelen}; 30 | \def\ttwo{0.33 * \linelen}; 31 | \def\levtwo{-2.2}; % level 2 32 | \def\levthree{-4.2}; % level 2 33 | 34 | \draw[thick] (0,0) -- (\linelen,0); 35 | 36 | \node at (0,0) [below] {$0$}; 37 | \node at (\linelen,0) [below] {$1$}; 38 | \fill (\tone,0) circle (2pt) node [below] {$t_1$}; 39 | 40 | \draw [decorate,decoration={brace,amplitude=10pt},xshift=0pt,yshift=3pt] 41 | (\tone,0) -- (\linelen,0) node [black,midway,yshift=0.8cm] {\footnotesize 42 | processed by firm 1}; 43 | \draw [decorate,decoration={brace,amplitude=10pt},xshift=0pt,yshift=3pt] 44 | (0,0) -- (\tone,0) node [black,midway,yshift=0.8cm] {\footnotesize 45 | subcontracted by firm 1 to firm 2}; 46 | 47 | \draw[->] (0.5 * \tone, -0.2) -- (0.5 * \tone, -0.9); 48 | 49 | \draw[thick] (0, \levtwo) -- (\tone, \levtwo); 50 | \node at (0,\levtwo) [below] {$0$}; 51 | \fill (\tone,\levtwo) circle (2pt) node [below] {$t_1$}; 52 | \fill (\ttwo,\levtwo) circle (2pt) node [below] {$t_2$}; 53 | 54 | \draw [decorate,decoration={brace,amplitude=10pt},xshift=0pt,yshift=3pt] 55 | (0,\levtwo) -- (\ttwo,\levtwo) node [black,midway,yshift=0.8cm] {\footnotesize 56 | subcontracted by 2 to 3}; 57 | \draw [decorate,decoration={brace,amplitude=10pt},xshift=0pt,yshift=3pt] 58 | (\ttwo,\levtwo) -- (\tone,\levtwo) node [black,midway,yshift=0.8cm] {\footnotesize 59 | processed by firm 2}; 60 | 61 | \draw[->] (0.5 * \ttwo, -2.4) -- (0.5 * \ttwo, -2.9); 62 | 63 | \draw[thick] (0, \levthree) -- (\ttwo, \levthree); 64 | \node at (0,\levthree) [below] {$0$}; 65 | \fill (\ttwo,\levthree) circle (2pt) node [below] {$t_2$}; 66 | 67 | \draw [decorate,decoration={brace,amplitude=10pt},xshift=0pt,yshift=3pt] 68 | (0,\levthree) -- (\ttwo,\levthree) node [black,midway,yshift=0.8cm] {\footnotesize 69 | processed by firm 3}; 70 | 71 | \end{tikzpicture} 72 | 73 | \end{document} 74 | -------------------------------------------------------------------------------- /source/rst/.ipynb_checkpoints/Untitled-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import glob\n", 10 | "import re\n", 11 | "import os\n", 12 | "import errno\n", 13 | "path1 = '/home/anju/Documents/lecture-source-py/source/rst/*.rst'\n", 14 | "path2 = '*.tex'\n", 15 | "path = '*.rst'\n", 16 | "files = glob.glob(path)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "def func_replace(a, b, filename):\n", 26 | " with open(filename,'r+', encoding=\"utf8\") as f:\n", 27 | " #convert to string:\n", 28 | " data = f.read()\n", 29 | " f.seek(0)\n", 30 | " f.write(data.replace(a, b))\n", 31 | " f.truncate()" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": null, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "def replace(srr, name):\n", 41 | " \n", 42 | " func_replace(\"_static/figures/\", \"_static/lecture_specific/\"+srr+\"/\", name)\n", 43 | " \n", 44 | " func_replace(\"_static/code/\", \"_static/lecture_specific/\", name)\n", 45 | " \n", 46 | " func_replace(\"_static/pdfs/\", \"_static/lecture_specific/\"+srr+\"/\", name)" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "count=0\n", 56 | "for name in files:\n", 57 | " #name = \"von_neumann_model.tex\"\n", 58 | " srr =\"\"\n", 59 | " srr += name[0:len(name)-4]\n", 60 | " print(srr+\"\\n\")\n", 61 | " count+=1\n", 62 | " replace(srr,name)\n", 63 | " #make_changes(name)\n", 64 | " #sections_name(name)\n", 65 | " #func_replace(name[0:len(name)-4]+\"}\"+\"\\n\"+\" \\\\end{itemize}\"+\"\\n\"+\"\\\\end{itemize}\", name[0:len(name)-4]+\"}\"+\"\\n\"+\" \\\\end{itemize}\",name)\n", 66 | "\n", 67 | "print(count)" 68 | ] 69 | } 70 | ], 71 | "metadata": { 72 | "kernelspec": { 73 | "display_name": "Python 3", 74 | "language": "python", 75 | "name": "python3" 76 | }, 77 | "language_info": { 78 | "codemirror_mode": { 79 | "name": "ipython", 80 | "version": 3 81 | }, 82 | "file_extension": ".py", 83 | "mimetype": "text/x-python", 84 | "name": "python", 85 | "nbconvert_exporter": "python", 86 | "pygments_lexer": "ipython3", 87 | "version": "3.7.3" 88 | } 89 | }, 90 | "nbformat": 4, 91 | "nbformat_minor": 2 92 | } 93 | -------------------------------------------------------------------------------- /.github/workflows/cache.yml: -------------------------------------------------------------------------------- 1 | # !!! 2 | # Once https://github.com/actions/cache/issues/63 is merged 3 | # this can be enabled for daily cache for full HTML previews 4 | # !!! 5 | # name: Build Website Cache (Nightly) 6 | # on: 7 | # schedule: 8 | # - cron: '1 0 * * *' 9 | # jobs: 10 | # build-cache: 11 | # name: Build Website 12 | # runs-on: ubuntu-latest 13 | # steps: 14 | # - name: Checkout 15 | # uses: actions/checkout@v2 16 | # - name: Setup Anaconda 17 | # uses: goanpeca/setup-miniconda@v1 18 | # with: 19 | # auto-update-conda: true 20 | # auto-activate-base: true 21 | # miniconda-version: 'latest' 22 | # python-version: 3.7 23 | # environment-file: environment.yml 24 | # activate-environment: qe-lectures 25 | # - name: Checkout QuantEcon theme 26 | # uses: actions/checkout@v2 27 | # with: 28 | # repository: QuantEcon/lecture-python-advanced.theme 29 | # token: ${{ secrets.ACTIONS_PAT }} 30 | # path: theme/lecture-python-advanced.theme 31 | # - name: Get current date 32 | # id: date 33 | # run: echo "::set-output name=date::$(date +'%Y-%m-%d')" 34 | # - name: Cache Website Build Folder 35 | # id: cache 36 | # uses: actions/cache@v1 37 | # with: 38 | # path: _build 39 | # key: cache-sphinx-${{ steps.date.outputs.date }} 40 | # - name: Build Website files 41 | # shell: bash -l {0} 42 | # run: | 43 | # make website THEMEPATH=theme/lecture-python-advanced.theme 44 | # ls _build/website/jupyter_html/* 45 | name: Build Website Cache 46 | on: 47 | push: 48 | branches: 49 | - master 50 | jobs: 51 | build-cache: 52 | name: Build Website 53 | runs-on: ubuntu-latest 54 | steps: 55 | - name: Checkout 56 | uses: actions/checkout@v2 57 | - name: Setup Anaconda 58 | uses: conda-incubator/setup-miniconda@v2 59 | with: 60 | auto-update-conda: true 61 | auto-activate-base: true 62 | miniconda-version: 'latest' 63 | python-version: 3.8 64 | environment-file: environment.yml 65 | activate-environment: lecture-python-advanced 66 | - name: Checkout QuantEcon theme 67 | uses: actions/checkout@v2 68 | with: 69 | repository: QuantEcon/lecture-python-advanced.theme 70 | token: ${{ secrets.ACTIONS_PAT }} 71 | path: theme/lecture-python-advanced.theme 72 | - name: Cache Website Build Folder 73 | id: cache 74 | uses: actions/cache@v1 75 | with: 76 | path: _build 77 | key: cache-sphinx 78 | - name: Build Website files 79 | shell: bash -l {0} 80 | run: | 81 | make website THEMEPATH=theme/lecture-python-advanced.theme 82 | ls _build/website/jupyter_html/* -------------------------------------------------------------------------------- /source/rst/.ipynb_checkpoints/changethis-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import glob\n", 10 | "import re\n", 11 | "import os\n", 12 | "import errno\n", 13 | "path1 = '/home/anju/Documents/lecture-source-py/source/rst/*.rst'\n", 14 | "path2 = '*.tex'\n", 15 | "path = '*.rst'\n", 16 | "files = glob.glob(path)" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 6, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "def func_replace(a, b, filename):\n", 26 | " with open(filename,'r+', encoding=\"utf8\") as f:\n", 27 | " #convert to string:\n", 28 | " data = f.read()\n", 29 | " f.seek(0)\n", 30 | " f.write(data.replace(a, b))\n", 31 | " f.truncate()" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 7, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "def replace(srr, name):\n", 41 | " \n", 42 | " func_replace(\"_static/figures/\", \"_static/lecture_specific/\"+srr+\"/\", name)\n", 43 | " \n", 44 | " func_replace(\"_static/code/\", \"_static/lecture_specific/\", name)\n", 45 | " \n", 46 | " func_replace(\"_static/pdfs/\", \"_static/lecture_specific/\"+srr+\"/\", name)" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 8, 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "name": "stdout", 56 | "output_type": "stream", 57 | "text": [ 58 | "classical_filtering\n", 59 | "\n", 60 | "coase\n", 61 | "\n", 62 | "coleman_policy_iter\n", 63 | "\n", 64 | "amss\n", 65 | "\n", 66 | "amss2\n", 67 | "\n", 68 | "amss3\n", 69 | "\n", 70 | "complex_and_trig\n", 71 | "\n", 72 | "arma\n", 73 | "\n", 74 | "cass_koopmans\n", 75 | "\n", 76 | "arellano\n", 77 | "\n", 78 | "career\n", 79 | "\n", 80 | "chang_ramsey\n", 81 | "\n", 82 | "chang_credible\n", 83 | "\n", 84 | "cattle_cycles\n", 85 | "\n", 86 | "calvo\n", 87 | "\n", 88 | "black_litterman\n", 89 | "\n", 90 | "16\n" 91 | ] 92 | } 93 | ], 94 | "source": [ 95 | "count=0\n", 96 | "for name in files:\n", 97 | " #name = \"von_neumann_model.tex\"\n", 98 | " srr =\"\"\n", 99 | " srr += name[0:len(name)-4]\n", 100 | " print(srr+\"\\n\")\n", 101 | " count+=1\n", 102 | " replace(srr,name)\n", 103 | " #make_changes(name)\n", 104 | " #sections_name(name)\n", 105 | " #func_replace(name[0:len(name)-4]+\"}\"+\"\\n\"+\" \\\\end{itemize}\"+\"\\n\"+\"\\\\end{itemize}\", name[0:len(name)-4]+\"}\"+\"\\n\"+\" \\\\end{itemize}\",name)\n", 106 | "\n", 107 | "print(count)" 108 | ] 109 | } 110 | ], 111 | "metadata": { 112 | "kernelspec": { 113 | "display_name": "Python 3", 114 | "language": "python", 115 | "name": "python3" 116 | }, 117 | "language_info": { 118 | "codemirror_mode": { 119 | "name": "ipython", 120 | "version": 3 121 | }, 122 | "file_extension": ".py", 123 | "mimetype": "text/x-python", 124 | "name": "python", 125 | "nbconvert_exporter": "python", 126 | "pygments_lexer": "ipython3", 127 | "version": "3.7.3" 128 | } 129 | }, 130 | "nbformat": 4, 131 | "nbformat_minor": 2 132 | } 133 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := bash 2 | # 3 | # Makefile for Sphinx Extension Test Cases 4 | # 5 | 6 | # You can set these variables from the command line. 7 | SPHINXOPTS = -c "./" 8 | SPHINXBUILD = python -msphinx 9 | SPHINXPROJ = lecture-python-programming 10 | SOURCEDIR = source/rst 11 | BUILDDIR = _build 12 | BUILDWEBSITE = _build/website 13 | BUILDCOVERAGE = _build/coverage 14 | BUILDPDF = _build/pdf 15 | PORT = 8890 16 | FILES = 17 | THEMEPATH = theme/minimal 18 | TEMPLATEPATH = $(THEMEPATH)/templates 19 | 20 | # Put it first so that "make" without argument is like "make help". 21 | help: 22 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(FILES) $(SPHINXOPTS) $(O) 23 | 24 | .PHONY: help Makefile 25 | 26 | # Install requiremenets for building lectures. 27 | setup: 28 | pip install -r requirements.txt 29 | 30 | preview: 31 | ifeq (,$(filter $(target),website Website)) 32 | cd $(BUILDWEBSITE)/jupyter_html && python -m http.server $(PORT) 33 | else 34 | ifdef lecture 35 | cd $(BUILDDIR)/jupyter/ && jupyter notebook --port $(PORT) --port-retries=0 $(basename $(lecture)).ipynb 36 | else 37 | cd $(BUILDDIR)/jupyter/ && jupyter notebook --port $(PORT) --port-retries=0 38 | endif 39 | endif 40 | 41 | clean-coverage: 42 | rm -rf $(BUILDCOVERAGE) 43 | 44 | clean-website: 45 | rm -rf $(BUILDWEBSITE) 46 | 47 | clean-pdf: 48 | rm -rf $(BUILDDIR)/jupyterpdf 49 | 50 | coverage: 51 | ifneq ($(strip $(parallel)),) 52 | @$(SPHINXBUILD) -M jupyter "$(SOURCEDIR)" "$(BUILDCOVERAGE)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_make_coverage=1 -D jupyter_execute_notebooks=1 -D jupyter_ignore_skip_test=0 -D jupyter_theme_path="$(THEMEPATH)" -D jupyter_template_path="$(TEMPLATEPATH)" -D jupyter_template_coverage_file_path="error_report_template.html" -D jupyter_number_workers=$(parallel) 53 | else 54 | @$(SPHINXBUILD) -M jupyter "$(SOURCEDIR)" "$(BUILDCOVERAGE)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_make_coverage=1 -D jupyter_execute_notebooks=1 -D jupyter_ignore_skip_test=0 -D jupyter_theme_path="$(THEMEPATH)" -D jupyter_template_path="$(TEMPLATEPATH)" -D jupyter_template_coverage_file_path="error_report_template.html" 55 | endif 56 | 57 | website: 58 | echo "Theme: $(THEMEPATH)" 59 | ifneq ($(strip $(parallel)),) 60 | @$(SPHINXBUILD) -M jupyter "$(SOURCEDIR)" "$(BUILDWEBSITE)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_make_site=1 -D jupyter_generate_html=1 -D jupyter_download_nb=1 -D jupyter_execute_notebooks=1 -D jupyter_target_html=1 -D jupyter_download_nb_image_urlpath="https://s3-ap-southeast-2.amazonaws.com/python-programming.quantecon.org/_static/" -D jupyter_images_markdown=0 -D jupyter_theme_path="$(THEMEPATH)" -D jupyter_template_path="$(TEMPLATEPATH)" -D jupyter_html_template="html.tpl" -D jupyter_download_nb_urlpath="https://python-programming.quantecon.org/" -D jupyter_coverage_dir=$(BUILDCOVERAGE) -D jupyter_number_workers=$(parallel) 61 | 62 | else 63 | @$(SPHINXBUILD) -M jupyter "$(SOURCEDIR)" "$(BUILDWEBSITE)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_make_site=1 -D jupyter_generate_html=1 -D jupyter_download_nb=1 -D jupyter_execute_notebooks=1 -D jupyter_target_html=1 -D jupyter_download_nb_image_urlpath="https://s3-ap-southeast-2.amazonaws.com/python-programming.quantecon.org/_static/" -D jupyter_images_markdown=0 -D jupyter_theme_path="$(THEMEPATH)" -D jupyter_template_path="$(TEMPLATEPATH)" -D jupyter_html_template="html.tpl" -D jupyter_download_nb_urlpath="https://python-programming.quantecon.org/" -D jupyter_coverage_dir=$(BUILDCOVERAGE) 64 | endif 65 | 66 | pdf: 67 | ifneq ($(strip $(parallel)),) 68 | @$(SPHINXBUILD) -M jupyterpdf "$(SOURCEDIR)" "$(BUILDDIR)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_latex_template="latex.tpl" -D jupyter_theme_path="$(THEMEPATH)" -D jupyter_template_path="$(TEMPLATEPATH)" -D jupyter_latex_template_book="latex_book.tpl" -D jupyter_images_markdown=1 -D jupyter_execute_notebooks=1 -D jupyter_pdf_book=1 -D jupyter_target_pdf=1 -D jupyter_number_workers=$(parallel) 69 | 70 | else 71 | @$(SPHINXBUILD) -M jupyterpdf "$(SOURCEDIR)" "$(BUILDDIR)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_theme_path="$(THEMEPATH)" -D jupyter_template_path="$(TEMPLATEPATH)" -D jupyter_latex_template="latex.tpl" -D jupyter_latex_template_book="latex_book.tpl" -D jupyter_images_markdown=1 -D jupyter_execute_notebooks=1 -D jupyter_pdf_book=1 -D jupyter_target_pdf=1 72 | endif 73 | 74 | constructor-pdf: 75 | ifneq ($(strip $(parallel)),) 76 | @$(SPHINXBUILD) -M jupyter "$(SOURCEDIR)" "$(BUILDPDF)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_images_markdown=1 -D jupyter_execute_notebooks=1 -D jupyter_number_workers=$(parallel) 77 | 78 | else 79 | @$(SPHINXBUILD) -M jupyter "$(SOURCEDIR)" "$(BUILDPDF)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_images_markdown=1 -D jupyter_execute_notebooks=1 80 | endif 81 | 82 | notebooks: 83 | make jupyter 84 | 85 | # Catch-all target: route all unknown targets to Sphinx using the new 86 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 87 | %: Makefile 88 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_allow_html_only=1 89 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/lucas_model/lucastree.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.stats import lognorm 3 | from scipy.integrate import fixed_quad 4 | 5 | 6 | class LucasTree: 7 | """ 8 | Class to store parameters of a the Lucas tree model, a grid for the 9 | iteration step and some other helpful bits and pieces. 10 | 11 | Parameters 12 | ---------- 13 | γ : scalar(float) 14 | The coefficient of risk aversion in the household's CRRA utility 15 | function 16 | β : scalar(float) 17 | The household's discount factor 18 | α : scalar(float) 19 | The correlation coefficient in the shock process 20 | σ : scalar(float) 21 | The volatility of the shock process 22 | grid_size : int 23 | The size of the grid to use 24 | 25 | Attributes 26 | ---------- 27 | γ, β, α, σ, grid_size : see Parameters 28 | grid : ndarray 29 | Properties for grid upon which prices are evaluated 30 | ϕ : scipy.stats.lognorm 31 | The distribution for the shock process 32 | 33 | Examples 34 | -------- 35 | >>> tree = LucasTree(γ=2, β=0.95, α=0.90, σ=0.1) 36 | >>> price_vals = solve_lucas_model(tree) 37 | 38 | """ 39 | 40 | def __init__(self, 41 | γ=2, 42 | β=0.95, 43 | α=0.90, 44 | σ=0.1, 45 | grid_size=100): 46 | 47 | self.γ, self.β, self.α, self.σ = γ, β, α, σ 48 | 49 | # == Set the grid interval to contain most of the mass of the 50 | # stationary distribution of the consumption endowment == # 51 | ssd = self.σ / np.sqrt(1 - self.α**2) 52 | grid_min, grid_max = np.exp(-4 * ssd), np.exp(4 * ssd) 53 | self.grid = np.linspace(grid_min, grid_max, grid_size) 54 | self.grid_size = grid_size 55 | 56 | # == set up distribution for shocks == # 57 | self.ϕ = lognorm(σ) 58 | self.draws = self.ϕ.rvs(500) 59 | 60 | # == h(y) = β * int G(y,z)^(1-γ) ϕ(dz) == # 61 | self.h = np.empty(self.grid_size) 62 | for i, y in enumerate(self.grid): 63 | self.h[i] = β * np.mean((y**α * self.draws)**(1 - γ)) 64 | 65 | 66 | 67 | ## == Now the functions that act on a Lucas Tree == # 68 | 69 | def lucas_operator(f, tree, Tf=None): 70 | """ 71 | The approximate Lucas operator, which computes and returns the 72 | updated function Tf on the grid points. 73 | 74 | Parameters 75 | ---------- 76 | f : array_like(float) 77 | A candidate function on R_+ represented as points on a grid 78 | and should be flat NumPy array with len(f) = len(grid) 79 | 80 | tree : instance of LucasTree 81 | Stores the parameters of the problem 82 | 83 | Tf : array_like(float) 84 | Optional storage array for Tf 85 | 86 | Returns 87 | ------- 88 | Tf : array_like(float) 89 | The updated function Tf 90 | 91 | Notes 92 | ----- 93 | The argument `Tf` is optional, but recommended. If it is passed 94 | into this function, then we do not have to allocate any memory 95 | for the array here. As this function is often called many times 96 | in an iterative algorithm, this can save significant computation 97 | time. 98 | 99 | """ 100 | grid, h = tree.grid, tree.h 101 | α, β = tree.α, tree.β 102 | z_vec = tree.draws 103 | 104 | # == turn f into a function == # 105 | Af = lambda x: np.interp(x, grid, f) 106 | 107 | # == set up storage if needed == # 108 | if Tf is None: 109 | Tf = np.empty_like(f) 110 | 111 | # == Apply the T operator to f using Monte Carlo integration == # 112 | for i, y in enumerate(grid): 113 | Tf[i] = h[i] + β * np.mean(Af(y**α * z_vec)) 114 | 115 | return Tf 116 | 117 | def solve_lucas_model(tree, tol=1e-6, max_iter=500): 118 | """ 119 | Compute the equilibrium price function associated with Lucas 120 | tree 121 | 122 | Parameters 123 | ---------- 124 | tree : An instance of LucasTree 125 | Contains parameters 126 | tol : float 127 | error tolerance 128 | max_iter : int 129 | the maximum number of iterations 130 | 131 | Returns 132 | ------- 133 | price : array_like(float) 134 | The prices at the grid points in the attribute `grid` of the object 135 | 136 | """ 137 | 138 | # == simplify notation == # 139 | grid, grid_size = tree.grid, tree.grid_size 140 | γ = tree.γ 141 | 142 | # == Create storage array for lucas_operator. Reduces memory 143 | # allocation and speeds code up == # 144 | Tf = np.empty(grid_size) 145 | 146 | i = 0 147 | f = np.empty(grid_size) # Initial guess of f 148 | error = tol + 1 149 | 150 | while error > tol and i < max_iter: 151 | f_new = lucas_operator(f, tree, Tf) 152 | error = np.max(np.abs(f_new - f)) 153 | f[:] = f_new 154 | i += 1 155 | 156 | price = f * grid**γ # Back out price vector 157 | 158 | return price -------------------------------------------------------------------------------- /source/_static/lecture_specific/amss2/sequential_allocation.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.optimize import root 3 | from quantecon import MarkovChain 4 | 5 | 6 | class SequentialAllocation: 7 | 8 | ''' 9 | Class that takes CESutility or BGPutility object as input returns 10 | planner's allocation as a function of the multiplier on the 11 | implementability constraint μ. 12 | ''' 13 | 14 | def __init__(self, model): 15 | 16 | # Initialize from model object attributes 17 | self.β, self.π, self.G = model.β, model.π, model.G 18 | self.mc, self.Θ = MarkovChain(self.π), model.Θ 19 | self.S = len(model.π) # Number of states 20 | self.model = model 21 | 22 | # Find the first best allocation 23 | self.find_first_best() 24 | 25 | def find_first_best(self): 26 | ''' 27 | Find the first best allocation 28 | ''' 29 | model = self.model 30 | S, Θ, G = self.S, self.Θ, self.G 31 | Uc, Un = model.Uc, model.Un 32 | 33 | def res(z): 34 | c = z[:S] 35 | n = z[S:] 36 | return np.hstack([Θ * Uc(c, n) + Un(c, n), Θ * n - c - G]) 37 | 38 | res = root(res, 0.5 * np.ones(2 * S)) 39 | 40 | if not res.success: 41 | raise Exception('Could not find first best') 42 | 43 | self.cFB = res.x[:S] 44 | self.nFB = res.x[S:] 45 | 46 | # Multiplier on the resource constraint 47 | self.ΞFB = Uc(self.cFB, self.nFB) 48 | self.zFB = np.hstack([self.cFB, self.nFB, self.ΞFB]) 49 | 50 | def time1_allocation(self, μ): 51 | ''' 52 | Computes optimal allocation for time t >= 1 for a given μ 53 | ''' 54 | model = self.model 55 | S, Θ, G = self.S, self.Θ, self.G 56 | Uc, Ucc, Un, Unn = model.Uc, model.Ucc, model.Un, model.Unn 57 | 58 | def FOC(z): 59 | c = z[:S] 60 | n = z[S:2 * S] 61 | Ξ = z[2 * S:] 62 | # FOC of c 63 | return np.hstack([Uc(c, n) - μ * (Ucc(c, n) * c + Uc(c, n)) - Ξ, 64 | Un(c, n) - μ * (Unn(c, n) * n + Un(c, n)) \ 65 | + Θ * Ξ, # FOC of n 66 | Θ * n - c - G]) 67 | 68 | # Find the root of the first-order condition 69 | res = root(FOC, self.zFB) 70 | if not res.success: 71 | raise Exception('Could not find LS allocation.') 72 | z = res.x 73 | c, n, Ξ = z[:S], z[S:2 * S], z[2 * S:] 74 | 75 | # Compute x 76 | I = Uc(c, n) * c + Un(c, n) * n 77 | x = np.linalg.solve(np.eye(S) - self.β * self.π, I) 78 | 79 | return c, n, x, Ξ 80 | 81 | def time0_allocation(self, B_, s_0): 82 | ''' 83 | Finds the optimal allocation given initial government debt B_ and 84 | state s_0 85 | ''' 86 | model, π, Θ, G, β = self.model, self.π, self.Θ, self.G, self.β 87 | Uc, Ucc, Un, Unn = model.Uc, model.Ucc, model.Un, model.Unn 88 | 89 | # First order conditions of planner's problem 90 | def FOC(z): 91 | μ, c, n, Ξ = z 92 | xprime = self.time1_allocation(μ)[2] 93 | return np.hstack([Uc(c, n) * (c - B_) + Un(c, n) * n + β * π[s_0] 94 | @ xprime, 95 | Uc(c, n) - μ * (Ucc(c, n) 96 | * (c - B_) + Uc(c, n)) - Ξ, 97 | Un(c, n) - μ * (Unn(c, n) * n 98 | + Un(c, n)) + Θ[s_0] * Ξ, 99 | (Θ * n - c - G)[s_0]]) 100 | 101 | # Find root 102 | res = root(FOC, np.array( 103 | [0, self.cFB[s_0], self.nFB[s_0], self.ΞFB[s_0]])) 104 | if not res.success: 105 | raise Exception('Could not find time 0 LS allocation.') 106 | 107 | return res.x 108 | 109 | def time1_value(self, μ): 110 | ''' 111 | Find the value associated with multiplier μ 112 | ''' 113 | c, n, x, Ξ = self.time1_allocation(μ) 114 | U = self.model.U(c, n) 115 | V = np.linalg.solve(np.eye(self.S) - self.β * self.π, U) 116 | return c, n, x, V 117 | 118 | def Τ(self, c, n): 119 | ''' 120 | Computes Τ given c, n 121 | ''' 122 | model = self.model 123 | Uc, Un = model.Uc(c, n), model.Un(c, n) 124 | 125 | return 1 + Un / (self.Θ * Uc) 126 | 127 | def simulate(self, B_, s_0, T, sHist=None): 128 | ''' 129 | Simulates planners policies for T periods 130 | ''' 131 | model, π, β = self.model, self.π, self.β 132 | Uc = model.Uc 133 | 134 | if sHist is None: 135 | sHist = self.mc.simulate(T, s_0) 136 | 137 | cHist, nHist, Bhist, ΤHist, μHist = np.zeros((5, T)) 138 | RHist = np.zeros(T - 1) 139 | 140 | # Time 0 141 | μ, cHist[0], nHist[0], _ = self.time0_allocation(B_, s_0) 142 | ΤHist[0] = self.Τ(cHist[0], nHist[0])[s_0] 143 | Bhist[0] = B_ 144 | μHist[0] = μ 145 | 146 | # Time 1 onward 147 | for t in range(1, T): 148 | c, n, x, Ξ = self.time1_allocation(μ) 149 | Τ = self.Τ(c, n) 150 | u_c = Uc(c, n) 151 | s = sHist[t] 152 | Eu_c = π[sHist[t - 1]] @ u_c 153 | cHist[t], nHist[t], Bhist[t], ΤHist[t] = c[s], n[s], x[s] / u_c[s], \ 154 | Τ[s] 155 | RHist[t - 1] = Uc(cHist[t - 1], nHist[t - 1]) / (β * Eu_c) 156 | μHist[t] = μ 157 | 158 | return np.array([cHist, nHist, Bhist, ΤHist, sHist, μHist, RHist]) 159 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/opt_tax_recur/sequential_allocation.py: -------------------------------------------------------------------------------- 1 | class SequentialLS: 2 | 3 | ''' 4 | Class that takes a preference object, state transition matrix, 5 | and state contingent government expenditure plan as inputs, and 6 | solves the sequential allocation problem described above. 7 | It returns optimal allocations about consumption and labor supply, 8 | as well as the multiplier on the implementability constraint Φ. 9 | ''' 10 | 11 | def __init__(self, 12 | pref, 13 | π=0.5*np.ones((2, 2)), 14 | g=np.array([0.1, 0.2])): 15 | 16 | # Initialize from pref object attributes 17 | self.β, self.π, self.g = pref.β, π, g 18 | self.mc = MarkovChain(self.π) 19 | self.S = len(π) # Number of states 20 | self.pref = pref 21 | 22 | # Find the first best allocation 23 | self.find_first_best() 24 | 25 | def FOC_first_best(self, c, g): 26 | ''' 27 | First order conditions that characterize 28 | the first best allocation. 29 | ''' 30 | 31 | pref = self.pref 32 | Uc, Ul = pref.Uc, pref.Ul 33 | 34 | n = c + g 35 | l = 1 - n 36 | 37 | return Uc(c, l) - Ul(c, l) 38 | 39 | def find_first_best(self): 40 | ''' 41 | Find the first best allocation 42 | ''' 43 | S, g = self.S, self.g 44 | 45 | res = root(self.FOC_first_best, 0.5 * np.ones(S), args=(g,)) 46 | 47 | if (res.fun > 1e-10).any(): 48 | raise Exception('Could not find first best') 49 | 50 | self.cFB = res.x 51 | self.nFB = self.cFB + g 52 | 53 | def FOC_time1(self, c, Φ, g): 54 | ''' 55 | First order conditions that characterize 56 | optimal time 1 allocation problems. 57 | ''' 58 | 59 | pref = self.pref 60 | Uc, Ucc, Ul, Ull, Ulc = pref.Uc, pref.Ucc, pref.Ul, pref.Ull, pref.Ulc 61 | 62 | n = c + g 63 | l = 1 - n 64 | 65 | LHS = (1 + Φ) * Uc(c, l) + Φ * (c * Ucc(c, l) - n * Ulc(c, l)) 66 | RHS = (1 + Φ) * Ul(c, l) + Φ * (c * Ulc(c, l) - n * Ull(c, l)) 67 | 68 | diff = LHS - RHS 69 | 70 | return diff 71 | 72 | def time1_allocation(self, Φ): 73 | ''' 74 | Computes optimal allocation for time t >= 1 for a given Φ 75 | ''' 76 | pref = self.pref 77 | S, g = self.S, self.g 78 | 79 | # use the first best allocation as intial guess 80 | res = root(self.FOC_time1, self.cFB, args=(Φ, g)) 81 | 82 | if (res.fun > 1e-10).any(): 83 | raise Exception('Could not find LS allocation.') 84 | 85 | c = res.x 86 | n = c + g 87 | l = 1 - n 88 | 89 | # Compute x 90 | I = pref.Uc(c, n) * c - pref.Ul(c, l) * n 91 | x = np.linalg.solve(np.eye(S) - self.β * self.π, I) 92 | 93 | return c, n, x 94 | 95 | def FOC_time0(self, c0, Φ, g0, b0): 96 | ''' 97 | First order conditions that characterize 98 | time 0 allocation problem. 99 | ''' 100 | 101 | pref = self.pref 102 | Ucc, Ulc = pref.Ucc, pref.Ulc 103 | 104 | n0 = c0 + g0 105 | l0 = 1 - n0 106 | 107 | diff = self.FOC_time1(c0, Φ, g0) 108 | diff -= Φ * (Ucc(c0, l0) - Ulc(c0, l0)) * b0 109 | 110 | return diff 111 | 112 | def implementability(self, Φ, b0, s0, cn0_arr): 113 | ''' 114 | Compute the differences between the RHS and LHS 115 | of the implementability constraint given Φ, 116 | initial debt, and initial state. 117 | ''' 118 | 119 | pref, π, g, β = self.pref, self.π, self.g, self.β 120 | Uc, Ul = pref.Uc, pref.Ul 121 | g0 = self.g[s0] 122 | 123 | c, n, x = self.time1_allocation(Φ) 124 | 125 | res = root(self.FOC_time0, cn0_arr[0], args=(Φ, g0, b0)) 126 | c0 = res.x 127 | n0 = c0 + g0 128 | l0 = 1 - n0 129 | 130 | cn0_arr[:] = c0, n0 131 | 132 | LHS = Uc(c0, l0) * b0 133 | RHS = Uc(c0, l0) * c0 - Ul(c0, l0) * n0 + β * π[s0] @ x 134 | 135 | return RHS - LHS 136 | 137 | def time0_allocation(self, b0, s0): 138 | ''' 139 | Finds the optimal time 0 allocation given 140 | initial government debt b0 and state s0 141 | ''' 142 | 143 | # use the first best allocation as initial guess 144 | cn0_arr = np.array([self.cFB[s0], self.nFB[s0]]) 145 | 146 | res = root(self.implementability, 0., args=(b0, s0, cn0_arr)) 147 | 148 | if (res.fun > 1e-10).any(): 149 | raise Exception('Could not find time 0 LS allocation.') 150 | 151 | Φ = res.x[0] 152 | c0, n0 = cn0_arr 153 | 154 | return Φ, c0, n0 155 | 156 | def τ(self, c, n): 157 | ''' 158 | Computes τ given c, n 159 | ''' 160 | pref = self.pref 161 | Uc, Ul = pref.Uc, pref.Ul 162 | 163 | return 1 - Ul(c, 1-n) / Uc(c, 1-n) 164 | 165 | def simulate(self, b0, s0, T, sHist=None): 166 | ''' 167 | Simulates planners policies for T periods 168 | ''' 169 | pref, π, β = self.pref, self.π, self.β 170 | Uc = pref.Uc 171 | 172 | if sHist is None: 173 | sHist = self.mc.simulate(T, s0) 174 | 175 | cHist, nHist, Bhist, τHist, ΦHist = np.empty((5, T)) 176 | RHist = np.empty(T-1) 177 | 178 | # Time 0 179 | Φ, cHist[0], nHist[0] = self.time0_allocation(b0, s0) 180 | τHist[0] = self.τ(cHist[0], nHist[0]) 181 | Bhist[0] = b0 182 | ΦHist[0] = Φ 183 | 184 | # Time 1 onward 185 | for t in range(1, T): 186 | c, n, x = self.time1_allocation(Φ) 187 | τ = self.τ(c, n) 188 | u_c = Uc(c, 1-n) 189 | s = sHist[t] 190 | Eu_c = π[sHist[t-1]] @ u_c 191 | cHist[t], nHist[t], Bhist[t], τHist[t] = c[s], n[s], x[s] / u_c[s], τ[s] 192 | RHist[t-1] = Uc(cHist[t-1], 1-nHist[t-1]) / (β * Eu_c) 193 | ΦHist[t] = Φ 194 | 195 | gHist = self.g[sHist] 196 | yHist = nHist 197 | 198 | return [cHist, nHist, Bhist, τHist, gHist, yHist, sHist, ΦHist, RHist] 199 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/amss/recursive_allocation.py: -------------------------------------------------------------------------------- 1 | class AMSS: 2 | # WARNING: THE CODE IS EXTREMELY SENSITIVE TO CHOCIES OF PARAMETERS. 3 | # DO NOT CHANGE THE PARAMETERS AND EXPECT IT TO WORK 4 | 5 | def __init__(self, pref, β, Π, g, x_grid, bounds_v): 6 | self.β, self.Π, self.g = β, Π, g 7 | self.x_grid = x_grid 8 | self.n = x_grid[0][2] 9 | self.S = len(Π) 10 | self.bounds = bounds_v 11 | self.pref = pref 12 | 13 | self.T_v, self.T_w = bellman_operator_factory(Π, β, x_grid, g, 14 | bounds_v) 15 | 16 | self.V_solved = False 17 | self.W_solved = False 18 | 19 | def compute_V(self, V, σ_v_star, tol_vfi, maxitr, print_itr): 20 | 21 | T_v = self.T_v 22 | 23 | self.success = False 24 | 25 | V_new = np.zeros_like(V) 26 | 27 | Δ = 1.0 28 | for itr in range(maxitr): 29 | T_v(V, V_new, σ_v_star, self.pref) 30 | 31 | Δ = np.max(np.abs(V_new - V)) 32 | 33 | if Δ < tol_vfi: 34 | self.V_solved = True 35 | print('Successfully completed VFI after %i iterations' 36 | % (itr+1)) 37 | break 38 | 39 | if (itr + 1) % print_itr == 0: 40 | print('Error at iteration %i : ' % (itr + 1), Δ) 41 | 42 | V[:] = V_new[:] 43 | 44 | self.V = V 45 | self.σ_v_star = σ_v_star 46 | 47 | return V, σ_v_star 48 | 49 | def compute_W(self, b_0, W, σ_w_star): 50 | T_w = self.T_w 51 | V = self.V 52 | 53 | T_w(W, σ_w_star, V, b_0, self.pref) 54 | 55 | self.W = W 56 | self.σ_w_star = σ_w_star 57 | self.W_solved = True 58 | print('Succesfully solved the time 0 problem.') 59 | 60 | return W, σ_w_star 61 | 62 | def solve(self, V, σ_v_star, b_0, W, σ_w_star, tol_vfi=1e-7, 63 | maxitr=1000, print_itr=10): 64 | print("===============") 65 | print("Solve time 1 problem") 66 | print("===============") 67 | self.compute_V(V, σ_v_star, tol_vfi, maxitr, print_itr) 68 | print("===============") 69 | print("Solve time 0 problem") 70 | print("===============") 71 | self.compute_W(b_0, W, σ_w_star) 72 | 73 | def simulate(self, s_hist, b_0): 74 | if not (self.V_solved and self.W_solved): 75 | msg = "V and W need to be successfully computed before simulation." 76 | raise ValueError(msg) 77 | 78 | pref = self.pref 79 | x_grid, g, β, S = self.x_grid, self.g, self.β, self.S 80 | σ_v_star, σ_w_star = self.σ_v_star, self.σ_w_star 81 | 82 | T = len(s_hist) 83 | s_0 = s_hist[0] 84 | 85 | # Pre-allocate 86 | n_hist = np.zeros(T) 87 | x_hist = np.zeros(T) 88 | c_hist = np.zeros(T) 89 | τ_hist = np.zeros(T) 90 | b_hist = np.zeros(T) 91 | g_hist = np.zeros(T) 92 | 93 | # Compute t = 0 94 | l_0, T_0 = σ_w_star[s_0] 95 | c_0 = (1 - l_0) - g[s_0] 96 | x_0 = (-pref.Uc(c_0, l_0) * (c_0 - T_0 - b_0) + 97 | pref.Ul(c_0, l_0) * (1 - l_0)) 98 | 99 | n_hist[0] = (1 - l_0) 100 | x_hist[0] = x_0 101 | c_hist[0] = c_0 102 | τ_hist[0] = 1 - pref.Ul(c_0, l_0) / pref.Uc(c_0, l_0) 103 | b_hist[0] = b_0 104 | g_hist[0] = g[s_0] 105 | 106 | # Compute t > 0 107 | for t in range(T - 1): 108 | x_ = x_hist[t] 109 | s_ = s_hist[t] 110 | l = np.zeros(S) 111 | T = np.zeros(S) 112 | for s in range(S): 113 | x_arr = np.array([x_]) 114 | l[s] = eval_linear(x_grid, σ_v_star[s_, :, s], x_arr) 115 | T[s] = eval_linear(x_grid, σ_v_star[s_, :, S+s], x_arr) 116 | 117 | c = (1 - l) - g 118 | u_c = pref.Uc(c, l) 119 | Eu_c = Π[s_] @ u_c 120 | 121 | x = u_c * x_ / (β * Eu_c) - u_c * (c - T) + pref.Ul(c, l) * (1 - l) 122 | 123 | c_next = c[s_hist[t+1]] 124 | l_next = l[s_hist[t+1]] 125 | 126 | x_hist[t+1] = x[s_hist[t+1]] 127 | n_hist[t+1] = 1 - l_next 128 | c_hist[t+1] = c_next 129 | τ_hist[t+1] = 1 - pref.Ul(c_next, l_next) / pref.Uc(c_next, l_next) 130 | b_hist[t+1] = x_ / (β * Eu_c) 131 | g_hist[t+1] = g[s_hist[t+1]] 132 | 133 | return c_hist, n_hist, b_hist, τ_hist, g_hist, n_hist 134 | 135 | 136 | def obj_factory(Π, β, x_grid, g): 137 | S = len(Π) 138 | 139 | @njit 140 | def obj_V(σ, state, V, pref): 141 | # Unpack state 142 | s_, x_ = state 143 | 144 | l = σ[:S] 145 | T = σ[S:] 146 | 147 | c = (1 - l) - g 148 | u_c = pref.Uc(c, l) 149 | Eu_c = Π[s_] @ u_c 150 | x = u_c * x_ / (β * Eu_c) - u_c * (c - T) + pref.Ul(c, l) * (1 - l) 151 | 152 | V_next = np.zeros(S) 153 | 154 | for s in range(S): 155 | V_next[s] = eval_linear(x_grid, V[s], np.array([x[s]])) 156 | 157 | out = Π[s_] @ (pref.U(c, l) + β * V_next) 158 | 159 | return out 160 | 161 | @njit 162 | def obj_W(σ, state, V, pref): 163 | # Unpack state 164 | s_, b_0 = state 165 | l, T = σ 166 | 167 | c = (1 - l) - g[s_] 168 | x = -pref.Uc(c, l) * (c - T - b_0) + pref.Ul(c, l) * (1 - l) 169 | 170 | V_next = eval_linear(x_grid, V[s_], np.array([x])) 171 | 172 | out = pref.U(c, l) + β * V_next 173 | 174 | return out 175 | 176 | return obj_V, obj_W 177 | 178 | 179 | def bellman_operator_factory(Π, β, x_grid, g, bounds_v): 180 | obj_V, obj_W = obj_factory(Π, β, x_grid, g) 181 | n = x_grid[0][2] 182 | S = len(Π) 183 | x_nodes = nodes(x_grid) 184 | 185 | @njit(parallel=True) 186 | def T_v(V, V_new, σ_star, pref): 187 | for s_ in prange(S): 188 | for x_i in prange(n): 189 | state = (s_, x_nodes[x_i]) 190 | x0 = σ_star[s_, x_i] 191 | res = optimize.nelder_mead(obj_V, x0, bounds=bounds_v, 192 | args=(state, V, pref)) 193 | 194 | if res.success: 195 | V_new[s_, x_i] = res.fun 196 | σ_star[s_, x_i] = res.x 197 | else: 198 | print("Optimization routine failed.") 199 | 200 | bounds_w = np.array([[-9.0, 1.0], [0., 10.]]) 201 | 202 | def T_w(W, σ_star, V, b_0, pref): 203 | for s_ in prange(S): 204 | state = (s_, b_0) 205 | x0 = σ_star[s_] 206 | res = optimize.nelder_mead(obj_W, x0, bounds=bounds_w, 207 | args=(state, V, pref)) 208 | 209 | W[s_] = res.fun 210 | σ_star[s_] = res.x 211 | 212 | return T_v, T_w 213 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/opt_tax_recur/recursive_allocation.py: -------------------------------------------------------------------------------- 1 | class RecursiveLS: 2 | 3 | ''' 4 | Compute the planner's allocation by solving Bellman 5 | equation. 6 | ''' 7 | 8 | def __init__(self, 9 | pref, 10 | x_grid, 11 | π=0.5*np.ones((2, 2)), 12 | g=np.array([0.1, 0.2])): 13 | 14 | self.π, self.g, self.S = π, g, len(π) 15 | self.pref, self.x_grid = pref, x_grid 16 | 17 | bounds = np.empty((self.S, 2)) 18 | 19 | # bound for n 20 | bounds[0] = 0, 1 21 | 22 | # bound for xprime 23 | for s in range(self.S-1): 24 | bounds[s+1] = x_grid.min(), x_grid.max() 25 | 26 | self.bounds = bounds 27 | 28 | # initialization of time 1 value function 29 | self.V = None 30 | 31 | def time1_allocation(self, V=None, tol=1e-7): 32 | ''' 33 | Solve the optimal time 1 allocation problem 34 | by iterating Bellman value function. 35 | ''' 36 | 37 | π, g, S = self.π, self.g, self.S 38 | pref, x_grid, bounds = self.pref, self.x_grid, self.bounds 39 | 40 | # initial guess of value function 41 | if V is None: 42 | V = np.zeros((len(x_grid), S)) 43 | 44 | # initial guess of policy 45 | z = np.empty((len(x_grid), S, S+2)) 46 | 47 | # guess of n 48 | z[:, :, 1] = 0.5 49 | 50 | # guess of xprime 51 | for s in range(S): 52 | for i in range(S-1): 53 | z[:, s, i+2] = x_grid 54 | 55 | while True: 56 | # value function iteration 57 | V_new, z_new = T(V, z, pref, π, g, x_grid, bounds) 58 | 59 | if np.max(np.abs(V - V_new)) < tol: 60 | break 61 | 62 | V = V_new 63 | z = z_new 64 | 65 | self.V = V_new 66 | self.z1 = z_new 67 | self.c1 = z_new[:, :, 0] 68 | self.n1 = z_new[:, :, 1] 69 | self.xprime1 = z_new[:, :, 2:] 70 | 71 | return V_new, z_new 72 | 73 | def time0_allocation(self, b0, s0): 74 | ''' 75 | Find the optimal time 0 allocation by maximization. 76 | ''' 77 | 78 | if self.V is None: 79 | self.time1_allocation() 80 | 81 | π, g, S = self.π, self.g, self.S 82 | pref, x_grid, bounds = self.pref, self.x_grid, self.bounds 83 | V, z1 = self.V, self.z1 84 | 85 | x = 1. # x is arbitrary 86 | res = nelder_mead(obj_V, 87 | z1[0, s0, 1:-1], 88 | args=(x, s0, V, pref, π, g, x_grid, b0), 89 | bounds=bounds, 90 | tol_f=1e-10) 91 | 92 | n0, xprime0 = IC(res.x, x, s0, b0, pref, π, g) 93 | c0 = n0 - g[s0] 94 | z0 = np.array([c0, n0, *xprime0]) 95 | 96 | self.z0 = z0 97 | self.n0 = n0 98 | self.c0 = n0 - g[s0] 99 | self.xprime0 = xprime0 100 | 101 | return z0 102 | 103 | def τ(self, c, n): 104 | ''' 105 | Computes τ given c, n 106 | ''' 107 | pref = self.pref 108 | uc, ul = pref.Uc(c, 1-n), pref.Ul(c, 1-n) 109 | 110 | return 1 - ul / uc 111 | 112 | def simulate(self, b0, s0, T, sHist=None): 113 | ''' 114 | Simulates Ramsey plan for T periods 115 | ''' 116 | pref, π = self.pref, self.π 117 | Uc = pref.Uc 118 | 119 | if sHist is None: 120 | sHist = self.mc.simulate(T, s0) 121 | 122 | cHist, nHist, Bhist, τHist, xHist = np.empty((5, T)) 123 | RHist = np.zeros(T-1) 124 | 125 | # Time 0 126 | self.time0_allocation(b0, s0) 127 | cHist[0], nHist[0], xHist[0] = self.c0, self.n0, self.xprime0[s0] 128 | τHist[0] = self.τ(cHist[0], nHist[0]) 129 | Bhist[0] = b0 130 | 131 | # Time 1 onward 132 | for t in range(1, T): 133 | s, x = sHist[t], xHist[t-1] 134 | cHist[t] = interp(self.x_grid, self.c1[:, s], x) 135 | nHist[t] = interp(self.x_grid, self.n1[:, s], x) 136 | 137 | τHist[t] = self.τ(cHist[t], nHist[t]) 138 | 139 | Bhist[t] = x / Uc(cHist[t], 1-nHist[t]) 140 | 141 | c, n = np.empty((2, self.S)) 142 | for sprime in range(self.S): 143 | c[sprime] = interp(x_grid, self.c1[:, sprime], x) 144 | n[sprime] = interp(x_grid, self.n1[:, sprime], x) 145 | Euc = π[sHist[t-1]] @ Uc(c, 1-n) 146 | RHist[t-1] = Uc(cHist[t-1], 1-nHist[t-1]) / (self.pref.β * Euc) 147 | 148 | gHist = self.g[sHist] 149 | yHist = nHist 150 | 151 | if t < T-1: 152 | sprime = sHist[t+1] 153 | xHist[t] = interp(self.x_grid, self.xprime1[:, s, sprime], x) 154 | 155 | return [cHist, nHist, Bhist, τHist, gHist, yHist, xHist, RHist] 156 | 157 | # Helper functions 158 | 159 | @njit(parallel=True) 160 | def T(V, z, pref, π, g, x_grid, bounds): 161 | ''' 162 | One step iteration of Bellman value function. 163 | ''' 164 | 165 | S = len(π) 166 | 167 | V_new = np.empty_like(V) 168 | z_new = np.empty_like(z) 169 | 170 | for i in prange(len(x_grid)): 171 | x = x_grid[i] 172 | for s in prange(S): 173 | res = nelder_mead(obj_V, 174 | z[i, s, 1:-1], 175 | args=(x, s, V, pref, π, g, x_grid), 176 | bounds=bounds, 177 | tol_f=1e-10) 178 | 179 | # optimal policy 180 | n, xprime = IC(res.x, x, s, None, pref, π, g) 181 | z_new[i, s, 0] = n - g[s] # c 182 | z_new[i, s, 1] = n # n 183 | z_new[i, s, 2:] = xprime # xprime 184 | 185 | V_new[i, s] = res.fun 186 | 187 | return V_new, z_new 188 | 189 | @njit 190 | def obj_V(z_sub, x, s, V, pref, π, g, x_grid, b0=None): 191 | ''' 192 | The objective on the right hand side of the Bellman equation. 193 | z_sub contains guesses of n and xprime[:-1]. 194 | ''' 195 | 196 | S = len(π) 197 | β, U = pref.β, pref.U 198 | 199 | # find (n, xprime) that satisfies implementability constraint 200 | n, xprime = IC(z_sub, x, s, b0, pref, π, g) 201 | c, l = n-g[s], 1-n 202 | 203 | # if xprime[-1] violates bound, return large penalty 204 | if (xprime[-1] < x_grid.min()): 205 | return -1e9 * (1 + np.abs(xprime[-1] - x_grid.min())) 206 | elif (xprime[-1] > x_grid.max()): 207 | return -1e9 * (1 + np.abs(xprime[-1] - x_grid.max())) 208 | 209 | # prepare Vprime vector 210 | Vprime = np.empty(S) 211 | for sprime in range(S): 212 | Vprime[sprime] = interp(x_grid, V[:, sprime], xprime[sprime]) 213 | 214 | # compute the objective value 215 | obj = U(c, l) + β * π[s] @ Vprime 216 | 217 | return obj 218 | 219 | @njit 220 | def IC(z_sub, x, s, b0, pref, π, g): 221 | ''' 222 | Find xprime[-1] that satisfies the implementability condition 223 | given the guesses of n and xprime[:-1]. 224 | ''' 225 | 226 | β, Uc, Ul = pref.β, pref.Uc, pref.Ul 227 | 228 | n = z_sub[0] 229 | xprime = np.empty(len(π)) 230 | xprime[:-1] = z_sub[1:] 231 | 232 | c, l = n-g[s], 1-n 233 | uc = Uc(c, l) 234 | ul = Ul(c, l) 235 | 236 | if b0 is None: 237 | diff = x 238 | else: 239 | diff = uc * b0 240 | 241 | diff -= uc * (n - g[s]) - ul * n + β * π[s][:-1] @ xprime[:-1] 242 | xprime[-1] = diff / (β * π[s][-1]) 243 | 244 | return n, xprime 245 | -------------------------------------------------------------------------------- /source/rst/lucas_asset_pricing_dles.rst: -------------------------------------------------------------------------------- 1 | .. _lucas_asset_pricing_dles: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | .. index:: 6 | single: python 7 | 8 | ***************************** 9 | Lucas Asset Pricing Using DLE 10 | ***************************** 11 | 12 | .. contents:: :depth: 2 13 | 14 | 15 | This is one of a suite of lectures that use the quantecon DLE class to instantiate models within the 16 | :cite:`HS2013` class of models described in detail in :doc:`Recursive Models of Dynamic Linear Economies `. 17 | 18 | 19 | In addition to what's in Anaconda, this lecture uses the quantecon library 20 | 21 | .. code-block:: ipython 22 | :class: hide-output 23 | 24 | !pip install --upgrade quantecon 25 | 26 | This lecture uses the DLE class to price payout 27 | streams that are linear functions of the economy's state vector, as well 28 | as risk-free assets that pay out one unit of the first consumption good 29 | with certainty. 30 | 31 | We assume basic knowledge of the class of economic environments that fall within the domain of the 32 | DLE class. 33 | 34 | Many details about the basic environment are contained in the lecture 35 | :doc:`Growth in Dynamic Linear Economies `. 36 | 37 | We'll also need the following imports 38 | 39 | .. code-block:: ipython 40 | 41 | import numpy as np 42 | import matplotlib.pyplot as plt 43 | from quantecon import LQ 44 | from quantecon import DLE 45 | %matplotlib inline 46 | 47 | We use a linear-quadratic version of an economy that Lucas (1978) :cite:`Lucas1978` used 48 | to develop an equilibrium theory of asset prices: 49 | 50 | **Preferences** 51 | 52 | .. math:: -\frac{1}{2}\mathbb{E}\sum_{t=0}^\infty \beta^t[(c_t - b_t)^2 + l_t^2]|J_0 53 | 54 | .. math:: s_t = c_t 55 | 56 | .. math:: b_t = U_bz_t 57 | 58 | **Technology** 59 | 60 | .. math:: c_t = d_{1t} 61 | 62 | .. math:: k_t = \delta_k k_{t-1} + i_t 63 | 64 | .. math:: g_t = \phi_1 i_t \, , \phi_1 > 0 65 | 66 | .. math:: 67 | 68 | \left[ {\begin{array}{c} 69 | d_{1t} \\ 0 70 | \end{array} } 71 | \right] = U_dz_t 72 | 73 | **Information** 74 | 75 | .. math:: 76 | 77 | z_{t+1} = 78 | \left[ {\begin{array}{ccc} 79 | 1 & 0 & 0 \\ 0 & 0.8 & 0 \\ 0 & 0 & 0.5 80 | \end{array} } 81 | \right] 82 | z_t + 83 | \left[ {\begin{array}{cc} 84 | 0 & 0 \\ 1 & 0 \\ 0 & 1 85 | \end{array} } 86 | \right] 87 | w_{t+1} 88 | 89 | .. math:: 90 | 91 | U_b = 92 | \left[ {\begin{array}{ccc} 93 | 30 & 0 & 0 94 | \end{array} } 95 | \right] 96 | 97 | .. math:: 98 | 99 | U_d = 100 | \left[ {\begin{array}{ccc} 101 | 5 & 1 & 0 \\ 0 & 0 & 0 102 | \end{array} } 103 | \right] 104 | 105 | .. math:: 106 | 107 | x_0 = 108 | \left[ {\begin{array}{ccccc} 109 | 5 & 150 & 1 & 0 & 0 110 | \end{array} } 111 | \right]' 112 | 113 | Asset Pricing Equations 114 | ======================= 115 | 116 | :cite:`HS2013` show that the time t value of a permanent claim to a stream 117 | :math:`y_s = U_ax_s \, , s \geq t` is: 118 | 119 | .. math:: a_t = (x_t'\mu_ax_t + \sigma_a)/(\bar e _1M_cx_t) 120 | 121 | with 122 | 123 | .. math:: \mu_a = \sum_{\tau = 0}^\infty \beta^\tau(A^{o'})^\tau Z_a A^{o\tau} 124 | 125 | .. math:: \sigma_a = \frac{\beta}{1-\beta} \text{trace} (Z_a \sum_{\tau = 0}^\infty \beta^\tau (A^{o})^\tau C C^{'} (A^{o'})^\tau) 126 | 127 | where 128 | 129 | .. math:: Z_a = U_a^{'}M_c 130 | 131 | The use of :math:`\bar e _1` indicates that the first consumption good 132 | is the numeraire. 133 | 134 | Asset Pricing Simulations 135 | ========================= 136 | 137 | .. code-block:: python3 138 | 139 | gam = 0 140 | γ = np.array([[gam], [0]]) 141 | ϕ_c = np.array([[1], [0]]) 142 | ϕ_g = np.array([[0], [1]]) 143 | ϕ_1 = 1e-4 144 | ϕ_i = np.array([[0], [-ϕ_1]]) 145 | δ_k = np.array([[.95]]) 146 | θ_k = np.array([[1]]) 147 | β = np.array([[1 / 1.05]]) 148 | ud = np.array([[5, 1, 0], 149 | [0, 0, 0]]) 150 | a22 = np.array([[1, 0, 0], 151 | [0, 0.8, 0], 152 | [0, 0, 0.5]]) 153 | c2 = np.array([[0, 1, 0], 154 | [0, 0, 1]]).T 155 | l_λ = np.array([[0]]) 156 | π_h = np.array([[1]]) 157 | δ_h = np.array([[.9]]) 158 | θ_h = np.array([[1]]) - δ_h 159 | ub = np.array([[30, 0, 0]]) 160 | x0 = np.array([[5, 150, 1, 0, 0]]).T 161 | 162 | info1 = (a22, c2, ub, ud) 163 | tech1 = (ϕ_c, ϕ_g, ϕ_i, γ, δ_k, θ_k) 164 | pref1 = (β, l_λ, π_h, δ_h, θ_h) 165 | 166 | .. code-block:: python3 167 | 168 | econ1 = DLE(info1, tech1, pref1) 169 | 170 | After specifying a "Pay" matrix, we simulate the economy. 171 | 172 | The particular choice of "Pay" used below means that we are pricing a 173 | perpetual claim on the endowment process :math:`d_{1t}` 174 | 175 | .. code-block:: python3 176 | 177 | econ1.compute_sequence(x0, ts_length=100, Pay=np.array([econ1.Sd[0, :]])) 178 | 179 | The graph below plots the price of this claim over time: 180 | 181 | .. code-block:: python3 182 | 183 | ### Fig 7.12.1 from p.147 of HS2013 184 | plt.plot(econ1.Pay_Price, label='Price of Tree') 185 | plt.legend() 186 | plt.show() 187 | 188 | The next plot displays the realized gross rate of return on this "Lucas 189 | tree" as well as on a risk-free one-period bond: 190 | 191 | .. code-block:: python3 192 | 193 | ### Left panel of Fig 7.12.2 from p.148 of HS2013 194 | plt.plot(econ1.Pay_Gross, label='Tree') 195 | plt.plot(econ1.R1_Gross, label='Risk-Free') 196 | plt.legend() 197 | plt.show() 198 | 199 | .. code-block:: python3 200 | 201 | np.corrcoef(econ1.Pay_Gross[1:, 0], econ1.R1_Gross[1:, 0]) 202 | 203 | 204 | Above we have also calculated the correlation coefficient between these 205 | two returns. 206 | 207 | To give an idea of how the term structure of interest rates moves in 208 | this economy, the next plot displays the *net* rates of return on 209 | one-period and five-period risk-free bonds: 210 | 211 | .. code-block:: python3 212 | 213 | ### Right panel of Fig 7.12.2 from p.148 of HS2013 214 | plt.plot(econ1.R1_Net, label='One-Period') 215 | plt.plot(econ1.R5_Net, label='Five-Period') 216 | plt.legend() 217 | plt.show() 218 | 219 | From the above plot, we can see the tendency of the term structure to 220 | slope up when rates are low and to slope down when rates are high. 221 | 222 | Comparing it to the previous plot of the price of the "Lucas tree", we 223 | can also see that net rates of return are low when the price of the tree 224 | is high, and vice versa. 225 | 226 | We now plot the realized gross rate of return on a "Lucas tree" as well 227 | as on a risk-free one-period bond when the autoregressive parameter for 228 | the endowment process is reduced to 0.4: 229 | 230 | .. code-block:: python3 231 | 232 | a22_2 = np.array([[1, 0, 0], 233 | [0, 0.4, 0], 234 | [0, 0, 0.5]]) 235 | info2 = (a22_2, c2, ub, ud) 236 | 237 | econ2 = DLE(info2, tech1, pref1) 238 | econ2.compute_sequence(x0, ts_length=100, Pay=np.array([econ2.Sd[0, :]])) 239 | 240 | .. code-block:: python3 241 | 242 | ### Left panel of Fig 7.12.3 from p.148 of HS2013 243 | plt.plot(econ2.Pay_Gross, label='Tree') 244 | plt.plot(econ2.R1_Gross, label='Risk-Free') 245 | plt.legend() 246 | plt.show() 247 | 248 | .. code-block:: python3 249 | 250 | np.corrcoef(econ2.Pay_Gross[1:, 0], econ2.R1_Gross[1:, 0]) 251 | 252 | 253 | The correlation between these two gross rates is now more negative. 254 | 255 | Next, we again plot the *net* rates of return on one-period and 256 | five-period risk-free bonds: 257 | 258 | .. code-block:: python3 259 | 260 | ### Right panel of Fig 7.12.3 from p.148 of HS2013 261 | plt.plot(econ2.R1_Net, label='One-Period') 262 | plt.plot(econ2.R5_Net, label='Five-Period') 263 | plt.legend() 264 | plt.show() 265 | 266 | We can see the tendency of the term structure to slope up when rates are 267 | low (and down when rates are high) has been accentuated relative to the 268 | first instance of our economy. 269 | -------------------------------------------------------------------------------- /source/rst/irfs_in_hall_model.rst: -------------------------------------------------------------------------------- 1 | .. _irfs_in_hall_model: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | .. index:: 6 | single: python 7 | 8 | **************************** 9 | IRFs in Hall Models 10 | **************************** 11 | 12 | .. contents:: :depth: 2 13 | 14 | 15 | This is another member of a suite of lectures that use the quantecon DLE class to instantiate models within the 16 | :cite:`HS2013` class of models described in detail in :doc:`Recursive Models of Dynamic Linear Economies `. 17 | 18 | In addition to what's in Anaconda, this lecture uses the quantecon library. 19 | 20 | .. code-block:: ipython 21 | :class: hide-output 22 | 23 | !pip install --upgrade quantecon 24 | 25 | We'll make these imports: 26 | 27 | .. code-block:: ipython 28 | 29 | import numpy as np 30 | import matplotlib.pyplot as plt 31 | %matplotlib inline 32 | from quantecon import LQ 33 | from quantecon import DLE 34 | 35 | This lecture shows how the DLE class can be used to create impulse 36 | response functions for three related economies, starting from 37 | Hall (1978) :cite:`Hall1978`. 38 | 39 | Knowledge of the basic economic environment is assumed. 40 | 41 | See the lecture "Growth in Dynamic Linear Economies" for more details. 42 | 43 | Example 1: Hall (1978) 44 | ======================= 45 | 46 | First, we set parameters to make consumption (almost) follow a random 47 | walk. 48 | 49 | We set 50 | 51 | .. math:: \lambda = 0, \pi = 1, \gamma_1 = 0.1, \phi_1 = 0.00001, \delta_k = 0.95, \beta = \frac{1}{1.05} 52 | 53 | (In this example :math:`\delta_h` and :math:`\theta_h` are arbitrary as 54 | household capital does not enter the equation for consumption services. 55 | 56 | We set them to values that will become useful in Example 3) 57 | 58 | It is worth noting that this choice of parameter values ensures that 59 | :math:`\beta(\gamma_1 + \delta_k) = 1`. 60 | 61 | For simulations of this economy, we choose an initial condition of: 62 | 63 | .. math:: 64 | 65 | x_0 = 66 | \left[ {\begin{array}{ccccc} 67 | 5 & 150 & 1 & 0 & 0 68 | \end{array} } 69 | \right]' 70 | 71 | .. code-block:: python3 72 | 73 | γ_1 = 0.1 74 | γ = np.array([[γ_1], [0]]) 75 | ϕ_c = np.array([[1], [0]]) 76 | ϕ_g = np.array([[0], [1]]) 77 | ϕ_1 = 1e-5 78 | ϕ_i = np.array([[1], [-ϕ_1]]) 79 | δ_k = np.array([[.95]]) 80 | θ_k = np.array([[1]]) 81 | β = np.array([[1 / 1.05]]) 82 | l_λ = np.array([[0]]) 83 | π_h = np.array([[1]]) 84 | δ_h = np.array([[.9]]) 85 | θ_h = np.array([[1]]) 86 | a22 = np.array([[1, 0, 0], 87 | [0, 0.8, 0], 88 | [0, 0, 0.5]]) 89 | c2 = np.array([[0, 0], 90 | [1, 0], 91 | [0, 1]]) 92 | ud = np.array([[5, 1, 0], 93 | [0, 0, 0]]) 94 | ub = np.array([[30, 0, 0]]) 95 | x0 = np.array([[5], [150], [1], [0], [0]]) 96 | 97 | info1 = (a22, c2, ub, ud) 98 | tech1 = (ϕ_c, ϕ_g, ϕ_i, γ, δ_k, θ_k) 99 | pref1 = (β, l_λ, π_h, δ_h, θ_h) 100 | 101 | These parameter values are used to define an economy of the DLE class. 102 | 103 | We can then simulate the economy for a chosen length of time, from our 104 | initial state vector :math:`x_0`. 105 | 106 | The economy stores the simulated values for each variable. Below we plot 107 | consumption and investment: 108 | 109 | .. code-block:: python3 110 | 111 | econ1 = DLE(info1, tech1, pref1) 112 | econ1.compute_sequence(x0, ts_length=300) 113 | 114 | # This is the right panel of Fig 5.7.1 from p.105 of HS2013 115 | plt.plot(econ1.c[0], label='Cons.') 116 | plt.plot(econ1.i[0], label='Inv.') 117 | plt.legend() 118 | plt.show() 119 | 120 | The DLE class can be used to create impulse response functions for each 121 | of the endogenous variables: :math:`\{c_t,s_t,h_t,i_t,k_t,g_t\}`. 122 | 123 | If no selector vector for the shock is specified, the default choice is 124 | to give IRFs to the first shock in :math:`w_{t+1}`. 125 | 126 | Below we plot the impulse response functions of investment and 127 | consumption to an endowment innovation (the first shock) in the Hall 128 | model: 129 | 130 | .. code-block:: python3 131 | 132 | econ1.irf(ts_length=40, shock=None) 133 | # This is the left panel of Fig 5.7.1 from p.105 of HS2013 134 | plt.plot(econ1.c_irf, label='Cons.') 135 | plt.plot(econ1.i_irf, label='Inv.') 136 | plt.legend() 137 | plt.show() 138 | 139 | It can be seen that the endowment shock has permanent effects on the 140 | level of both consumption and investment, consistent with the endogenous 141 | unit eigenvalue in this economy. 142 | 143 | Investment is much more responsive to the endowment shock at shorter time 144 | horizons. 145 | 146 | Example 2: Higher Adjustment Costs 147 | =================================== 148 | 149 | We generate our next economy by making only one change to the parameters 150 | of Example 1: we raise the parameter associated with the cost of 151 | adjusting capital,\ :math:`\phi_1`, from 0.00001 to 0.2. 152 | 153 | This will lower the endogenous eigenvalue that is unity in Example 1 to 154 | a value slightly below 1. 155 | 156 | .. code-block:: python3 157 | 158 | ϕ_12 = 0.2 159 | ϕ_i2 = np.array([[1], [-ϕ_12]]) 160 | tech2 = (ϕ_c, ϕ_g, ϕ_i2, γ, δ_k, θ_k) 161 | 162 | econ2 = DLE(info1, tech2, pref1) 163 | econ2.compute_sequence(x0, ts_length = 300) 164 | 165 | # This is the right panel of Fig 5.8.1 from p.106 of HS2013 166 | plt.plot(econ2.c[0], label='Cons.') 167 | plt.plot(econ2.i[0], label='Inv.') 168 | plt.legend() 169 | plt.show() 170 | 171 | .. code-block:: python3 172 | 173 | econ2.irf(ts_length=40,shock=None) 174 | # This is the left panel of Fig 5.8.1 from p.106 of HS2013 175 | plt.plot(econ2.c_irf,label='Cons.') 176 | plt.plot(econ2.i_irf,label='Inv.') 177 | plt.legend() 178 | plt.show() 179 | 180 | .. code-block:: python3 181 | 182 | econ2.endo 183 | 184 | .. code-block:: python3 185 | 186 | econ2.compute_steadystate() 187 | print(econ2.css, econ2.iss, econ2.kss) 188 | 189 | The first graph shows that there seems to be a downward trend in both 190 | consumption and investment. 191 | 192 | his is a consequence of the decrease in the largest endogenous 193 | eigenvalue from unity in the earlier economy, caused by the higher 194 | adjustment cost. 195 | 196 | The present economy has a nonstochastic steady state value of 5 for 197 | consumption and 0 for both capital and investment. 198 | 199 | Because the largest endogenous eigenvalue is still close to 1, the 200 | economy heads only slowly towards these mean values. 201 | 202 | The impulse response functions now show that an endowment shock does not 203 | have a permanent effect on the levels of either consumption or 204 | investment. 205 | 206 | Example 3: Durable Consumption Goods 207 | ===================================== 208 | 209 | We generate our third economy by raising :math:`\phi_1` further, to 1.0. 210 | We also raise the production function parameter from 0.1 to 0.15 (which 211 | raises the non-stochastic steady state value of capital above zero). 212 | 213 | We also change the specification of preferences to make the consumption 214 | good *durable*. 215 | 216 | Specifically, we allow for a single durable household good obeying: 217 | 218 | .. math:: h_t = \delta_h h_{t-1} + c_t \, , 0<\delta_h<1 219 | 220 | Services are related to the stock of durables at the beginning of the 221 | period: 222 | 223 | .. math:: s_t = \lambda h_{t-1} \, , \lambda > 0 224 | 225 | And preferences are ordered by: 226 | 227 | .. math:: - \frac{1}{2} \mathbb{E} \sum_{t=0}^\infty \beta^t [(\lambda h_{t-1} - b_t)^2 + l_t^2]|J_0 228 | 229 | To implement this, we set :math:`\lambda=0.1` and :math:`\pi = 0` (we 230 | have already set :math:`\theta_h = 1` and :math:`\delta_h = 0.9`). 231 | 232 | We start from an initial condition that makes consumption begin near 233 | around its non-stochastic steady state. 234 | 235 | .. code-block:: python3 236 | 237 | ϕ_13 = 1 238 | ϕ_i3 = np.array([[1], [-ϕ_13]]) 239 | 240 | γ_12 = 0.15 241 | γ_2 = np.array([[γ_12], [0]]) 242 | 243 | l_λ2 = np.array([[0.1]]) 244 | π_h2 = np.array([[0]]) 245 | 246 | x01 = np.array([[150], [100], [1], [0], [0]]) 247 | 248 | tech3 = (ϕ_c, ϕ_g, ϕ_i3, γ_2, δ_k, θ_k) 249 | pref2 = (β, l_λ2, π_h2, δ_h, θ_h) 250 | 251 | econ3 = DLE(info1, tech3, pref2) 252 | econ3.compute_sequence(x01, ts_length=300) 253 | 254 | # This is the right panel of Fig 5.11.1 from p.111 of HS2013 255 | plt.plot(econ3.c[0], label='Cons.') 256 | plt.plot(econ3.i[0], label='Inv.') 257 | plt.legend() 258 | plt.show() 259 | 260 | In contrast to Hall's original model of Example 1, it is now investment 261 | that is much smoother than consumption. 262 | 263 | This illustrates how making consumption goods durable tends to undo the 264 | strong consumption smoothing result that Hall obtained. 265 | 266 | .. code-block:: python3 267 | 268 | econ3.irf(ts_length=40, shock=None) 269 | # This is the left panel of Fig 5.11.1 from p.111 of HS2013 270 | plt.plot(econ3.c_irf, label='Cons.') 271 | plt.plot(econ3.i_irf, label='Inv.') 272 | plt.legend() 273 | plt.show() 274 | 275 | The impulse response functions confirm that consumption is now much more 276 | responsive to an endowment shock (and investment less so) than in 277 | Example 1. 278 | 279 | As in Example 2, the endowment shock has permanent effects on 280 | neither variable. 281 | -------------------------------------------------------------------------------- /source/rst/permanent_income_dles.rst: -------------------------------------------------------------------------------- 1 | .. _permanent_income_dles: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | .. index:: 6 | single: python 7 | 8 | ****************************************** 9 | Permanent Income Model using the DLE Class 10 | ****************************************** 11 | 12 | .. contents:: :depth: 2 13 | 14 | 15 | This lecture is part of a suite of lectures that use the quantecon DLE class to instantiate models within the 16 | :cite:`HS2013` class of models described in detail in :doc:`Recursive Models of Dynamic Linear Economies `. 17 | 18 | In addition to what's included in Anaconda, this lecture uses the quantecon library. 19 | 20 | .. code-block:: ipython 21 | :class: hide-output 22 | 23 | !pip install --upgrade quantecon 24 | 25 | 26 | This lecture adds a third solution method for the 27 | linear-quadratic-Gaussian permanent income model with 28 | :math:`\beta R = 1`, complementing the other two solution methods described in `Optimal Savings I: The Permanent Income Model `__ and 29 | `Optimal Savings II: LQ Techniques `__ and `this Jupyter 30 | notebook `__. 31 | 32 | 33 | 34 | The additional solution method uses the **DLE** class. 35 | 36 | In this way, we map the permanent 37 | income model into the framework of Hansen & Sargent (2013) "Recursive 38 | Models of Dynamic Linear Economies" :cite:`HS2013`. 39 | 40 | We'll also require the following imports 41 | 42 | .. code-block:: ipython 43 | 44 | import quantecon as qe 45 | import numpy as np 46 | import scipy.linalg as la 47 | import matplotlib.pyplot as plt 48 | %matplotlib inline 49 | from quantecon import DLE 50 | 51 | np.set_printoptions(suppress=True, precision=4) 52 | 53 | The Permanent Income Model 54 | ========================== 55 | 56 | The LQ permanent income model is an example of a **savings problem**. 57 | 58 | A consumer has preferences over consumption streams that are ordered by 59 | the utility functional 60 | 61 | .. math:: 62 | :label: perm-utility 63 | 64 | E_0 \sum_{t=0}^\infty \beta^t u(c_t) 65 | 66 | where :math:`E_t` is the mathematical expectation conditioned on the 67 | consumer's time :math:`t` information, :math:`c_t` is time :math:`t` 68 | consumption, :math:`u(c)` is a strictly concave one-period utility 69 | function, and :math:`\beta \in (0,1)` is a discount factor. 70 | 71 | The LQ model gets its name partly from assuming that the utility 72 | function :math:`u` is quadratic: 73 | 74 | .. math:: u(c) = -.5(c - \gamma)^2 75 | 76 | where :math:`\gamma>0` is a bliss level of consumption. 77 | 78 | The consumer maximizes the utility functional :eq:`perm-utility` by choosing a 79 | consumption, borrowing plan :math:`\{c_t, b_{t+1}\}_{t=0}^\infty` 80 | subject to the sequence of budget constraints 81 | 82 | .. math:: 83 | :label: max-utility 84 | 85 | c_t + b_t = R^{-1} b_{t+1} + y_t, t \geq 0 86 | 87 | where :math:`y_t` is an exogenous stationary endowment process, 88 | :math:`R` is a constant gross risk-free interest rate, :math:`b_t` is 89 | one-period risk-free debt maturing at :math:`t`, and :math:`b_0` is a 90 | given initial condition. 91 | 92 | We shall assume that :math:`R^{-1} = \beta`. 93 | 94 | Equation :eq:`max-utility` is linear. 95 | 96 | We use another set of linear equations to model the endowment process. 97 | 98 | In particular, we assume that the endowment process has the state-space 99 | representation 100 | 101 | .. math:: 102 | :label: endowment 103 | 104 | \begin{aligned} z_{t+1} & = A_{22} z_t + C_2 w_{t+1} \cr 105 | y_t & = U_y z_t \cr \end{aligned} 106 | 107 | where :math:`w_{t+1}` is an IID process with mean zero and identity 108 | contemporaneous covariance matrix, :math:`A_{22}` is a stable matrix, 109 | its eigenvalues being strictly below unity in modulus, and :math:`U_y` 110 | is a selection vector that identifies :math:`y` with a particular linear 111 | combination of the :math:`z_t`. 112 | 113 | We impose the following condition on the consumption, borrowing plan: 114 | 115 | .. math:: 116 | :label: contraint 117 | 118 | E_0 \sum_{t=0}^\infty \beta^t b_t^2 < +\infty 119 | 120 | This condition suffices to rule out Ponzi schemes. 121 | 122 | (We impose this condition to rule out a borrow-more-and-more plan that 123 | would allow the household to enjoy bliss consumption forever) 124 | 125 | The state vector confronting the household at :math:`t` is 126 | 127 | .. math:: x_t = \begin{bmatrix} z_t \\ b_t \end{bmatrix} 128 | 129 | where :math:`b_t` is its one-period debt falling due at the beginning of 130 | period :math:`t` and :math:`z_t` contains all variables useful for 131 | forecasting its future endowment. 132 | 133 | We assume that :math:`\{y_t\}` follows a second order univariate 134 | autoregressive process: 135 | 136 | .. math:: y_{t+1} = \alpha + \rho_1 y_t + \rho_2 y_{t-1} + \sigma w_{t+1} 137 | 138 | Solution with the DLE Class 139 | --------------------------- 140 | 141 | One way of solving this model is to map the problem into the framework 142 | outlined in Section 4.8 of :cite:`HS2013` by setting up our technology, 143 | information and preference matrices as follows: 144 | 145 | **Technology:** 146 | :math:`\phi_c= \left[ {\begin{array}{c} 1 \\ 0 \end{array} } \right]` 147 | , 148 | :math:`\phi_g= \left[ {\begin{array}{c} 0 \\ 1 \end{array} } \right]` 149 | , 150 | :math:`\phi_i= \left[ {\begin{array}{c} -1 \\ -0.00001 \end{array} } \right]`, 151 | :math:`\Gamma= \left[ {\begin{array}{c} -1 \\ 0 \end{array} } \right]`, 152 | :math:`\Delta_k = 0`,  :math:`\Theta_k = R`. 153 | 154 | **Information:** 155 | :math:`A_{22} = \left[ {\begin{array}{ccc} 1 & 0 & 0 \\ \alpha & \rho_1 & \rho_2 \\ 0 & 1 & 0 \end{array} } \right]`, 156 | :math:`C_{2} = \left[ {\begin{array}{c} 0 \\ \sigma \\ 0 \end{array} } \right]`, 157 | :math:`U_b = \left[ {\begin{array}{ccc} \gamma & 0 & 0 \end{array} } \right]`, 158 | :math:`U_d = \left[ {\begin{array}{ccc} 0 & 1 & 0 \\ 0 & 0 & 0 \end{array} } \right]`. 159 | 160 | **Preferences:** :math:`\Lambda = 0`, :math:`\Pi = 1`, 161 | :math:`\Delta_h = 0`, :math:`\Theta_h = 0`. 162 | 163 | We set parameters 164 | 165 | :math:`\alpha = 10, \beta = 0.95, \rho_1 = 0.9, \rho_2 = 0, \sigma = 1` 166 | 167 | (The value of :math:`\gamma` does not affect the optimal decision rule) 168 | 169 | The chosen matrices mean that the household's technology is: 170 | 171 | .. math:: c_t + k_{t-1} = i_t + y_t 172 | 173 | .. math:: \frac{k_t}{R} = i_t 174 | 175 | .. math:: l_t^2 = (0.00001)^2i_t 176 | 177 | Combining the first two of these gives the budget constraint of the 178 | permanent income model, where :math:`k_t = b_{t+1}`. 179 | 180 | The third equation is a very small penalty on debt-accumulation to rule 181 | out Ponzi schemes. 182 | 183 | We set up this instance of the DLE class below: 184 | 185 | .. code-block:: python3 186 | 187 | α, β, ρ_1, ρ_2, σ = 10, 0.95, 0.9, 0, 1 188 | 189 | γ = np.array([[-1], [0]]) 190 | ϕ_c = np.array([[1], [0]]) 191 | ϕ_g = np.array([[0], [1]]) 192 | ϕ_1 = 1e-5 193 | ϕ_i = np.array([[-1], [-ϕ_1]]) 194 | δ_k = np.array([[0]]) 195 | θ_k = np.array([[1 / β]]) 196 | β = np.array([[β]]) 197 | l_λ = np.array([[0]]) 198 | π_h = np.array([[1]]) 199 | δ_h = np.array([[0]]) 200 | θ_h = np.array([[0]]) 201 | 202 | a22 = np.array([[1, 0, 0], 203 | [α, ρ_1, ρ_2], 204 | [0, 1, 0]]) 205 | 206 | c2 = np.array([[0], [σ], [0]]) 207 | ud = np.array([[0, 1, 0], 208 | [0, 0, 0]]) 209 | ub = np.array([[100, 0, 0]]) 210 | 211 | x0 = np.array([[0], [0], [1], [0], [0]]) 212 | 213 | info1 = (a22, c2, ub, ud) 214 | tech1 = (ϕ_c, ϕ_g, ϕ_i, γ, δ_k, θ_k) 215 | pref1 = (β, l_λ, π_h, δ_h, θ_h) 216 | econ1 = DLE(info1, tech1, pref1) 217 | 218 | To check the solution of this model with that from the **LQ** problem, 219 | we select the :math:`S_c` matrix from the DLE class. 220 | 221 | The solution to the 222 | DLE economy has: 223 | 224 | .. math:: c_t = S_c x_t 225 | 226 | .. code-block:: python3 227 | 228 | econ1.Sc 229 | 230 | The state vector in the DLE class is: 231 | 232 | .. math:: 233 | 234 | x_t = \left[ {\begin{array}{c} 235 | h_{t-1} \\ k_{t-1} \\ z_t 236 | \end{array} } 237 | \right] 238 | 239 | where :math:`k_{t-1}` = :math:`b_{t}` is set up to be :math:`b_t` in the 240 | permanent income model. 241 | 242 | The state vector in the LQ problem is 243 | :math:`\begin{bmatrix} z_t \\ b_t \end{bmatrix}`. 244 | 245 | Consequently, the relevant elements of econ1.Sc are the same as in 246 | :math:`-F` occur when we apply other approaches to the same model in the lecture 247 | `Optimal Savings II: LQ Techniques `__ and `this Jupyter 248 | notebook `__. 249 | 250 | 251 | The plot below quickly replicates the first two figures of 252 | that lecture and that notebook to confirm that the solutions are the same 253 | 254 | .. code-block:: python3 255 | 256 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 5)) 257 | 258 | for i in range(25): 259 | econ1.compute_sequence(x0, ts_length=150) 260 | ax1.plot(econ1.c[0], c='g') 261 | ax1.plot(econ1.d[0], c='b') 262 | ax1.plot(econ1.c[0], label='Consumption', c='g') 263 | ax1.plot(econ1.d[0], label='Income', c='b') 264 | ax1.legend() 265 | 266 | for i in range(25): 267 | econ1.compute_sequence(x0, ts_length=150) 268 | ax2.plot(econ1.k[0], color='r') 269 | ax2.plot(econ1.k[0], label='Debt', c='r') 270 | ax2.legend() 271 | plt.show() 272 | -------------------------------------------------------------------------------- /source/rst/tax_smoothing_3.rst: -------------------------------------------------------------------------------- 1 | .. _tax_smoothing_3: 2 | 3 | .. include:: /_static/includes/lecture_howto_py.raw 4 | 5 | .. index:: 6 | single: python 7 | 8 | 9 | **************************** 10 | How to Pay for a War: Part 3 11 | **************************** 12 | 13 | .. contents:: :depth: 2 14 | 15 | In addition to what's in Anaconda, this lecture deploys the quantecon library: 16 | 17 | .. code-block:: ipython 18 | :class: hide-output 19 | 20 | !pip install --upgrade quantecon 21 | 22 | Another Application of Markov Jump Linear Quadratic Dynamic Programming 23 | ======================================================================= 24 | 25 | This is another :doc:`sequel to an earlier lecture `. 26 | 27 | We again use a method introduced in lecture :doc:`Markov Jump LQ dynamic programming ` 28 | to implement some ideas Barro (1999 :cite:`barro1999determinants`, 2003 :cite:`barro2003religion`) that 29 | extend his classic 1979 :cite:`Barro1979` model of tax smoothing. 30 | 31 | Barro’s 1979 :cite:`Barro1979` model is about a government that borrows and lends in order 32 | to help it minimize an intertemporal measure of distortions caused by 33 | taxes. 34 | 35 | Technically, Barro’s 1979 :cite:`Barro1979` model looks a lot like a consumption-smoothing model. 36 | 37 | Our generalizations of his 1979 model will also look 38 | like souped-up consumption-smoothing models. 39 | 40 | In this lecture, we describe a tax-smoothing problem of a 41 | government that faces **roll-over risk**. 42 | 43 | Let's start with some standard imports: 44 | 45 | .. code-block:: ipython 46 | 47 | import quantecon as qe 48 | import numpy as np 49 | import matplotlib.pyplot as plt 50 | %matplotlib inline 51 | 52 | 53 | Roll-Over Risk 54 | ============== 55 | 56 | Let :math:`T_t` denote tax collections, :math:`\beta` a discount factor, 57 | :math:`b_{t,t+1}` time :math:`t+1` goods that the government promises to 58 | pay at :math:`t`, :math:`G_t` government purchases, :math:`p^t_{t+1}` 59 | the number of time :math:`t` goods received per time :math:`t+1` goods 60 | promised. 61 | 62 | The stochastic process of government expenditures is 63 | exogenous. 64 | 65 | The government’s problem is to choose a plan for borrowing 66 | and tax collections :math:`\{b_{t+1}, T_t\}_{t=0}^\infty` to minimize 67 | 68 | .. math:: E_0 \sum_{t=0}^\infty \beta^t T_t^2 69 | 70 | subject to the constraints 71 | 72 | .. math:: T_t + p^t_{t+1} b_{t,t+1} = G_t + b_{t-1,t} 73 | 74 | .. math:: G_t = U_{g,t} z_t 75 | 76 | .. math:: z_{t+1} = A_{22,t} z_t + C_{2,t} w_{t+1} 77 | 78 | where :math:`w_{t+1} \sim {\cal N}(0,I)`. The variables 79 | :math:`T_t, b_{t, t+1}` are *control* variables chosen at :math:`t`, 80 | while :math:`b_{t-1,t}` is an endogenous state variable inherited from 81 | the past at time :math:`t` and :math:`p^t_{t+1}` is an exogenous state 82 | variable at time :math:`t`. 83 | 84 | This is the same set-up as used :doc:`in this 85 | lecture `. 86 | 87 | We will consider a situation in which the government faces “roll-over 88 | risk”. 89 | 90 | Specifically, we shut down the government’s ability to borrow in 91 | one of the Markov states. 92 | 93 | A Dead End 94 | ========== 95 | 96 | A first thought for how to implement this might be to allow 97 | :math:`p^t_{t+1}` to vary over time with: 98 | 99 | .. math:: p^t_{t+1} = \beta 100 | 101 | in Markov state 1 and 102 | 103 | .. math:: p^t_{t+1} = 0 104 | 105 | in Markov state 2. 106 | 107 | Consequently, in the second Markov state, the 108 | government is unable to borrow, and the budget constraint becomes 109 | :math:`T_t = G_t + b_{t-1,t}`. 110 | 111 | However, if this is the only adjustment we make in our linear-quadratic 112 | model, the government will not set :math:`b_{t,t+1} = 0`, which is the 113 | outcome we want to express *roll-over* risk in period :math:`t`. 114 | 115 | Instead, the government would have an incentive to set :math:`b_{t,t+1}` 116 | to a large negative number in state 2 – it would accumulate large 117 | amounts of *assets* to bring into period :math:`t+1` because that is 118 | cheap (Our Riccati equations will discover this for us!). 119 | 120 | Thus, we must represent “roll-over risk” some other way. 121 | 122 | Better Representation of Roll-Over Risk 123 | ========================================= 124 | 125 | To force the government to set :math:`b_{t,t+1} = 0`, we can instead 126 | extend the model to have four Markov states: 127 | 128 | 1. Good today, good yesterday 129 | 2. Good today, bad yesterday 130 | 3. Bad today, good yesterday 131 | 4. Bad today, bad yesterday 132 | 133 | where good is a state in which effectively the government can issue debt 134 | and bad is a state in which effectively the government can’t issue debt. 135 | 136 | We’ll explain what *effectively* means shortly. 137 | 138 | We now set 139 | 140 | .. math:: p^t_{t+1} = \beta 141 | 142 | in all states. 143 | 144 | In addition – and this is important because it defines what we mean by 145 | *effectively* -- we put a large penalty on the :math:`b_{t-1,t}` 146 | element of the state vector in states 2 and 4. 147 | 148 | This will prevent the 149 | government from wishing to issue any debt in states 3 or 4 because it 150 | would experience a large penalty from doing so in the next period. 151 | 152 | The transition matrix for this formulation is: 153 | 154 | .. math:: 155 | 156 | \Pi = \begin{bmatrix} 0.95 & 0 & 0.05 & 0 \\ 157 | 0.95 & 0 & 0.05 & 0 \\ 158 | 0 & 0.9 & 0 & 0.1 \\ 159 | 0 & 0.9 & 0 & 0.1 \\ 160 | \end{bmatrix} 161 | 162 | This transition matrix ensures that the Markov state cannot move, for 163 | example, from state 3 to state 1. 164 | 165 | Because state 3 is “bad today”, the next period cannot have “good yesterday”. 166 | 167 | .. code-block:: python3 168 | 169 | # Model parameters 170 | β, Gbar, ρ, σ = 0.95, 5, 0.8, 1 171 | 172 | # Basic model matrices 173 | A22 = np.array([[1, 0], [Gbar, ρ], ]) 174 | C2 = np.array([[0], [σ]]) 175 | Ug = np.array([[0, 1]]) 176 | 177 | # LQ framework matrices 178 | A_t = np.zeros((1, 3)) 179 | A_b = np.hstack((np.zeros((2, 1)), A22)) 180 | A = np.vstack((A_t, A_b)) 181 | 182 | B = np.zeros((3, 1)) 183 | B[0, 0] = 1 184 | 185 | C = np.vstack((np.zeros((1, 1)), C2)) 186 | 187 | Sg = np.hstack((np.zeros((1, 1)), Ug)) 188 | S1 = np.zeros((1, 3)) 189 | S1[0, 0] = 1 190 | S = S1 + Sg 191 | 192 | R = S.T @ S 193 | 194 | # Large penalty on debt in R2 to prevent borrowing in a bad state 195 | R1 = np.copy(R) 196 | R2 = np.copy(R) 197 | R1[0, 0] = R[0, 0] + 1e-9 198 | R2[0, 0] = R[0, 0] + 1e12 199 | 200 | M = np.array([[-β]]) 201 | Q = M.T @ M 202 | W = M.T @ S 203 | 204 | Π = np.array([[0.95, 0, 0.05, 0], 205 | [0.95, 0, 0.05, 0], 206 | [0, 0.9, 0, 0.1], 207 | [0, 0.9, 0, 0.1]]) 208 | 209 | # Construct lists of matrices that correspond to each state 210 | As = [A, A, A, A] 211 | Bs = [B, B, B, B] 212 | Cs = [C, C, C, C] 213 | Rs = [R1, R2, R1, R2] 214 | Qs = [Q, Q, Q, Q] 215 | Ws = [W, W, W, W] 216 | 217 | lqm = qe.LQMarkov(Π, Qs, Rs, As, Bs, Cs=Cs, Ns=Ws, beta=β) 218 | lqm.stationary_values(); 219 | 220 | This model is simulated below, using the same process for :math:`G_t` as 221 | in :doc:`this lecture `. 222 | 223 | When :math:`p^t_{t+1} = \beta` 224 | government debt fluctuates around zero. 225 | 226 | The spikes in the series for 227 | taxation show periods when the government is unable to access financial 228 | markets: positive spikes occur when debt is positive, and the government 229 | must raise taxes in the current period. 230 | 231 | Negative spikes occur when the government has positive asset holdings. 232 | 233 | An inability to use financial markets in the next period means that the 234 | government uses those assets to lower taxation today. 235 | 236 | .. code-block:: python3 237 | 238 | x0 = np.array([[0, 1, 25]]) 239 | T = 300 240 | x, u, w, state = lqm.compute_sequence(x0, ts_length=T) 241 | 242 | # Calculate taxation each period from the budget constraint and the Markov state 243 | tax = np.zeros([T, 1]) 244 | for i in range(T): 245 | tax[i, :] = S @ x[:, i] + M @ u[:, i] 246 | 247 | # Plot of debt issuance and taxation 248 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 4)) 249 | ax1.plot(x[0, :]) 250 | ax1.set_title('One-period debt issuance') 251 | ax1.set_xlabel('Time') 252 | ax2.plot(tax) 253 | ax2.set_title('Taxation') 254 | ax2.set_xlabel('Time') 255 | plt.show() 256 | 257 | We can adjust the model so that, rather than having debt fluctuate 258 | around zero, the government is a debtor in every period we allow it to 259 | borrow. 260 | 261 | To accomplish this, we simply raise :math:`p^t_{t+1}` to 262 | :math:`\beta + 0.02 = 0.97`. 263 | 264 | .. code-block:: python3 265 | 266 | M = np.array([[-β - 0.02]]) 267 | 268 | Q = M.T @ M 269 | W = M.T @ S 270 | 271 | # Construct lists of matrices 272 | As = [A, A, A, A] 273 | Bs = [B, B, B, B] 274 | Cs = [C, C, C, C] 275 | Rs = [R1, R2, R1, R2] 276 | Qs = [Q, Q, Q, Q] 277 | Ws = [W, W, W, W] 278 | 279 | lqm2 = qe.LQMarkov(Π, Qs, Rs, As, Bs, Cs=Cs, Ns=Ws, beta=β) 280 | x, u, w, state = lqm2.compute_sequence(x0, ts_length=T) 281 | 282 | # Calculate taxation each period from the budget constraint and the 283 | # Markov state 284 | tax = np.zeros([T, 1]) 285 | for i in range(T): 286 | tax[i, :] = S @ x[:, i] + M @ u[:, i] 287 | 288 | # Plot of debt issuance and taxation 289 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 4)) 290 | ax1.plot(x[0, :]) 291 | ax1.set_title('One-period debt issuance') 292 | ax1.set_xlabel('Time') 293 | ax2.plot(tax) 294 | ax2.set_title('Taxation') 295 | ax2.set_xlabel('Time') 296 | plt.show() 297 | 298 | With a lower interest rate, the government has an incentive to 299 | increase debt over time. 300 | 301 | However, with “roll-over risk”, debt is 302 | recurrently reset to zero and taxes spike up. 303 | 304 | Consequently, the 305 | government is wary of letting debt get too high, due to the high costs of 306 | a “sudden stop”. 307 | -------------------------------------------------------------------------------- /theme/minimal/templates/html.tpl: -------------------------------------------------------------------------------- 1 | {%- extends 'display_priority.tpl' -%} 2 | 3 | {% set site_title = 'Lectures' %} 4 | {% set nb_title = nb.metadata.get('title', '') %} 5 | {% set nb_filename = nb.metadata.get('filename', '') %} 6 | {% set nb_filename_with_path = nb.metadata.get('filename_with_path','') %} 7 | {% set indexPage = nb_filename.startswith('index') %} 8 | {% set download_nb = nb.metadata.get('download_nb','') %} 9 | {% set download_nb_path = nb.metadata.get('download_nb_path','') %} 10 | {% if nb_filename.endswith('.rst') %} 11 | {% set nb_filename = nb_filename[:-4] %} 12 | {% endif %} 13 | 14 | {%- block header %} 15 | 16 | 17 | 18 | 19 | {% if nb_filename == 'index' %} 20 | {{ site_title }} 21 | {% else %} 22 | {{nb_title}} – {{ site_title }} 23 | {% endif %} 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 |
39 | 40 |
41 | 42 |

{{ site_title }}

43 | 44 |

Skip to content

45 | 46 |
47 | 48 |
49 | 50 | {% if indexPage or nb_filename == 'status' %} 51 |
52 | {% else %} 53 |
54 | {% endif %} 55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 | 65 | 66 |
67 | 68 | {%- endblock header-%} 69 | 70 | {% block codecell %} 71 | {% set html_class = cell['metadata'].get('html-class', {}) %} 72 |
73 | {{ super() }} 74 |
75 | {%- endblock codecell %} 76 | 77 | {% block input_group -%} 78 |
79 | {{ super() }} 80 |
81 | {% endblock input_group %} 82 | 83 | {% block output_group %} 84 |
85 |
86 | {{ super() }} 87 |
88 |
89 | {% endblock output_group %} 90 | 91 | {% block in_prompt -%} 92 |
93 | {%- if cell.execution_count is defined -%} 94 | In [{{ cell.execution_count|replace(None, " ") }}]: 95 | {%- else -%} 96 | In [ ]: 97 | {%- endif -%} 98 |
99 | {%- endblock in_prompt %} 100 | 101 | {% block empty_in_prompt -%} 102 |
103 |
104 | {%- endblock empty_in_prompt %} 105 | 106 | {# 107 | output_prompt doesn't do anything in HTML, 108 | because there is a prompt div in each output area (see output block) 109 | #} 110 | {% block output_prompt %} 111 | {% endblock output_prompt %} 112 | 113 | {% block input %} 114 |
115 |
116 | {{ cell.source | highlight_code(metadata=cell.metadata) }} 117 |
118 |
119 | {%- endblock input %} 120 | 121 | {% block output_area_prompt %} 122 | {%- if output.output_type == 'execute_result' -%} 123 |
124 | {%- if cell.execution_count is defined -%} 125 | Out[{{ cell.execution_count|replace(None, " ") }}]: 126 | {%- else -%} 127 | Out[ ]: 128 | {%- endif -%} 129 | {%- else -%} 130 |
131 | {%- endif -%} 132 |
133 | {% endblock output_area_prompt %} 134 | 135 | {% block output %} 136 |
137 | {% if resources.global_content_filter.include_output_prompt %} 138 | {{ self.output_area_prompt() }} 139 | {% endif %} 140 | {{ super() }} 141 |
142 | {% endblock output %} 143 | 144 | {% block markdowncell scoped %} 145 | {% set html_class = cell['metadata'].get('html-class', {}) %} 146 |
147 | {%- if resources.global_content_filter.include_input_prompt-%} 148 | {{ self.empty_in_prompt() }} 149 | {%- endif -%} 150 |
151 |
152 | {{ cell.source | markdown2html | strip_files_prefix }} 153 |
154 |
155 |
156 | {%- endblock markdowncell %} 157 | 158 | {% block unknowncell scoped %} 159 | unknown type {{ cell.type }} 160 | {% endblock unknowncell %} 161 | 162 | {% block execute_result -%} 163 | {%- set extra_class="output_execute_result" -%} 164 | {% block data_priority scoped %} 165 | {{ super() }} 166 | {% endblock data_priority %} 167 | {%- set extra_class="" -%} 168 | {%- endblock execute_result %} 169 | 170 | {% block stream_stdout -%} 171 |
172 |
173 | {{- output.text | ansi2html -}}
174 | 
175 |
176 | {%- endblock stream_stdout %} 177 | 178 | {% block stream_stderr -%} 179 |
180 |
181 | {{- output.text | ansi2html -}}
182 | 
183 |
184 | {%- endblock stream_stderr %} 185 | 186 | {% block data_svg scoped -%} 187 |
188 | {%- if output.svg_filename %} 189 | 194 | {%- endblock data_svg %} 195 | 196 | {% block data_html scoped -%} 197 |
198 | {{ output.data['text/html'] }} 199 |
200 | {%- endblock data_html %} 201 | 202 | {% block data_markdown scoped -%} 203 |
204 | {{ output.data['text/markdown'] | markdown2html }} 205 |
206 | {%- endblock data_markdown %} 207 | 208 | {% block data_png scoped %} 209 |
210 | {%- if 'image/png' in output.metadata.get('filenames', {}) %} 211 | 227 |
228 | {%- endblock data_png %} 229 | 230 | {% block data_jpg scoped %} 231 |
232 | {%- if 'image/jpeg' in output.metadata.get('filenames', {}) %} 233 | 249 |
250 | {%- endblock data_jpg %} 251 | 252 | {% block data_latex scoped %} 253 |
254 | {{ output.data['text/latex'] }} 255 |
256 | {%- endblock data_latex %} 257 | 258 | {% block error -%} 259 |
260 |
261 | {{- super() -}}
262 | 
263 |
264 | {%- endblock error %} 265 | 266 | {%- block traceback_line %} 267 | {{ line | ansi2html }} 268 | {%- endblock traceback_line %} 269 | 270 | {%- block data_text scoped %} 271 |
272 |
273 | {{- output.data['text/plain'] | ansi2html -}}
274 | 
275 |
276 | {%- endblock -%} 277 | 278 | {%- block data_javascript scoped %} 279 | {% set div_id = uuid4() %} 280 |
281 |
282 | 286 |
287 | {%- endblock -%} 288 | 289 | {%- block data_widget_state scoped %} 290 | {% set div_id = uuid4() %} 291 | {% set datatype_list = output.data | filter_data_type %} 292 | {% set datatype = datatype_list[0]%} 293 |
294 |
295 | 298 | 301 |
302 | {%- endblock data_widget_state -%} 303 | 304 | {%- block data_widget_view scoped %} 305 | {% set div_id = uuid4() %} 306 | {% set datatype_list = output.data | filter_data_type %} 307 | {% set datatype = datatype_list[0]%} 308 |
309 |
310 | 313 | 316 |
317 | {%- endblock data_widget_view -%} 318 | 319 | {%- block footer %} 320 | {% set mimetype = 'application/vnd.jupyter.widget-state+json'%} 321 | {% if mimetype in nb.metadata.get("widgets",{})%} 322 | 325 | {% endif %} 326 | {{ super() }} 327 | 328 | 329 |
330 | 331 |
332 | 333 |
334 | 335 |
336 | 337 |

© Copyright XXXX, Occaecat ipsum culpa nulla in Lorem dolor exercitation adipisicing in qui pariatur.

338 | 339 |
340 | 341 |
342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | {%- endblock footer-%} 351 | -------------------------------------------------------------------------------- /source/rst/rosen_schooling_model.rst: -------------------------------------------------------------------------------- 1 | .. _rosen_schooling_model: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | .. index:: 6 | single: python 7 | 8 | ********************* 9 | Rosen Schooling Model 10 | ********************* 11 | 12 | .. contents:: :depth: 2 13 | 14 | 15 | This lecture is yet another part of a suite of lectures that use the quantecon DLE class to instantiate models within the 16 | :cite:`HS2013` class of models described in detail in :doc:`Recursive Models of Dynamic Linear Economies`. 17 | 18 | In addition to what's included in Anaconda, this lecture uses the quantecon library 19 | 20 | .. code-block:: ipython 21 | :class: hide-output 22 | 23 | !pip install --upgrade quantecon 24 | 25 | We'll also need the following imports: 26 | 27 | .. code-block:: ipython 28 | 29 | import numpy as np 30 | import matplotlib.pyplot as plt 31 | from quantecon import LQ 32 | from collections import namedtuple 33 | from quantecon import DLE 34 | from math import sqrt 35 | %matplotlib inline 36 | 37 | A One-Occupation Model 38 | ====================== 39 | 40 | Ryoo and Rosen's (2004) :cite:`ryoo2004engineering` partial equilibrium model determines 41 | 42 | - a stock of "Engineers" :math:`N_t` 43 | 44 | - a number of new entrants in engineering school, :math:`n_t` 45 | 46 | - the wage rate of engineers, :math:`w_t` 47 | 48 | It takes k periods of schooling to become an engineer. 49 | 50 | The model consists of the following equations: 51 | 52 | - a demand curve for engineers: 53 | 54 | .. math:: w_t = - \alpha_d N_t + \epsilon_{dt} 55 | 56 | - a time-to-build structure of the education process: 57 | 58 | .. math:: N_{t+k} = \delta_N N_{t+k-1} + n_t 59 | 60 | - a definition of the discounted present value of each new engineering 61 | student: 62 | 63 | .. math:: v_t = \beta_k \mathbb{E} \sum_{j=0}^\infty (\beta \delta_N)^j w_{t+k+j} 64 | 65 | - a supply curve of new students driven by present value :math:`v_t`: 66 | 67 | .. math:: n_t = \alpha_s v_t + \epsilon_{st} 68 | 69 | Mapping into HS2013 Framework 70 | ============================= 71 | 72 | We represent this model in the :cite:`HS2013` framework by 73 | 74 | - sweeping the time-to-build structure and the demand for engineers 75 | into the household technology, and 76 | 77 | - putting the supply of engineers into the technology for producing 78 | goods 79 | 80 | Preferences 81 | ----------- 82 | 83 | .. math:: 84 | 85 | \Pi = 0, \Lambda= 86 | \begin{bmatrix} 87 | \alpha_d & 0 & \cdots & 0 88 | \end{bmatrix} 89 | , \Delta_h = 90 | \begin{bmatrix} 91 | \delta_N & 1 & 0 & \cdots & 0 \\ 0 & 0 & 1 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & \cdots& \cdots & 0 & 1 \\ 0 & 0 & 0 & \cdots & 0 92 | \end{bmatrix} 93 | , \Theta_h = 94 | \begin{bmatrix} 95 | 0 \\ 0 \\ \vdots \\ 0 \\ 1 96 | \end{bmatrix} 97 | 98 | where :math:`\Lambda` is a k+1 x 1 matrix, :math:`\Delta_h` is a k\_1 x 99 | k+1 matrix, and :math:`\Theta_h` is a k+1 x 1 matrix. 100 | 101 | This specification sets :math:`N_t = h_{1t-1}`, :math:`n_t = c_t`, 102 | :math:`h_{\tau+1,t-1} = n_{t-(k-\tau)}` for :math:`\tau = 1,...,k`. 103 | 104 | Below we set things up so that the number of years of education, :math:`k`, can 105 | be varied. 106 | 107 | Technology 108 | ---------- 109 | 110 | To capture Ryoo and Rosen's :cite:`ryoo2004engineering` supply curve, we use the physical 111 | technology: 112 | 113 | .. math:: c_t = i_t + d_{1t} 114 | 115 | .. math:: \psi_1i_t = g_t 116 | 117 | where :math:`\psi_1` is inversely proportional to :math:`\alpha_s`. 118 | 119 | Information 120 | ----------- 121 | 122 | Because we want :math:`b_t = \epsilon_{dt}` and :math:`d_{1t} =\epsilon_{st}`, we set 123 | 124 | 125 | .. math:: 126 | 127 | A_{22}= 128 | \begin{bmatrix} 129 | 1 & 0 & 0 \\ 0 & \rho_s & 0 \\ 0 & 0 & \rho_d 130 | \end{bmatrix} 131 | , C_2 = 132 | \begin{bmatrix} 133 | 0 & 0 \\ 1 & 0 \\ 0 & 1 134 | \end{bmatrix} 135 | , U_b = 136 | \begin{bmatrix} 137 | 30 & 0 & 1 138 | \end{bmatrix} 139 | , U_d = 140 | \begin{bmatrix} 141 | 10 & 1 & 0 \\ 0 & 0 & 0 142 | \end{bmatrix} 143 | 144 | where :math:`\rho_s` and :math:`\rho_d` describe the persistence of the 145 | supply and demand shocks 146 | 147 | .. code-block:: python3 148 | 149 | Information = namedtuple('Information', ['a22', 'c2','ub','ud']) 150 | Technology = namedtuple('Technology', ['ϕ_c', 'ϕ_g', 'ϕ_i', 'γ', 'δ_k', 'θ_k']) 151 | Preferences = namedtuple('Preferences', ['β', 'l_λ', 'π_h', 'δ_h', 'θ_h']) 152 | 153 | Effects of Changes in Education Technology and Demand 154 | ----------------------------------------------------- 155 | 156 | We now study how changing 157 | 158 | - the number of years of education required to become an engineer and 159 | 160 | - the slope of the demand curve 161 | 162 | affects responses to demand shocks. 163 | 164 | To begin, we set :math:`k = 4` and :math:`\alpha_d = 0.1` 165 | 166 | .. code-block:: python3 167 | 168 | k = 4 # Number of periods of schooling required to become an engineer 169 | 170 | β = np.array([[1 / 1.05]]) 171 | α_d = np.array([[0.1]]) 172 | α_s = 1 173 | ε_1 = 1e-7 174 | λ_1 = np.ones((1, k)) * ε_1 175 | # Use of ε_1 is trick to aquire detectability, see HS2013 p. 228 footnote 4 176 | l_λ = np.hstack((α_d, λ_1)) 177 | π_h = np.array([[0]]) 178 | 179 | δ_n = np.array([[0.95]]) 180 | d1 = np.vstack((δ_n, np.zeros((k - 1, 1)))) 181 | d2 = np.hstack((d1, np.eye(k))) 182 | δ_h = np.vstack((d2, np.zeros((1, k + 1)))) 183 | 184 | θ_h = np.vstack((np.zeros((k, 1)), 185 | np.ones((1, 1)))) 186 | 187 | ψ_1 = 1 / α_s 188 | 189 | ϕ_c = np.array([[1], [0]]) 190 | ϕ_g = np.array([[0], [-1]]) 191 | ϕ_i = np.array([[-1], [ψ_1]]) 192 | γ = np.array([[0], [0]]) 193 | 194 | δ_k = np.array([[0]]) 195 | θ_k = np.array([[0]]) 196 | 197 | ρ_s = 0.8 198 | ρ_d = 0.8 199 | 200 | a22 = np.array([[1, 0, 0], 201 | [0, ρ_s, 0], 202 | [0, 0, ρ_d]]) 203 | 204 | c2 = np.array([[0, 0], [10, 0], [0, 10]]) 205 | ub = np.array([[30, 0, 1]]) 206 | ud = np.array([[10, 1, 0], [0, 0, 0]]) 207 | 208 | info1 = Information(a22, c2, ub, ud) 209 | tech1 = Technology(ϕ_c, ϕ_g, ϕ_i, γ, δ_k, θ_k) 210 | pref1 = Preferences(β, l_λ, π_h, δ_h, θ_h) 211 | 212 | econ1 = DLE(info1, tech1, pref1) 213 | 214 | We create three other instances by: 215 | 216 | 1. Raising :math:`\alpha_d` to 2 217 | 2. Raising :math:`k` to 7 218 | 3. Raising :math:`k` to 10 219 | 220 | .. code-block:: python3 221 | 222 | α_d = np.array([[2]]) 223 | l_λ = np.hstack((α_d, λ_1)) 224 | pref2 = Preferences(β, l_λ, π_h, δ_h, θ_h) 225 | econ2 = DLE(info1, tech1, pref2) 226 | 227 | α_d = np.array([[0.1]]) 228 | 229 | k = 7 230 | λ_1 = np.ones((1, k)) * ε_1 231 | l_λ = np.hstack((α_d, λ_1)) 232 | d1 = np.vstack((δ_n, np.zeros((k - 1, 1)))) 233 | d2 = np.hstack((d1, np.eye(k))) 234 | δ_h = np.vstack((d2, np.zeros((1, k+1)))) 235 | θ_h = np.vstack((np.zeros((k, 1)), 236 | np.ones((1, 1)))) 237 | 238 | Pref3 = Preferences(β, l_λ, π_h, δ_h, θ_h) 239 | econ3 = DLE(info1, tech1, Pref3) 240 | 241 | k = 10 242 | λ_1 = np.ones((1, k)) * ε_1 243 | l_λ = np.hstack((α_d, λ_1)) 244 | d1 = np.vstack((δ_n, np.zeros((k - 1, 1)))) 245 | d2 = np.hstack((d1, np.eye(k))) 246 | δ_h = np.vstack((d2, np.zeros((1, k + 1)))) 247 | θ_h = np.vstack((np.zeros((k, 1)), 248 | np.ones((1, 1)))) 249 | 250 | pref4 = Preferences(β, l_λ, π_h, δ_h, θ_h) 251 | econ4 = DLE(info1, tech1, pref4) 252 | 253 | shock_demand = np.array([[0], [1]]) 254 | 255 | econ1.irf(ts_length=25, shock=shock_demand) 256 | econ2.irf(ts_length=25, shock=shock_demand) 257 | econ3.irf(ts_length=25, shock=shock_demand) 258 | econ4.irf(ts_length=25, shock=shock_demand) 259 | 260 | The first figure plots the impulse response of :math:`n_t` (on the left) 261 | and :math:`N_t` (on the right) to a positive demand shock, for 262 | :math:`\alpha_d = 0.1` and :math:`\alpha_d = 2`. 263 | 264 | When :math:`\alpha_d = 2`, the number of new students :math:`n_t` rises 265 | initially, but the response then turns negative. 266 | 267 | A positive demand shock raises wages, drawing new students into the 268 | profession. 269 | 270 | However, these new students raise :math:`N_t`. 271 | 272 | The higher is :math:`\alpha_d`, the larger the effect of this rise in 273 | :math:`N_t` on wages. 274 | 275 | This counteracts the demand shock's positive effect on wages, reducing 276 | the number of new students in subsequent periods. 277 | 278 | Consequently, when :math:`\alpha_d` is lower, the effect of a demand 279 | shock on :math:`N_t` is larger 280 | 281 | .. code-block:: python3 282 | 283 | 284 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4)) 285 | ax1.plot(econ1.c_irf,label='$\\alpha_d = 0.1$') 286 | ax1.plot(econ2.c_irf,label='$\\alpha_d = 2$') 287 | ax1.legend() 288 | ax1.set_title('Response of $n_t$ to a demand shock') 289 | 290 | ax2.plot(econ1.h_irf[:, 0], label='$\\alpha_d = 0.1$') 291 | ax2.plot(econ2.h_irf[:, 0], label='$\\alpha_d = 24$') 292 | ax2.legend() 293 | ax2.set_title('Response of $N_t$ to a demand shock') 294 | plt.show() 295 | 296 | The next figure plots the impulse response of :math:`n_t` (on the left) 297 | and :math:`N_t` (on the right) to a positive demand shock, for 298 | :math:`k=4`, :math:`k=7` and :math:`k=10` (with :math:`\alpha_d = 0.1`) 299 | 300 | .. code-block:: python3 301 | 302 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4)) 303 | ax1.plot(econ1.c_irf, label='$k=4$') 304 | ax1.plot(econ3.c_irf, label='$k=7$') 305 | ax1.plot(econ4.c_irf, label='$k=10$') 306 | ax1.legend() 307 | ax1.set_title('Response of $n_t$ to a demand shock') 308 | 309 | ax2.plot(econ1.h_irf[:,0], label='$k=4$') 310 | ax2.plot(econ3.h_irf[:,0], label='$k=7$') 311 | ax2.plot(econ4.h_irf[:,0], label='$k=10$') 312 | ax2.legend() 313 | ax2.set_title('Response of $N_t$ to a demand shock') 314 | plt.show() 315 | 316 | 317 | Both panels in the above figure show that raising :math:`k` lowers the effect of 318 | a positive demand shock on entry into the engineering profession. 319 | 320 | Increasing the number of periods of schooling lowers 321 | the number of new students in response to a demand shock. 322 | 323 | This occurs because with longer required schooling, new students ultimately benefit less from the impact of that shock on wages. 324 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/amss2/recursive_allocation.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.optimize import fmin_slsqp 3 | from scipy.optimize import root 4 | from quantecon import MarkovChain 5 | 6 | 7 | class RecursiveAllocationAMSS: 8 | 9 | def __init__(self, model, μgrid, tol_diff=1e-7, tol=1e-7): 10 | 11 | self.β, self.π, self.G = model.β, model.π, model.G 12 | self.mc, self.S = MarkovChain(self.π), len(model.π) # Number of states 13 | self.Θ, self.model, self.μgrid = model.Θ, model, μgrid 14 | self.tol_diff, self.tol = tol_diff, tol 15 | 16 | # Find the first best allocation 17 | self.solve_time1_bellman() 18 | self.T.time_0 = True # Bellman equation now solves time 0 problem 19 | 20 | def solve_time1_bellman(self): 21 | ''' 22 | Solve the time 1 Bellman equation for calibration model and 23 | initial grid μgrid0 24 | ''' 25 | model, μgrid0 = self.model, self.μgrid 26 | π = model.π 27 | S = len(model.π) 28 | 29 | # First get initial fit from Lucas Stokey solution. 30 | # Need to change things to be ex ante 31 | pp = SequentialAllocation(model) 32 | interp = interpolator_factory(2, None) 33 | 34 | def incomplete_allocation(μ_, s_): 35 | c, n, x, V = pp.time1_value(μ_) 36 | return c, n, π[s_] @ x, π[s_] @ V 37 | cf, nf, xgrid, Vf, xprimef = [], [], [], [], [] 38 | for s_ in range(S): 39 | c, n, x, V = zip(*map(lambda μ: incomplete_allocation(μ, s_), μgrid0)) 40 | c, n = np.vstack(c).T, np.vstack(n).T 41 | x, V = np.hstack(x), np.hstack(V) 42 | xprimes = np.vstack([x] * S) 43 | cf.append(interp(x, c)) 44 | nf.append(interp(x, n)) 45 | Vf.append(interp(x, V)) 46 | xgrid.append(x) 47 | xprimef.append(interp(x, xprimes)) 48 | cf, nf, xprimef = fun_vstack(cf), fun_vstack(nf), fun_vstack(xprimef) 49 | Vf = fun_hstack(Vf) 50 | policies = [cf, nf, xprimef] 51 | 52 | # Create xgrid 53 | x = np.vstack(xgrid).T 54 | xbar = [x.min(0).max(), x.max(0).min()] 55 | xgrid = np.linspace(xbar[0], xbar[1], len(μgrid0)) 56 | self.xgrid = xgrid 57 | 58 | # Now iterate on Bellman equation 59 | T = BellmanEquation(model, xgrid, policies, tol=self.tol) 60 | diff = 1 61 | while diff > self.tol_diff: 62 | PF = T(Vf) 63 | 64 | Vfnew, policies = self.fit_policy_function(PF) 65 | diff = np.abs((Vf(xgrid) - Vfnew(xgrid)) / Vf(xgrid)).max() 66 | 67 | print(diff) 68 | Vf = Vfnew 69 | 70 | # Store value function policies and Bellman Equations 71 | self.Vf = Vf 72 | self.policies = policies 73 | self.T = T 74 | 75 | def fit_policy_function(self, PF): 76 | ''' 77 | Fits the policy functions 78 | ''' 79 | S, xgrid = len(self.π), self.xgrid 80 | interp = interpolator_factory(3, 0) 81 | cf, nf, xprimef, Tf, Vf = [], [], [], [], [] 82 | for s_ in range(S): 83 | PFvec = np.vstack([PF(x, s_) for x in self.xgrid]).T 84 | Vf.append(interp(xgrid, PFvec[0, :])) 85 | cf.append(interp(xgrid, PFvec[1:1 + S])) 86 | nf.append(interp(xgrid, PFvec[1 + S:1 + 2 * S])) 87 | xprimef.append(interp(xgrid, PFvec[1 + 2 * S:1 + 3 * S])) 88 | Tf.append(interp(xgrid, PFvec[1 + 3 * S:])) 89 | policies = fun_vstack(cf), fun_vstack( 90 | nf), fun_vstack(xprimef), fun_vstack(Tf) 91 | Vf = fun_hstack(Vf) 92 | return Vf, policies 93 | 94 | def Τ(self, c, n): 95 | ''' 96 | Computes Τ given c and n 97 | ''' 98 | model = self.model 99 | Uc, Un = model.Uc(c, n), model.Un(c, n) 100 | 101 | return 1 + Un / (self.Θ * Uc) 102 | 103 | def time0_allocation(self, B_, s0): 104 | ''' 105 | Finds the optimal allocation given initial government debt B_ and 106 | state s_0 107 | ''' 108 | PF = self.T(self.Vf) 109 | z0 = PF(B_, s0) 110 | c0, n0, xprime0, T0 = z0[1:] 111 | return c0, n0, xprime0, T0 112 | 113 | def simulate(self, B_, s_0, T, sHist=None): 114 | ''' 115 | Simulates planners policies for T periods 116 | ''' 117 | model, π = self.model, self.π 118 | Uc = model.Uc 119 | cf, nf, xprimef, Tf = self.policies 120 | 121 | if sHist is None: 122 | sHist = simulate_markov(π, s_0, T) 123 | 124 | cHist, nHist, Bhist, xHist, ΤHist, THist, μHist = np.zeros((7, T)) 125 | # Time 0 126 | cHist[0], nHist[0], xHist[0], THist[0] = self.time0_allocation(B_, s_0) 127 | ΤHist[0] = self.Τ(cHist[0], nHist[0])[s_0] 128 | Bhist[0] = B_ 129 | μHist[0] = self.Vf[s_0](xHist[0]) 130 | 131 | # Time 1 onward 132 | for t in range(1, T): 133 | s_, x, s = sHist[t - 1], xHist[t - 1], sHist[t] 134 | c, n, xprime, T = cf[s_, :](x), nf[s_, :]( 135 | x), xprimef[s_, :](x), Tf[s_, :](x) 136 | 137 | Τ = self.Τ(c, n)[s] 138 | u_c = Uc(c, n) 139 | Eu_c = π[s_, :] @ u_c 140 | 141 | μHist[t] = self.Vf[s](xprime[s]) 142 | 143 | cHist[t], nHist[t], Bhist[t], ΤHist[t] = c[s], n[s], x / Eu_c, Τ 144 | xHist[t], THist[t] = xprime[s], T[s] 145 | return np.array([cHist, nHist, Bhist, ΤHist, THist, μHist, sHist, xHist]) 146 | 147 | 148 | class BellmanEquation: 149 | ''' 150 | Bellman equation for the continuation of the Lucas-Stokey Problem 151 | ''' 152 | 153 | def __init__(self, model, xgrid, policies0, tol, maxiter=1000): 154 | 155 | self.β, self.π, self.G = model.β, model.π, model.G 156 | self.S = len(model.π) # Number of states 157 | self.Θ, self.model, self.tol = model.Θ, model, tol 158 | self.maxiter = maxiter 159 | 160 | self.xbar = [min(xgrid), max(xgrid)] 161 | self.time_0 = False 162 | 163 | self.z0 = {} 164 | cf, nf, xprimef = policies0 165 | 166 | for s_ in range(self.S): 167 | for x in xgrid: 168 | self.z0[x, s_] = np.hstack([cf[s_, :](x), 169 | nf[s_, :](x), 170 | xprimef[s_, :](x), 171 | np.zeros(self.S)]) 172 | 173 | self.find_first_best() 174 | 175 | def find_first_best(self): 176 | ''' 177 | Find the first best allocation 178 | ''' 179 | model = self.model 180 | S, Θ, Uc, Un, G = self.S, self.Θ, model.Uc, model.Un, self.G 181 | 182 | def res(z): 183 | c = z[:S] 184 | n = z[S:] 185 | return np.hstack([Θ * Uc(c, n) + Un(c, n), Θ * n - c - G]) 186 | 187 | res = root(res, 0.5 * np.ones(2 * S)) 188 | if not res.success: 189 | raise Exception('Could not find first best') 190 | 191 | self.cFB = res.x[:S] 192 | self.nFB = res.x[S:] 193 | IFB = Uc(self.cFB, self.nFB) * self.cFB + \ 194 | Un(self.cFB, self.nFB) * self.nFB 195 | 196 | self.xFB = np.linalg.solve(np.eye(S) - self.β * self.π, IFB) 197 | 198 | self.zFB = {} 199 | for s in range(S): 200 | self.zFB[s] = np.hstack( 201 | [self.cFB[s], self.nFB[s], self.π[s] @ self.xFB, 0.]) 202 | 203 | def __call__(self, Vf): 204 | ''' 205 | Given continuation value function next period return value function this 206 | period return T(V) and optimal policies 207 | ''' 208 | if not self.time_0: 209 | def PF(x, s): return self.get_policies_time1(x, s, Vf) 210 | else: 211 | def PF(B_, s0): return self.get_policies_time0(B_, s0, Vf) 212 | return PF 213 | 214 | def get_policies_time1(self, x, s_, Vf): 215 | ''' 216 | Finds the optimal policies 217 | ''' 218 | model, β, Θ, G, S, π = self.model, self.β, self.Θ, self.G, self.S, self.π 219 | U, Uc, Un = model.U, model.Uc, model.Un 220 | 221 | def objf(z): 222 | c, n, xprime = z[:S], z[S:2 * S], z[2 * S:3 * S] 223 | 224 | Vprime = np.empty(S) 225 | for s in range(S): 226 | Vprime[s] = Vf[s](xprime[s]) 227 | 228 | return -π[s_] @ (U(c, n) + β * Vprime) 229 | 230 | def objf_prime(x): 231 | 232 | epsilon = 1e-7 233 | x0 = np.asfarray(x) 234 | f0 = np.atleast_1d(objf(x0)) 235 | jac = np.zeros([len(x0), len(f0)]) 236 | dx = np.zeros(len(x0)) 237 | for i in range(len(x0)): 238 | dx[i] = epsilon 239 | jac[i] = (objf(x0+dx) - f0)/epsilon 240 | dx[i] = 0.0 241 | 242 | return jac.transpose() 243 | 244 | def cons(z): 245 | c, n, xprime, T = z[:S], z[S:2 * S], z[2 * S:3 * S], z[3 * S:] 246 | u_c = Uc(c, n) 247 | Eu_c = π[s_] @ u_c 248 | return np.hstack([ 249 | x * u_c / Eu_c - u_c * (c - T) - Un(c, n) * n - β * xprime, 250 | Θ * n - c - G]) 251 | 252 | if model.transfers: 253 | bounds = [(0., 100)] * S + [(0., 100)] * S + \ 254 | [self.xbar] * S + [(0., 100.)] * S 255 | else: 256 | bounds = [(0., 100)] * S + [(0., 100)] * S + \ 257 | [self.xbar] * S + [(0., 0.)] * S 258 | out, fx, _, imode, smode = fmin_slsqp(objf, self.z0[x, s_], 259 | f_eqcons=cons, bounds=bounds, 260 | fprime=objf_prime, full_output=True, 261 | iprint=0, acc=self.tol, iter=self.maxiter) 262 | 263 | if imode > 0: 264 | raise Exception(smode) 265 | 266 | self.z0[x, s_] = out 267 | return np.hstack([-fx, out]) 268 | 269 | def get_policies_time0(self, B_, s0, Vf): 270 | ''' 271 | Finds the optimal policies 272 | ''' 273 | model, β, Θ, G = self.model, self.β, self.Θ, self.G 274 | U, Uc, Un = model.U, model.Uc, model.Un 275 | 276 | def objf(z): 277 | c, n, xprime = z[:-1] 278 | 279 | return -(U(c, n) + β * Vf[s0](xprime)) 280 | 281 | def cons(z): 282 | c, n, xprime, T = z 283 | return np.hstack([ 284 | -Uc(c, n) * (c - B_ - T) - Un(c, n) * n - β * xprime, 285 | (Θ * n - c - G)[s0]]) 286 | 287 | if model.transfers: 288 | bounds = [(0., 100), (0., 100), self.xbar, (0., 100.)] 289 | else: 290 | bounds = [(0., 100), (0., 100), self.xbar, (0., 0.)] 291 | out, fx, _, imode, smode = fmin_slsqp(objf, self.zFB[s0], f_eqcons=cons, 292 | bounds=bounds, full_output=True, 293 | iprint=0) 294 | 295 | if imode > 0: 296 | raise Exception(smode) 297 | 298 | return np.hstack([-fx, out]) 299 | -------------------------------------------------------------------------------- /source/_static/lecture_specific/lu_tricks/control_and_filter.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.stats as spst 3 | import scipy.linalg as la 4 | 5 | class LQFilter: 6 | 7 | def __init__(self, d, h, y_m, r=None, h_eps=None, β=None): 8 | """ 9 | 10 | Parameters 11 | ---------- 12 | d : list or numpy.array (1-D or a 2-D column vector) 13 | The order of the coefficients: [d_0, d_1, ..., d_m] 14 | h : scalar 15 | Parameter of the objective function (corresponding to the 16 | quadratic term) 17 | y_m : list or numpy.array (1-D or a 2-D column vector) 18 | Initial conditions for y 19 | r : list or numpy.array (1-D or a 2-D column vector) 20 | The order of the coefficients: [r_0, r_1, ..., r_k] 21 | (optional, if not defined -> deterministic problem) 22 | β : scalar 23 | Discount factor (optional, default value is one) 24 | """ 25 | 26 | self.h = h 27 | self.d = np.asarray(d) 28 | self.m = self.d.shape[0] - 1 29 | 30 | self.y_m = np.asarray(y_m) 31 | 32 | if self.m == self.y_m.shape[0]: 33 | self.y_m = self.y_m.reshape(self.m, 1) 34 | else: 35 | raise ValueError("y_m must be of length m = {self.m:d}") 36 | 37 | #--------------------------------------------- 38 | # Define the coefficients of ϕ upfront 39 | #--------------------------------------------- 40 | ϕ = np.zeros(2 * self.m + 1) 41 | for i in range(- self.m, self.m + 1): 42 | ϕ[self.m - i] = np.sum(np.diag(self.d.reshape(self.m + 1, 1) \ 43 | @ self.d.reshape(1, self.m + 1), 44 | k=-i 45 | ) 46 | ) 47 | ϕ[self.m] = ϕ[self.m] + self.h 48 | self.ϕ = ϕ 49 | 50 | #----------------------------------------------------- 51 | # If r is given calculate the vector ϕ_r 52 | #----------------------------------------------------- 53 | if r is None: 54 | pass 55 | else: 56 | self.r = np.asarray(r) 57 | self.k = self.r.shape[0] - 1 58 | ϕ_r = np.zeros(2 * self.k + 1) 59 | for i in range(- self.k, self.k + 1): 60 | ϕ_r[self.k - i] = np.sum(np.diag(self.r.reshape(self.k + 1, 1) \ 61 | @ self.r.reshape(1, self.k + 1), 62 | k=-i 63 | ) 64 | ) 65 | if h_eps is None: 66 | self.ϕ_r = ϕ_r 67 | else: 68 | ϕ_r[self.k] = ϕ_r[self.k] + h_eps 69 | self.ϕ_r = ϕ_r 70 | 71 | #----------------------------------------------------- 72 | # If β is given, define the transformed variables 73 | #----------------------------------------------------- 74 | if β is None: 75 | self.β = 1 76 | else: 77 | self.β = β 78 | self.d = self.β**(np.arange(self.m + 1)/2) * self.d 79 | self.y_m = self.y_m * (self.β**(- np.arange(1, self.m + 1)/2)) \ 80 | .reshape(self.m, 1) 81 | 82 | def construct_W_and_Wm(self, N): 83 | """ 84 | This constructs the matrices W and W_m for a given number of periods N 85 | """ 86 | 87 | m = self.m 88 | d = self.d 89 | 90 | W = np.zeros((N + 1, N + 1)) 91 | W_m = np.zeros((N + 1, m)) 92 | 93 | #--------------------------------------- 94 | # Terminal conditions 95 | #--------------------------------------- 96 | 97 | D_m1 = np.zeros((m + 1, m + 1)) 98 | M = np.zeros((m + 1, m)) 99 | 100 | # (1) Constuct the D_{m+1} matrix using the formula 101 | 102 | for j in range(m + 1): 103 | for k in range(j, m + 1): 104 | D_m1[j, k] = d[:j + 1] @ d[k - j: k + 1] 105 | 106 | # Make the matrix symmetric 107 | D_m1 = D_m1 + D_m1.T - np.diag(np.diag(D_m1)) 108 | 109 | # (2) Construct the M matrix using the entries of D_m1 110 | 111 | for j in range(m): 112 | for i in range(j + 1, m + 1): 113 | M[i, j] = D_m1[i - j - 1, m] 114 | 115 | #---------------------------------------------- 116 | # Euler equations for t = 0, 1, ..., N-(m+1) 117 | #---------------------------------------------- 118 | ϕ = self.ϕ 119 | 120 | W[:(m + 1), :(m + 1)] = D_m1 + self.h * np.eye(m + 1) 121 | W[:(m + 1), (m + 1):(2 * m + 1)] = M 122 | 123 | for i, row in enumerate(np.arange(m + 1, N + 1 - m)): 124 | W[row, (i + 1):(2 * m + 2 + i)] = ϕ 125 | 126 | for i in range(1, m + 1): 127 | W[N - m + i, -(2 * m + 1 - i):] = ϕ[:-i] 128 | 129 | for i in range(m): 130 | W_m[N - i, :(m - i)] = ϕ[(m + 1 + i):] 131 | 132 | return W, W_m 133 | 134 | def roots_of_characteristic(self): 135 | """ 136 | This function calculates z_0 and the 2m roots of the characteristic 137 | equation associated with the Euler equation (1.7) 138 | 139 | Note: 140 | ------ 141 | numpy.poly1d(roots, True) defines a polynomial using its roots that can 142 | be evaluated at any point. If x_1, x_2, ... , x_m are the roots then 143 | p(x) = (x - x_1)(x - x_2)...(x - x_m) 144 | """ 145 | m = self.m 146 | ϕ = self.ϕ 147 | 148 | # Calculate the roots of the 2m-polynomial 149 | roots = np.roots(ϕ) 150 | # Sort the roots according to their length (in descending order) 151 | roots_sorted = roots[np.argsort(abs(roots))[::-1]] 152 | 153 | z_0 = ϕ.sum() / np.poly1d(roots, True)(1) 154 | z_1_to_m = roots_sorted[:m] # We need only those outside the unit circle 155 | 156 | λ = 1 / z_1_to_m 157 | 158 | return z_1_to_m, z_0, λ 159 | 160 | def coeffs_of_c(self): 161 | ''' 162 | This function computes the coefficients {c_j, j = 0, 1, ..., m} for 163 | c(z) = sum_{j = 0}^{m} c_j z^j 164 | 165 | Based on the expression (1.9). The order is 166 | c_coeffs = [c_0, c_1, ..., c_{m-1}, c_m] 167 | ''' 168 | z_1_to_m, z_0 = self.roots_of_characteristic()[:2] 169 | 170 | c_0 = (z_0 * np.prod(z_1_to_m).real * (- 1)**self.m)**(.5) 171 | c_coeffs = np.poly1d(z_1_to_m, True).c * z_0 / c_0 172 | 173 | return c_coeffs[::-1] 174 | 175 | def solution(self): 176 | """ 177 | This function calculates {λ_j, j=1,...,m} and {A_j, j=1,...,m} 178 | of the expression (1.15) 179 | """ 180 | λ = self.roots_of_characteristic()[2] 181 | c_0 = self.coeffs_of_c()[-1] 182 | 183 | A = np.zeros(self.m, dtype=complex) 184 | for j in range(self.m): 185 | denom = 1 - λ/λ[j] 186 | A[j] = c_0**(-2) / np.prod(denom[np.arange(self.m) != j]) 187 | 188 | return λ, A 189 | 190 | def construct_V(self, N): 191 | ''' 192 | This function constructs the covariance matrix for x^N (see section 6) 193 | for a given period N 194 | ''' 195 | V = np.zeros((N, N)) 196 | ϕ_r = self.ϕ_r 197 | 198 | for i in range(N): 199 | for j in range(N): 200 | if abs(i-j) <= self.k: 201 | V[i, j] = ϕ_r[self.k + abs(i-j)] 202 | 203 | return V 204 | 205 | def simulate_a(self, N): 206 | """ 207 | Assuming that the u's are normal, this method draws a random path 208 | for x^N 209 | """ 210 | V = self.construct_V(N + 1) 211 | d = spst.multivariate_normal(np.zeros(N + 1), V) 212 | 213 | return d.rvs() 214 | 215 | def predict(self, a_hist, t): 216 | """ 217 | This function implements the prediction formula discussed in section 6 (1.59) 218 | It takes a realization for a^N, and the period in which the prediction is 219 | formed 220 | 221 | Output: E[abar | a_t, a_{t-1}, ..., a_1, a_0] 222 | """ 223 | 224 | N = np.asarray(a_hist).shape[0] - 1 225 | a_hist = np.asarray(a_hist).reshape(N + 1, 1) 226 | V = self.construct_V(N + 1) 227 | 228 | aux_matrix = np.zeros((N + 1, N + 1)) 229 | aux_matrix[:(t + 1), :(t + 1)] = np.eye(t + 1) 230 | L = la.cholesky(V).T 231 | Ea_hist = la.inv(L) @ aux_matrix @ L @ a_hist 232 | 233 | return Ea_hist 234 | 235 | def optimal_y(self, a_hist, t=None): 236 | """ 237 | - if t is NOT given it takes a_hist (list or numpy.array) as a 238 | deterministic a_t 239 | - if t is given, it solves the combined control prediction problem 240 | (section 7)(by default, t == None -> deterministic) 241 | 242 | for a given sequence of a_t (either deterministic or a particular 243 | realization), it calculates the optimal y_t sequence using the method 244 | of the lecture 245 | 246 | Note: 247 | ------ 248 | scipy.linalg.lu normalizes L, U so that L has unit diagonal elements 249 | To make things consistent with the lecture, we need an auxiliary 250 | diagonal matrix D which renormalizes L and U 251 | """ 252 | 253 | N = np.asarray(a_hist).shape[0] - 1 254 | W, W_m = self.construct_W_and_Wm(N) 255 | 256 | L, U = la.lu(W, permute_l=True) 257 | D = np.diag(1 / np.diag(U)) 258 | U = D @ U 259 | L = L @ np.diag(1 / np.diag(D)) 260 | 261 | J = np.fliplr(np.eye(N + 1)) 262 | 263 | if t is None: # If the problem is deterministic 264 | 265 | a_hist = J @ np.asarray(a_hist).reshape(N + 1, 1) 266 | 267 | #-------------------------------------------- 268 | # Transform the 'a' sequence if β is given 269 | #-------------------------------------------- 270 | if self.β != 1: 271 | a_hist = a_hist * (self.β**(np.arange(N + 1) / 2))[::-1] \ 272 | .reshape(N + 1, 1) 273 | 274 | a_bar = a_hist - W_m @ self.y_m # a_bar from the lecture 275 | Uy = np.linalg.solve(L, a_bar) # U @ y_bar = L^{-1} 276 | y_bar = np.linalg.solve(U, Uy) # y_bar = U^{-1}L^{-1} 277 | 278 | # Reverse the order of y_bar with the matrix J 279 | J = np.fliplr(np.eye(N + self.m + 1)) 280 | # y_hist : concatenated y_m and y_bar 281 | y_hist = J @ np.vstack([y_bar, self.y_m]) 282 | 283 | #-------------------------------------------- 284 | # Transform the optimal sequence back if β is given 285 | #-------------------------------------------- 286 | if self.β != 1: 287 | y_hist = y_hist * (self.β**(- np.arange(-self.m, N + 1)/2)) \ 288 | .reshape(N + 1 + self.m, 1) 289 | 290 | return y_hist, L, U, y_bar 291 | 292 | else: # If the problem is stochastic and we look at it 293 | 294 | Ea_hist = self.predict(a_hist, t).reshape(N + 1, 1) 295 | Ea_hist = J @ Ea_hist 296 | 297 | a_bar = Ea_hist - W_m @ self.y_m # a_bar from the lecture 298 | Uy = np.linalg.solve(L, a_bar) # U @ y_bar = L^{-1} 299 | y_bar = np.linalg.solve(U, Uy) # y_bar = U^{-1}L^{-1} 300 | 301 | # Reverse the order of y_bar with the matrix J 302 | J = np.fliplr(np.eye(N + self.m + 1)) 303 | # y_hist : concatenated y_m and y_bar 304 | y_hist = J @ np.vstack([y_bar, self.y_m]) 305 | 306 | return y_hist, L, U, y_bar 307 | -------------------------------------------------------------------------------- /source/rst/hs_invertibility_example.rst: -------------------------------------------------------------------------------- 1 | .. _hs_invertibility_example: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | .. index:: 6 | single: python 7 | 8 | *********************** 9 | Shock Non Invertibility 10 | *********************** 11 | 12 | .. contents:: :depth: 2 13 | 14 | Overview 15 | ======== 16 | 17 | This is another member of a suite of lectures that use the quantecon DLE class to instantiate models within the 18 | :cite:`HS2013` class of models described in detail in :doc:`Recursive Models of Dynamic Linear Economies`. 19 | 20 | In addition to what's in Anaconda, this lecture uses the quantecon library. 21 | 22 | .. code-block:: ipython 23 | :class: hide-output 24 | 25 | !pip install --upgrade quantecon 26 | 27 | We'll make these imports: 28 | 29 | .. code-block:: ipython 30 | 31 | import numpy as np 32 | import quantecon as qe 33 | import matplotlib.pyplot as plt 34 | from quantecon import LQ 35 | from quantecon import DLE 36 | from math import sqrt 37 | %matplotlib inline 38 | 39 | This lecture can be viewed as introducing an early contribution to what is now often called 40 | a **news and noise** issue. 41 | 42 | In particular, it analyzes a **shock-invertibility** issue that is 43 | endemic within a class of permanent income models. 44 | 45 | Technically, the invertibility problem indicates a situation in which 46 | histories of the shocks in an econometrician's autoregressive or Wold 47 | moving average representation span a smaller information space than do 48 | the shocks that are seen by the agents inside the econometrician's model. 49 | 50 | This situation sets the stage for an econometrician who is unaware of the 51 | problem and consequently misinterprets shocks and likely responses to them. 52 | 53 | A shock-invertibility that is technically close to the one studied here is discussed by 54 | Eric Leeper, Todd Walker, and Susan Yang :cite:`Leeper_Walker_Yang` in their analysis of **fiscal foresight**. 55 | 56 | A distinct shock-invertibility issue is present in the special LQ consumption smoothing model 57 | in :doc:`quantecon lecture`. 58 | 59 | Model 60 | ===== 61 | 62 | We consider the following modification of Robert Hall's (1978) model :cite:`Hall1978` in which the endowment process is the sum of two orthogonal autoregressive processes: 63 | 64 | **Preferences** 65 | 66 | .. math:: -\frac{1}{2}\mathbb{E}\sum_{t=0}^\infty \beta^t[(c_t - b_t)^2 + l_t^2]|J_0 67 | 68 | .. math:: s_t = c_t 69 | 70 | .. math:: b_t = U_bz_t 71 | 72 | **Technology** 73 | 74 | .. math:: c_t + i_t = \gamma k_{t-1} + d_t 75 | 76 | .. math:: k_t = \delta_k k_{t-1} + i_t 77 | 78 | .. math:: g_t = \phi_1 i_t \, , \phi_1 > 0 79 | 80 | .. math:: g_t \cdot g_t = l_t^2 81 | 82 | **Information** 83 | 84 | .. math:: 85 | 86 | z_{t+1} = 87 | \left[ {\begin{array}{cccccc} 88 | 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0.9 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 89 | \end{array} } 90 | \right] 91 | z_t + 92 | \left[ {\begin{array}{cc} 93 | 0 & 0 \\ 1 & 0 \\ 0 & 4 \\ 0 & 0 \\ 0 & 0 \\ 0 & 0 94 | \end{array} } 95 | \right] 96 | w_{t+1} 97 | 98 | .. math:: 99 | 100 | U_b = 101 | \left[ {\begin{array}{cccccc} 102 | 30 & 0 & 0 & 0 & 0 & 0 103 | \end{array} } 104 | \right] 105 | 106 | .. math:: 107 | 108 | U_d = 109 | \left[ {\begin{array}{cccccc} 110 | 5 & 1 & 1 & 0.8 & 0.6 & 0.4 \\ 0 & 0 & 0 & 0 & 0 & 0 111 | \end{array} } 112 | \right] 113 | 114 | The preference shock is constant at 30, while the endowment process is 115 | the sum of a constant and two orthogonal processes. 116 | 117 | Specifically: 118 | 119 | .. math:: d_t = 5 + d_{1t} + d_{2t} 120 | 121 | .. math:: d_{1t} = 0.9d_{1t-1} + w_{1t} 122 | 123 | .. math:: d_{2t} = 4w_{2t} + 0.8(4w_{2t-1})+ 0.6(4w_{2t-2})+ 0.4(4w_{2t-3}) 124 | 125 | :math:`d_{1t}` is a first-order AR process, while :math:`d_{2t}` is a 126 | third-order pure moving average process. 127 | 128 | .. code-block:: python3 129 | 130 | γ_1 = 0.05 131 | γ = np.array([[γ_1], [0]]) 132 | ϕ_c = np.array([[1], [0]]) 133 | ϕ_g = np.array([[0], [1]]) 134 | ϕ_1 = 0.00001 135 | ϕ_i = np.array([[1], [-ϕ_1]]) 136 | δ_k = np.array([[1]]) 137 | θ_k = np.array([[1]]) 138 | β = np.array([[1 / 1.05]]) 139 | l_λ = np.array([[0]]) 140 | π_h = np.array([[1]]) 141 | δ_h = np.array([[.9]]) 142 | θ_h = np.array([[1]]) - δ_h 143 | ud = np.array([[5, 1, 1, 0.8, 0.6, 0.4], 144 | [0, 0, 0, 0, 0, 0]]) 145 | a22 = np.zeros((6, 6)) 146 | # Chase's great trick 147 | a22[[0, 1, 3, 4, 5], [0, 1, 2, 3, 4]] = np.array([1.0, 0.9, 1.0, 1.0, 1.0]) 148 | c2 = np.zeros((6, 2)) 149 | c2[[1, 2], [0, 1]] = np.array([1.0, 4.0]) 150 | ub = np.array([[30, 0, 0, 0, 0, 0]]) 151 | x0 = np.array([[5], [150], [1], [0], [0], [0], [0], [0]]) 152 | 153 | info1 = (a22, c2, ub, ud) 154 | tech1 = (ϕ_c, ϕ_g, ϕ_i, γ, δ_k, θ_k) 155 | pref1 = (β, l_λ, π_h, δ_h, θ_h) 156 | 157 | econ1 = DLE(info1, tech1, pref1) 158 | 159 | We define the household's net of interest deficit as :math:`c_t - d_t`. 160 | 161 | Hall's model imposes "expected present-value budget balance" in the 162 | sense that 163 | 164 | .. math:: \mathbb{E}\sum_{j=0}^\infty \beta^j (c_{t+j} - d_{t+j})|J_t = \beta^{-1}k_{t-1} \, \forall t 165 | 166 | If we define the moving average representation of 167 | :math:`(c_t, c_t - d_t)` in terms of the :math:`w_t`\ s to be: 168 | 169 | .. math:: 170 | 171 | \left[ {\begin{array}{c} 172 | c_t \\ c_t - d_t 173 | \end{array} } 174 | \right] = \left[ {\begin{array}{c} 175 | \sigma_1(L) \\ \sigma_2(L) 176 | \end{array} } 177 | \right] w_t 178 | 179 | then Hall's model imposes the restriction 180 | :math:`\sigma_2(\beta) = [0\,\,\,0]`. 181 | 182 | The agent inside this model sees histories of both components of the 183 | endowment process :math:`d_{1t}` and :math:`d_{2t}`. 184 | 185 | The econometrician has data on the history of the pair 186 | :math:`[c_t,d_t]`, but not directly on the history of :math:`w_t`. 187 | 188 | The econometrician obtains a Wold representation for the process 189 | :math:`[c_t,c_t-d_t]`: 190 | 191 | .. math:: 192 | 193 | \left[ {\begin{array}{c} 194 | c_t \\ c_t - d_t 195 | \end{array} } 196 | \right] = \left[ {\begin{array}{c} 197 | \sigma_1^*(L) \\ \sigma_2^*(L) 198 | \end{array} } 199 | \right] u_t 200 | 201 | The Appendix of chapter 8 of :cite:`HS2013` explains why the impulse 202 | response functions in the Wold representation estimated by the 203 | econometrician do not resemble the impulse response functions that 204 | depict the response of consumption and the deficit to innovations to 205 | agents' information. 206 | 207 | Technically, :math:`\sigma_2(\beta) = [0\,\,\,0]` implies that the 208 | history of :math:`u_t`\ s spans a *smaller* linear space than does the 209 | history of :math:`w_t`\ s. 210 | 211 | This means that :math:`u_t` will typically be a distributed lag of 212 | :math:`w_t` that is not concentrated at zero lag: 213 | 214 | .. math:: u_t = \sum_{j=0}^\infty \alpha_j w_{t-j} 215 | 216 | Thus, the econometrician's news :math:`u_t` potentially responds 217 | belatedly to agents' news :math:`w_t`. 218 | 219 | Code 220 | ==== 221 | 222 | We will construct Figures from Chapter 8 Appendix E of :cite:`HS2013` to 223 | illustrate these ideas: 224 | 225 | .. code-block:: python3 226 | 227 | # This is Fig 8.E.1 from p.188 of HS2013 228 | 229 | econ1.irf(ts_length=40, shock=None) 230 | 231 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4)) 232 | ax1.plot(econ1.c_irf, label='Consumption') 233 | ax1.plot(econ1.c_irf - econ1.d_irf[:,0].reshape(40,1), label='Deficit') 234 | ax1.legend() 235 | ax1.set_title('Response to $w_{1t}$') 236 | 237 | shock2 = np.array([[0], [1]]) 238 | econ1.irf(ts_length=40, shock=shock2) 239 | 240 | ax2.plot(econ1.c_irf, label='Consumption') 241 | ax2.plot(econ1.c_irf - econ1.d_irf[:,0].reshape(40, 1), label='Deficit') 242 | ax2.legend() 243 | ax2.set_title('Response to $w_{2t}$') 244 | plt.show() 245 | 246 | The above figure displays the impulse response of consumption and the 247 | deficit to the endowment innovations. 248 | 249 | Consumption displays the characteristic "random walk" response with 250 | respect to each innovation. 251 | 252 | Each endowment innovation leads to a 253 | temporary surplus followed by a permanent net-of-interest deficit. 254 | 255 | The temporary surplus just offsets the permanent deficit in terms of 256 | expected present value. 257 | 258 | .. code-block:: python3 259 | 260 | G_HS = np.vstack([econ1.Sc, econ1.Sc-econ1.Sd[0, :].reshape(1, 8)]) 261 | H_HS = 1e-8 * np.eye(2) # Set very small so there is no measurement error 262 | lss_hs = qe.LinearStateSpace(econ1.A0, econ1.C, G_HS, H_HS) 263 | 264 | hs_kal = qe.Kalman(lss_hs) 265 | w_lss = hs_kal.whitener_lss() 266 | ma_coefs = hs_kal.stationary_coefficients(50, 'ma') 267 | 268 | # This is Fig 8.E.2 from p.189 of HS2013 269 | 270 | ma_coefs = ma_coefs 271 | jj = 50 272 | y1_w1 = np.empty(jj) 273 | y2_w1 = np.empty(jj) 274 | y1_w2 = np.empty(jj) 275 | y2_w2 = np.empty(jj) 276 | 277 | for t in range(jj): 278 | y1_w1[t] = ma_coefs[t][0, 0] 279 | y1_w2[t] = ma_coefs[t][0, 1] 280 | y2_w1[t] = ma_coefs[t][1, 0] 281 | y2_w2[t] = ma_coefs[t][1, 1] 282 | 283 | # This scales the impulse responses to match those in the book 284 | y1_w1 = sqrt(hs_kal.stationary_innovation_covar()[0, 0]) * y1_w1 285 | y2_w1 = sqrt(hs_kal.stationary_innovation_covar()[0, 0]) * y2_w1 286 | y1_w2 = sqrt(hs_kal.stationary_innovation_covar()[1, 1]) * y1_w2 287 | y2_w2 = sqrt(hs_kal.stationary_innovation_covar()[1, 1]) * y2_w2 288 | 289 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4)) 290 | ax1.plot(y1_w1, label='Consumption') 291 | ax1.plot(y2_w1, label='Deficit') 292 | ax1.legend() 293 | ax1.set_title('Response to $u_{1t}$') 294 | 295 | ax2.plot(y1_w2, label='Consumption') 296 | ax2.plot(y2_w2, label='Deficit') 297 | ax2.legend() 298 | ax2.set_title('Response to $u_{2t}$') 299 | plt.show() 300 | 301 | 302 | 303 | The above figure displays the impulse response of consumption and the 304 | deficit to the innovations in the econometrician's Wold representation 305 | 306 | - this is the object that would be recovered from a high order vector 307 | autoregression on the econometrician's observations. 308 | 309 | Consumption responds only to the first innovation 310 | 311 | - this is indicative of the Granger causality imposed on the 312 | :math:`[c_t, c_t - d_t]` process by Hall's model: consumption Granger 313 | causes :math:`c_t - d_t`, with no reverse causality. 314 | 315 | .. code-block:: python3 316 | 317 | # This is Fig 8.E.3 from p.189 of HS2013 318 | 319 | jj = 20 320 | irf_wlss = w_lss.impulse_response(jj) 321 | ycoefs = irf_wlss[1] 322 | # Pull out the shocks 323 | a1_w1 = np.empty(jj) 324 | a1_w2 = np.empty(jj) 325 | a2_w1 = np.empty(jj) 326 | a2_w2 = np.empty(jj) 327 | 328 | for t in range(jj): 329 | a1_w1[t] = ycoefs[t][0, 0] 330 | a1_w2[t] = ycoefs[t][0, 1] 331 | a2_w1[t] = ycoefs[t][1, 0] 332 | a2_w2[t] = ycoefs[t][1, 1] 333 | 334 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4)) 335 | ax1.plot(a1_w1, label='Consumption innov.') 336 | ax1.plot(a2_w1, label='Deficit innov.') 337 | ax1.set_title('Response to $w_{1t}$') 338 | ax1.legend() 339 | ax2.plot(a1_w2, label='Consumption innov.') 340 | ax2.plot(a2_w2, label='Deficit innov.') 341 | ax2.legend() 342 | ax2.set_title('Response to $w_{2t}$') 343 | plt.show() 344 | 345 | The above figure displays the impulse responses of :math:`u_t` to 346 | :math:`w_t`, as depicted in: 347 | 348 | .. math:: u_t = \sum_{j=0}^\infty \alpha_j w_{t-j} 349 | 350 | While the responses of the innovations to consumption are concentrated 351 | at lag zero for both components of :math:`w_t`, the responses of the 352 | innovations to :math:`(c_t - d_t)` are spread over time (especially in 353 | response to :math:`w_{1t}`). 354 | 355 | Thus, the innovations to :math:`(c_t - d_t)` as revealed by the vector 356 | autoregression depend on what the economic agent views as "old news". 357 | -------------------------------------------------------------------------------- /theme/minimal/static/js/base.js: -------------------------------------------------------------------------------- 1 | // base.js v1.0 2 | 3 | 4 | // Declare MathJax Macros for the Appropriate Macros 5 | MathJax.Hub.Config({ 6 | TeX: { 7 | Macros: { 8 | Var: "\\mathop{\\mathrm{Var}}", 9 | trace: "\\mathop{\\mathrm{trace}}", 10 | argmax: "\\mathop{\\mathrm{arg\\,max}}", 11 | argmin: "\\mathop{\\mathrm{arg\\,min}}", 12 | proj: "\\mathop{\\mathrm{proj}}", 13 | col: "\\mathop{\\mathrm{col}}", 14 | Span: "\\mathop{\\mathrm{span}}", 15 | epsilon: "\\varepsilon", 16 | EE: "\\mathbb{E}", 17 | PP: "\\mathbb{P}", 18 | RR: "\\mathbb{R}", 19 | NN: "\\mathbb{N}", 20 | ZZ: "\\mathbb{Z}", 21 | aA: "\\mathcal{A}", 22 | bB: "\\mathcal{B}", 23 | cC: "\\mathcal{C}", 24 | dD: "\\mathcal{D}", 25 | eE: "\\mathcal{E}", 26 | fF: "\\mathcal{F}", 27 | gG: "\\mathcal{G}", 28 | hH: "\\mathcal{H}", 29 | } 30 | } 31 | }); 32 | MathJax.Hub.Config({ 33 | tex2jax: { 34 | inlineMath: [ ['$','$'], ['\\(','\\)'] ], 35 | processEscapes: true 36 | } 37 | }); 38 | 39 | 40 | /* Collapsed code block */ 41 | 42 | const collapsableCodeBlocks = document.querySelectorAll("div[class^='collapse'] .highlight"); 43 | for (var i = 0; i < collapsableCodeBlocks.length; i++) { 44 | const toggleContainer = document.createElement('div'); 45 | toggleContainer.innerHTML = 'Show more...'; 46 | collapsableCodeBlocks[i].parentNode.insertBefore(toggleContainer, collapsableCodeBlocks[i].nextSibling); 47 | } 48 | 49 | const collapsableCodeToggles = document.querySelectorAll("div[class^='collapse'] .toggle"); 50 | for (var i = 0; i < collapsableCodeToggles.length; i++) { 51 | collapsableCodeToggles[i].addEventListener('click', function(e) { 52 | e.preventDefault(); 53 | var codeBlock = this.closest('div[class^="collapse"]'); 54 | if ( codeBlock.classList.contains('expanded') ) { 55 | codeBlock.classList.remove('expanded'); 56 | this.style.display = 'none'; 57 | this.nextSibling.style.display = 'block'; 58 | } else { 59 | codeBlock.classList.add('expanded'); 60 | this.style.display = 'none'; 61 | this.previousSibling.style.display = 'block'; 62 | } 63 | }); 64 | } 65 | 66 | 67 | /* Wrap container around all tables allowing hirizontal scroll */ 68 | 69 | const contentTables = document.querySelectorAll(".content table"); 70 | for (var i = 0; i < contentTables.length; i++) { 71 | var wrapper = document.createElement('div'); 72 | wrapper.classList.add('table-container'); 73 | contentTables[i].parentNode.insertBefore(wrapper, contentTables[i]); 74 | wrapper.appendChild(contentTables[i]); 75 | } 76 | 77 | 78 | // Populate status page from code execution results JSON 79 | 80 | function loadCodeExecutionJSON(callback) { 81 | var xobj = new XMLHttpRequest(); 82 | xobj.overrideMimeType("application/json"); 83 | xobj.open('GET', '_static/code-execution-results.json', true); // Replace 'appDataServices' with the path to your file 84 | xobj.onreadystatechange = function () { 85 | if (xobj.readyState == 4 && xobj.status == "200") { 86 | // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode 87 | callback(xobj.responseText); 88 | } 89 | }; 90 | xobj.send(null); 91 | } 92 | 93 | if ( document.getElementById('status_table') ) { 94 | 95 | loadCodeExecutionJSON(function(response) { 96 | // Parsing JSON string into object 97 | var data = JSON.parse(response); 98 | var status_data = []; 99 | var last_test_time = data.run_time; 100 | document.getElementById('last_test_time').textContent = last_test_time; 101 | for (var key in data.results) 102 | { 103 | var new_record = {}; 104 | new_record['name'] = data.results[key].filename; 105 | new_record['runtime'] = data.results[key].runtime; 106 | new_record['extension'] = data.results[key].extension; 107 | new_record['result'] = data.results[key].num_errors; 108 | new_record['language'] = data.results[key].language; 109 | 110 | status_data.push(new_record); 111 | } 112 | 113 | // empty the table 114 | var table = document.getElementById("status_table"); 115 | while (table.firstChild) 116 | table.removeChild(table.firstChild); 117 | var rawHTML = "Lecture FileLanguageRunning Time"; 118 | table.innerHTML = rawHTML; 119 | // add the data 120 | for (var i = 0; i < status_data.length; i ++) 121 | { 122 | var table = document.getElementById("status_table"); 123 | var row = table.insertRow(-1); 124 | row.setAttribute("id", status_data[i]['name'], 0); 125 | 126 | // Insert new cells ( elements) at the 1st and 2nd position of the "new" element: 127 | var lectureCell = row.insertCell(0); 128 | var langCell = row.insertCell(1); 129 | var runtimeCell = row.insertCell(2); 130 | var statusCell = row.insertCell(3); 131 | var badge, status, color, lang, link; 132 | 133 | if (status_data[i]['result'] === 0) 134 | { 135 | status = "Passing"; 136 | color = "brightgreen"; 137 | } 138 | else if (status_data[i]['result'] === 1) 139 | { 140 | status = "Failing"; 141 | color = "red"; 142 | } 143 | else if (status_data[i]['result'] === -1) { 144 | status = "Not available"; 145 | color = "lightgrey"; 146 | } 147 | 148 | link = '/' + status_data[i]['name'] + '.html'; 149 | 150 | badge = ''; 151 | 152 | // Add some text to the new cells: 153 | lectureCell.innerHTML = status_data[i]['name']; 154 | langCell.innerHTML = status_data[i]['language']; 155 | runtimeCell.innerHTML = status_data[i]['runtime']; 156 | statusCell.innerHTML = badge; 157 | 158 | 159 | } 160 | }) 161 | } 162 | 163 | 164 | // Show executability status badge in header 165 | 166 | const LECTURE_OK = 0; 167 | const LECTURE_FAILED = 1; 168 | const LECTURE_ERROR = -1; 169 | 170 | function update_page_badge(page_status) 171 | { 172 | var badge = document.getElementById("executability_status_badge"); 173 | var status, color; 174 | 175 | if (page_status === LECTURE_OK) 176 | { 177 | status = "Passing"; 178 | color = "brightgreen"; 179 | } 180 | else if (page_status == LECTURE_FAILED) 181 | { 182 | status = "Failing"; 183 | color = "red"; 184 | } 185 | else if (page_status == LECTURE_ERROR) 186 | { 187 | status = "Not available"; 188 | color = "lightgrey"; 189 | } 190 | else 191 | { 192 | console.log("Panic! Invalid parameter passed to update_page_badge()."); 193 | } 194 | 195 | badge.innerHTML = ''; 196 | 197 | //badge.style.display="block"; 198 | 199 | return; 200 | } 201 | 202 | function determine_page_status(status_data) 203 | { 204 | var path = window.location.pathname; 205 | var filename_parts = path.split("/"); 206 | var filename = filename_parts.pop(); 207 | 208 | var lecture_name = filename.split(".")[0].toLowerCase(); 209 | 210 | var res = LECTURE_ERROR; 211 | 212 | for (var i = 0; i < status_data.length; i ++) 213 | { 214 | if (status_data[i]['name'].split('/').pop() === lecture_name) 215 | { 216 | if (status_data[i]['result'] === 0) 217 | { 218 | res = LECTURE_OK; 219 | } 220 | else 221 | { 222 | res = LECTURE_FAILED; 223 | } 224 | } 225 | } 226 | return res; 227 | } 228 | 229 | function load_this_page_badge() 230 | { 231 | loadCodeExecutionJSON(function(response) { 232 | // Parsing JSON string into object 233 | var data = JSON.parse(response); 234 | status_data = []; 235 | for (var key in data.results) 236 | { 237 | var new_record = {}; 238 | new_record['name'] = data.results[key].filename; 239 | new_record['runtime'] = data.results[key].runtime; 240 | new_record['extension'] = data.results[key].extension; 241 | new_record['result'] = data.results[key].num_errors; 242 | new_record['language'] = data.results[key].language; 243 | status_data.push(new_record); 244 | } 245 | var page_status = determine_page_status(status_data); 246 | update_page_badge(page_status); 247 | }); 248 | } 249 | 250 | function get_badge(percentage) 251 | { 252 | var color, badge; 253 | 254 | if (percentage > -1) 255 | { 256 | if ( percentage < 50 ) { 257 | color = 'red'; 258 | } else { 259 | color = 'brightgreen'; 260 | } 261 | badge = 'https://img.shields.io/badge/Total%20coverage-' + percentage + '%25-' + color + '.svg'; 262 | } else { 263 | badge = 'https://img.shields.io/badge/Total%20coverage-not%20available-lightgrey.svg>'; 264 | } 265 | return badge; 266 | } 267 | 268 | function load_percentages() 269 | { 270 | var number_of_lectures = {}; 271 | var number_which_passed = {}; 272 | var keys_list = []; 273 | var combined_percentage; 274 | 275 | loadCodeExecutionJSON(function(response) { 276 | // Parsing JSON string into object 277 | var data = JSON.parse(response); 278 | for (var key in data.results) 279 | { 280 | if (data.results[key].num_errors === 0) 281 | { 282 | if (!(data.results[key].extension in number_which_passed)) 283 | { 284 | number_which_passed[data.results[key].extension] = 0; 285 | keys_list.push(data.results[key].extension); 286 | } 287 | number_which_passed[data.results[key].extension] += 1; 288 | } 289 | 290 | if (!(data.results[key].extension in number_of_lectures)) 291 | { 292 | number_of_lectures[data.results[key].extension] = 0; 293 | } 294 | number_of_lectures[data.results[key].extension] += 1; 295 | } 296 | 297 | var percentages = {}; 298 | var total_lectures = 0; 299 | var total_passing = 0; 300 | for (var k in keys_list) 301 | { 302 | key = keys_list[k]; 303 | 304 | percentages[key] = 0; 305 | if (number_of_lectures[key] === 0) 306 | { 307 | // An appropriate value for this is yet to be determined. 308 | percentages[key] = 100; 309 | } 310 | else 311 | { 312 | percentages[key] = Math.floor(100 * number_which_passed[key] / number_of_lectures[key]); 313 | } 314 | 315 | // Sensible boundary checking. 316 | if (percentages[key] < 0 || percentages[key] > 100) 317 | { 318 | percentages[key] = -1; 319 | } 320 | 321 | total_lectures += number_of_lectures[key]; 322 | total_passing += number_which_passed[key]; 323 | } 324 | 325 | if (total_lectures === 0) 326 | { 327 | combined_percentage = 0; 328 | } 329 | else 330 | { 331 | combined_percentage = Math.floor(100 * total_passing / total_lectures); 332 | } 333 | 334 | var badge = document.getElementById("coverage_badge"); 335 | badge.innerHTML = ''; 336 | 337 | }); 338 | 339 | } 340 | 341 | if ( document.getElementById('executability_status_badge') ) { 342 | load_this_page_badge(); 343 | } 344 | 345 | if ( document.getElementById('coverage_badge') ) { 346 | load_percentages(); 347 | } -------------------------------------------------------------------------------- /source/rst/muth_kalman.rst: -------------------------------------------------------------------------------- 1 | .. _muth_kalman: 2 | 3 | .. include:: /_static/includes/header.raw 4 | 5 | .. index:: 6 | single: python 7 | 8 | ***************************** 9 | Reverse Engineering a la Muth 10 | ***************************** 11 | 12 | .. contents:: :depth: 2 13 | 14 | In addition to what's in Anaconda, this lecture uses the quantecon library. 15 | 16 | .. code-block:: ipython 17 | :class: hide-output 18 | 19 | !pip install --upgrade quantecon 20 | 21 | We'll also need the following imports: 22 | 23 | .. code-block:: ipython 24 | 25 | import matplotlib.pyplot as plt 26 | %matplotlib inline 27 | import numpy as np 28 | import scipy.linalg as la 29 | 30 | from quantecon import Kalman 31 | from quantecon import LinearStateSpace 32 | from scipy.stats import norm 33 | np.set_printoptions(linewidth=120, precision=4, suppress=True) 34 | 35 | 36 | This lecture uses the Kalman filter to reformulate John F. Muth’s first 37 | paper :cite:`Muth1960` about rational expectations. 38 | 39 | Muth used *classical* prediction methods to reverse engineer a 40 | stochastic process that renders optimal Milton Friedman’s :cite:`Friedman1956` “adaptive 41 | expectations” scheme. 42 | 43 | Friedman (1956) and Muth (1960) 44 | =============================== 45 | 46 | Milton Friedman :cite:`Friedman1956` (1956) posited that 47 | consumer’s forecast their future disposable income with the adaptive 48 | expectations scheme 49 | 50 | .. math:: 51 | :label: expectations 52 | 53 | y_{t+i,t}^* = K \sum_{j=0}^\infty (1 - K)^j y_{t-j} 54 | 55 | where :math:`K \in (0,1)` and :math:`y_{t+i,t}^*` is a forecast of 56 | future :math:`y` over horizon :math:`i`. 57 | 58 | Milton Friedman justified the **exponential smoothing** forecasting 59 | scheme :eq:`expectations` informally, noting that it seemed a plausible way to use 60 | past income to forecast future income. 61 | 62 | In his first paper about rational expectations, John F. Muth :cite:`Muth1960` 63 | reverse-engineered a univariate stochastic process 64 | :math:`\{y_t\}_{t=- \infty}^\infty` for which Milton Friedman’s adaptive 65 | expectations scheme gives linear least forecasts of :math:`y_{t+j}` for 66 | any horizon :math:`i`. 67 | 68 | Muth sought a setting and a sense in which Friedman’s forecasting scheme 69 | is optimal. 70 | 71 | That is, Muth asked for what optimal forecasting **question** is Milton 72 | Friedman’s adaptive expectation scheme the **answer**. 73 | 74 | Muth (1960) used classical prediction methods based on lag-operators and 75 | :math:`z`-transforms to find the answer to his question. 76 | 77 | Please see lectures :doc:`Classical Control with Linear Algebra` and 78 | :doc:`Classical Filtering and Prediction with Linear Algebra` for an introduction to the classical 79 | tools that Muth used. 80 | 81 | 82 | Rather than using those classical tools, in this lecture we apply the 83 | Kalman filter to express the heart of Muth’s analysis concisely. 84 | 85 | The lecture `First Look at Kalman Filter `__ describes the Kalman filter. 86 | 87 | We'll use limiting versions of the Kalman filter corresponding to what are called **stationary values** in that lecture. 88 | 89 | A Process for Which Adaptive Expectations are Optimal 90 | ====================================================== 91 | 92 | Suppose that an observable :math:`y_t` is the sum of an unobserved 93 | random walk :math:`x_t` and an IID shock :math:`\epsilon_{2,t}`: 94 | 95 | .. math:: 96 | :label: state-space 97 | 98 | \begin{aligned} x_{t+1} & = x_t + \sigma_x \epsilon_{1,t+1} \cr 99 | y_t & = x_t + \sigma_y \epsilon_{2,t} \end{aligned} 100 | 101 | where 102 | 103 | .. math:: \begin{bmatrix} \epsilon_{1,t+1} \cr \epsilon_{2,t} \end{bmatrix} \sim {\mathcal N} (0, I) 104 | 105 | is an IID process. 106 | 107 | **Note:** A property of the state-space representation :eq:`state-space` is that in 108 | general neither :math:`\epsilon_{1,t}` nor :math:`\epsilon_{2,t}` is in 109 | the space spanned by square-summable linear combinations of 110 | :math:`y_t, y_{t-1}, \ldots`. 111 | 112 | In general 113 | :math:`\begin{bmatrix} \epsilon_{1,t} \cr \epsilon_{2t} \end{bmatrix}` 114 | has more information about future :math:`y_{t+j}`\ ’s than is contained 115 | in :math:`y_t, y_{t-1}, \ldots`. 116 | 117 | We can use the asymptotic or stationary values of the Kalman gain and 118 | the one-step-ahead conditional state covariance matrix to compute a 119 | time-invariant *innovations representation* 120 | 121 | .. math:: 122 | :label: innovations 123 | 124 | \begin{aligned} \hat x_{t+1} & = \hat x_t + K a_t \cr 125 | y_t & = \hat x_t + a_t \end{aligned} 126 | 127 | where :math:`\hat x_t = E [x_t | y_{t-1}, y_{t-2}, \ldots ]` and 128 | :math:`a_t = y_t - E[y_t |y_{t-1}, y_{t-2}, \ldots ]`. 129 | 130 | **Note:** A key property about an *innovations representation* is that 131 | :math:`a_t` is in the space spanned by square summable linear 132 | combinations of :math:`y_t, y_{t-1}, \ldots`. 133 | 134 | For more ramifications of this property, see the lectures :doc:`Shock Non-Invertibility` and 135 | :doc:`Recursive Models of Dynamic Linear Economies `. 136 | 137 | Later we’ll stack these state-space systems :eq:`state-space` and :eq:`innovations` to display some 138 | classic findings of Muth. 139 | 140 | But first, let’s create an instance of the state-space system :eq:`state-space` then 141 | apply the quantecon ``Kalman`` class, then uses it to construct the associated "innovations representation" 142 | 143 | .. code-block:: python3 144 | 145 | # Make some parameter choices 146 | # sigx/sigy are state noise std err and measurement noise std err 147 | μ_0, σ_x, σ_y = 10, 1, 5 148 | 149 | # Create a LinearStateSpace object 150 | A, C, G, H = 1, σ_x, 1, σ_y 151 | ss = LinearStateSpace(A, C, G, H, mu_0=μ_0) 152 | 153 | # Set prior and initialize the Kalman type 154 | x_hat_0, Σ_0 = 10, 1 155 | kmuth = Kalman(ss, x_hat_0, Σ_0) 156 | 157 | # Computes stationary values which we need for the innovation 158 | # representation 159 | S1, K1 = kmuth.stationary_values() 160 | 161 | # Form innovation representation state-space 162 | Ak, Ck, Gk, Hk = A, K1, G, 1 163 | 164 | ssk = LinearStateSpace(Ak, Ck, Gk, Hk, mu_0=x_hat_0) 165 | 166 | Some Useful State-Space Math 167 | ============================= 168 | 169 | Now we want to map the time-invariant innovations representation :eq:`innovations` and 170 | the original state-space system :eq:`state-space` into a convenient form for deducing 171 | the impulse responses from the original shocks to the :math:`x_t` and 172 | :math:`\hat x_t`. 173 | 174 | Putting both of these representations into a single state-space system 175 | is yet another application of the insight that “finding the state is an 176 | art”. 177 | 178 | We’ll define a state vector and appropriate state-space matrices that 179 | allow us to represent both systems in one fell swoop. 180 | 181 | Note that 182 | 183 | .. math:: a_t = x_t + \sigma_y \epsilon_{2,t} - \hat x_t 184 | 185 | so that 186 | 187 | .. math:: 188 | 189 | \begin{aligned} \hat x_{t+1} & = \hat x_t + K (x_t + \sigma_y \epsilon_{2,t} - \hat x_t) \cr 190 | & = (1-K) \hat x_t + K x_t + K \sigma_y \epsilon_{2,t} \end{aligned} 191 | 192 | The stacked system 193 | 194 | .. math:: 195 | 196 | \begin{bmatrix} x_{t+1} \cr \hat x_{t+1} \cr \epsilon_{2,t+1} \end{bmatrix} = 197 | \begin{bmatrix} 1 & 0 & 0 \cr K & (1-K) & K \sigma_y \cr 0 & 0 & 0 \end{bmatrix} 198 | \begin{bmatrix} x_{t} \cr \hat x_t \cr \epsilon_{2,t} \end{bmatrix}+ 199 | \begin{bmatrix} \sigma_x & 0 \cr 0 & 0 \cr 0 & 1 \end{bmatrix} 200 | \begin{bmatrix} \epsilon_{1,t+1} \cr \epsilon_{2,t+1} \end{bmatrix} 201 | 202 | .. math:: 203 | 204 | \begin{bmatrix} y_t \cr a_t \end{bmatrix} = \begin{bmatrix} 1 & 0 & \sigma_y \cr 205 | 1 & -1 & \sigma_y \end{bmatrix} \begin{bmatrix} x_{t} \cr \hat x_t \cr \epsilon_{2,t} \end{bmatrix} 206 | 207 | is a state-space system that tells us how the shocks 208 | :math:`\begin{bmatrix} \epsilon_{1,t+1} \cr \epsilon_{2,t+1} \end{bmatrix}` 209 | affect states :math:`\hat x_{t+1}, x_t`, the observable :math:`y_t`, and 210 | the innovation :math:`a_t`. 211 | 212 | With this tool at our disposal, let’s form the composite system and 213 | simulate it 214 | 215 | .. code-block:: python3 216 | 217 | # Create grand state-space for y_t, a_t as observed vars -- Use 218 | # stacking trick above 219 | Af = np.array([[ 1, 0, 0], 220 | [K1, 1 - K1, K1 * σ_y], 221 | [ 0, 0, 0]]) 222 | Cf = np.array([[σ_x, 0], 223 | [ 0, K1 * σ_y], 224 | [ 0, 1]]) 225 | Gf = np.array([[1, 0, σ_y], 226 | [1, -1, σ_y]]) 227 | 228 | μ_true, μ_prior = 10, 10 229 | μ_f = np.array([μ_true, μ_prior, 0]).reshape(3, 1) 230 | 231 | # Create the state-space 232 | ssf = LinearStateSpace(Af, Cf, Gf, mu_0=μ_f) 233 | 234 | # Draw observations of y from the state-space model 235 | N = 50 236 | xf, yf = ssf.simulate(N) 237 | 238 | print(f"Kalman gain = {K1}") 239 | print(f"Conditional variance = {S1}") 240 | 241 | 242 | Now that we have simulated our joint system, we have :math:`x_t`, 243 | :math:`\hat{x_t}`, and :math:`y_t`. 244 | 245 | We can now investigate how these 246 | variables are related by plotting some key objects. 247 | 248 | Estimates of Unobservables 249 | =========================== 250 | 251 | First, let’s plot the hidden state :math:`x_t` and the filtered version 252 | :math:`\hat x_t` that is linear-least squares projection of :math:`x_t` 253 | on the history :math:`y_{t-1}, y_{t-2}, \ldots` 254 | 255 | .. code-block:: python3 256 | 257 | fig, ax = plt.subplots() 258 | ax.plot(xf[0, :], label="$x_t$") 259 | ax.plot(xf[1, :], label="Filtered $x_t$") 260 | ax.legend() 261 | ax.set_xlabel("Time") 262 | ax.set_title(r"$x$ vs $\hat{x}$") 263 | plt.show() 264 | 265 | 266 | Note how :math:`x_t` and :math:`\hat{x_t}` differ. 267 | 268 | For Friedman, :math:`\hat x_t` and not :math:`x_t` is the consumer’s 269 | idea about her/his *permanent income*. 270 | 271 | Relation between Unobservable and Observable 272 | ============================================= 273 | 274 | Now let’s plot :math:`x_t` and :math:`y_t`. 275 | 276 | Recall that :math:`y_t` is just :math:`x_t` plus white noise 277 | 278 | .. code-block:: python3 279 | 280 | fig, ax = plt.subplots() 281 | ax.plot(yf[0, :], label="y") 282 | ax.plot(xf[0, :], label="x") 283 | ax.legend() 284 | ax.set_title(r"$x$ and $y$") 285 | ax.set_xlabel("Time") 286 | plt.show() 287 | 288 | We see above that :math:`y` seems to look like white noise around the 289 | values of :math:`x`. 290 | 291 | Innovations 292 | ----------- 293 | 294 | Recall that we wrote down the innovation representation that depended on 295 | :math:`a_t`. We now plot the innovations :math:`\{a_t\}`: 296 | 297 | .. code-block:: python3 298 | 299 | fig, ax = plt.subplots() 300 | ax.plot(yf[1, :], label="a") 301 | ax.legend() 302 | ax.set_title(r"Innovation $a_t$") 303 | ax.set_xlabel("Time") 304 | plt.show() 305 | 306 | 307 | MA and AR Representations 308 | =========================== 309 | 310 | Now we shall extract from the ``Kalman`` instance ``kmuth`` coefficients of 311 | 312 | - a fundamental moving average representation that represents 313 | :math:`y_t` as a one-sided moving sum of current and past 314 | :math:`a_t`\ s that are square summable linear combinations of :math:`y_t, y_{t-1}, \ldots`. 315 | 316 | - a univariate autoregression representation that depicts the 317 | coefficients in a linear least square projection of :math:`y_t` on 318 | the semi-infinite history :math:`y_{t-1}, y_{t-2}, \ldots`. 319 | 320 | Then we’ll plot each of them 321 | 322 | .. code-block:: python3 323 | 324 | # Kalman Methods for MA and VAR 325 | coefs_ma = kmuth.stationary_coefficients(5, "ma") 326 | coefs_var = kmuth.stationary_coefficients(5, "var") 327 | 328 | # Coefficients come in a list of arrays, but we 329 | # want to plot them and so need to stack into an array 330 | coefs_ma_array = np.vstack(coefs_ma) 331 | coefs_var_array = np.vstack(coefs_var) 332 | 333 | fig, ax = plt.subplots(2) 334 | ax[0].plot(coefs_ma_array, label="MA") 335 | ax[0].legend() 336 | ax[1].plot(coefs_var_array, label="VAR") 337 | ax[1].legend() 338 | 339 | plt.show() 340 | 341 | 342 | The **moving average** coefficients in the top panel show tell-tale 343 | signs of :math:`y_t` being a process whose first difference is a first-order 344 | autoregression. 345 | 346 | The **autoregressive coefficients** decline geometrically with decay 347 | rate :math:`(1-K)`. 348 | 349 | These are exactly the target outcomes that Muth (1960) aimed to reverse 350 | engineer 351 | 352 | .. code-block:: python3 353 | 354 | print(f'decay parameter 1 - K1 = {1 - K1}') 355 | --------------------------------------------------------------------------------