├── .gitignore ├── README.md ├── Project.toml ├── troubleshooting.ipynb ├── intro.ipynb ├── status.ipynb ├── multi_agent_models ├── schelling.ipynb └── aiyagari.ipynb ├── more_julia ├── general_packages.ipynb └── data_statistical_packages.ipynb ├── about_lectures.ipynb ├── introduction_dynamics └── short_path.ipynb ├── zreferences.ipynb └── dynamic_programming ├── egm_policy_iter.ipynb ├── mccall_model_with_separation.ipynb ├── jv.ipynb └── career.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | **/.ipynb_checkpoints 3 | .vscode/settings.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lecture-julia.notebooks 2 | 3 | [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/QuantEcon/lecture-julia.notebooks/main) 4 | 5 | Notebooks for https://julia.quantecon.org 6 | 7 | - [Lecture source](https://github.com/QuantEcon/lecture-julia.myst) 8 | - [README source code](https://github.com/QuantEcon/lecture-julia.myst/blob/main/_notebook_repo/README.md) 9 | -------------------------------------------------------------------------------- /Project.toml: -------------------------------------------------------------------------------- 1 | name = "quantecon-notebooks-julia" 2 | version = "0.10.0" 3 | authors = ["quantecon "] 4 | 5 | [deps] 6 | Arpack = "7d9fca2a-8960-54d3-9f78-7d1dccf2cb97" 7 | BandedMatrices = "aae01518-5342-5314-be14-df237901396f" 8 | BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" 9 | ControlSystems = "a6e380b2-a6ca-5380-bf3e-84a91bcd477e" 10 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 11 | DataInterpolations = "82cc6244-b520-54b8-b5a6-8a565e85f1d0" 12 | Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" 13 | Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" 14 | EnzymeTestUtils = "12d8515a-0907-448a-8884-5fe00fdf1c5a" 15 | FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838" 16 | FixedPointAcceleration = "817d07cb-a79a-5c30-9a31-890123675176" 17 | ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" 18 | Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" 19 | IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895" 20 | Integrals = "de52edbc-65ea-441a-8357-d3a637375a31" 21 | Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" 22 | IterativeSolvers = "42fd0dbc-a981-5370-80f2-aaf504508153" 23 | KernelDensity = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b" 24 | LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" 25 | Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" 26 | LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 27 | LinearMaps = "7a12625a-238d-50fd-b39a-03d52299707e" 28 | LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" 29 | LoopVectorization = "bdcacae8-1622-11e9-2a5c-532679323890" 30 | MatrixEquations = "99c1a7ee-ab34-5fd5-8076-27c950a045f4" 31 | NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" 32 | NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" 33 | Optim = "429524aa-4258-5aef-a3af-852621145aeb" 34 | Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba" 35 | OptimizationOptimJL = "36348300-93cb-4f02-beb5-3c3902f8871e" 36 | OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" 37 | Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" 38 | Polynomials = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" 39 | Preconditioners = "af69fa37-3177-5a40-98ee-561f696e4fcd" 40 | QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" 41 | QuantEcon = "fcd29c91-0bd7-5a09-975d-7ac3f643a60c" 42 | Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 43 | Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665" 44 | SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" 45 | SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" 46 | StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" 47 | Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 48 | StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" 49 | StochasticDiffEq = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0" 50 | Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" 51 | Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 52 | -------------------------------------------------------------------------------- /troubleshooting.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "29a2ec01", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "4ea8a2d8", 15 | "metadata": {}, 16 | "source": [ 17 | "# Troubleshooting" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "id": "efe46c02", 23 | "metadata": {}, 24 | "source": [ 25 | "## Contents\n", 26 | "\n", 27 | "- [Troubleshooting](#Troubleshooting) \n", 28 | " - [Resetting your Lectures](#Resetting-your-Lectures) \n", 29 | " - [Fixing Your Local Environment](#Fixing-Your-Local-Environment) \n", 30 | " - [Upgrading Julia](#Upgrading-Julia) \n", 31 | " - [Reporting an Issue](#Reporting-an-Issue) " 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "id": "b8f5a893", 37 | "metadata": {}, 38 | "source": [ 39 | "This troubleshooting page is to help ensure you software environment is setup correctly\n", 40 | "to run this lecture set locally on your machine." 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "id": "10afb7d8", 46 | "metadata": {}, 47 | "source": [ 48 | "## Resetting your Lectures\n", 49 | "\n", 50 | "Using VS Code, you can easily revert back individual lectures, all of the lectures, or get updated versions of the lecture notes.\n", 51 | "\n", 52 | "See the lecture on [setting up your environment](https://julia.quantecon.org/getting_started_julia/getting_started.html#reset-notebooks) for more.\n", 53 | "\n", 54 | "If the `Project.toml` or `Manifest.toml` files are modified, then you may want to redo the [instantiation](https://julia.quantecon.org/getting_started_julia/getting_started.html#install-packages) step to ensure you have the correct versions.\n", 55 | "\n", 56 | "\n", 57 | "" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "id": "e9922f68", 63 | "metadata": {}, 64 | "source": [ 65 | "## Fixing Your Local Environment\n", 66 | "\n", 67 | "If packages are misbehaving, you may want to simply [reset the lectures](https://julia.quantecon.org/getting_started_julia/getting_started.html#reset-notebooks) or at least the `Project.toml` and `Manifest.toml` files from the lecture notes, and then redo the [instantiation](https://julia.quantecon.org/getting_started_julia/getting_started.html#install-packages) step This will fix nearly every problem.\n", 68 | "\n", 69 | "However, if you are still having issues you could delete the entire `.julia` directory for your users, and then redo the installation of packages as well as `] add IJulia`. It is fast for recent versions of Julia.\n", 70 | "\n", 71 | "The directory is located in your user directory (e.g. `~/.julia` on MacOS and Linux, and `C:\\Users\\YOURUSERNAME\\.julia` on Windows) or you can find this directory by running `DEPOT_PATH[1]` in a Julia REPL." 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "id": "c129a682", 77 | "metadata": {}, 78 | "source": [ 79 | "## Upgrading Julia\n", 80 | "\n", 81 | "You should be able to upgrade Julia by simply\n", 82 | "\n", 83 | "- Installing the latest release from the [Julia website](https://julialang.org/downloads/). \n", 84 | "- Uninstalling your old release (so that the VS Code extension only uses the newest version) \n", 85 | "- And, finally, you will need to redo the `] add IJulia` [installation step](https://julia.quantecon.org/getting_started_julia/getting_started.html#intro-repl) to ensure that Jupyter knows how to find the new version. \n", 86 | "\n", 87 | "\n", 88 | "While upgrading Julia will typically work with the notebooks, there may be upgrades where a particular lecture has problems. Make sure that you have [updated your notebooks](https://julia.quantecon.org/getting_started_julia/getting_started.html#reset-notebooks) in case bug fixes were made, and post an issue to the [GitHub source for these lectures](https://github.com/QuantEcon/lecture-julia.myst/issues)." 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "id": "6cc8764f", 94 | "metadata": {}, 95 | "source": [ 96 | "## Reporting an Issue\n", 97 | "\n", 98 | "One way to give feedback is to raise an issue through our [issue tracker](https://github.com/QuantEcon/lecture-julia.myst/issues).\n", 99 | "\n", 100 | "Please be as specific as possible. Tell us where the problem is and as much\n", 101 | "detail about your local set up as you can provide.\n", 102 | "\n", 103 | "Another feedback option is to use our [discourse forum](https://discourse.quantecon.org/).\n", 104 | "\n", 105 | "Finally, you can provide direct feedback to [contact@quantecon.org](mailto:contact@quantecon.org)" 106 | ] 107 | } 108 | ], 109 | "metadata": { 110 | "date": 1766028222.383215, 111 | "filename": "troubleshooting.md", 112 | "kernelspec": { 113 | "display_name": "Julia", 114 | "language": "julia", 115 | "name": "julia-1.12" 116 | }, 117 | "title": "Troubleshooting" 118 | }, 119 | "nbformat": 4, 120 | "nbformat_minor": 5 121 | } -------------------------------------------------------------------------------- /intro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "f4f86371", 6 | "metadata": {}, 7 | "source": [ 8 | "# Quantitative Economics with Julia\n", 9 | "\n", 10 | "This website presents a set of lectures on quantitative economic modeling." 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "613a82ed", 16 | "metadata": {}, 17 | "source": [ 18 | "# Getting Started with Julia\n", 19 | "\n", 20 | "- [Setting up Your Julia Environment](https://julia.quantecon.org/getting_started_julia/getting_started.html)\n", 21 | "- [Introductory Examples](https://julia.quantecon.org/getting_started_julia/julia_by_example.html)\n", 22 | "- [Julia Essentials](https://julia.quantecon.org/getting_started_julia/julia_essentials.html)\n", 23 | "- [Arrays, Tuples, Ranges, and Other Fundamental Types](https://julia.quantecon.org/getting_started_julia/fundamental_types.html)\n", 24 | "- [Introduction to Types and Generic Programming](https://julia.quantecon.org/getting_started_julia/introduction_to_types.html)" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "id": "41ee370e", 30 | "metadata": {}, 31 | "source": [ 32 | "# Package Ecosystem\n", 33 | "\n", 34 | "- [Generic Programming](https://julia.quantecon.org/more_julia/generic_programming.html)\n", 35 | "- [Automatic Differentiation](https://julia.quantecon.org/more_julia/auto_differentiation.html)\n", 36 | "- [Quadrature and Interpolation](https://julia.quantecon.org/more_julia/quadrature_interpolation.html)\n", 37 | "- [General, Data, and Statistics Packages](https://julia.quantecon.org/more_julia/data_statistical_packages.html)\n", 38 | "- [Optimization and Nonlinear Solvers](https://julia.quantecon.org/more_julia/optimization_solver_packages.html)" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "id": "0954b92c", 44 | "metadata": {}, 45 | "source": [ 46 | "# Software Engineering\n", 47 | "\n", 48 | "- [Visual Studio Code and Other Tools](https://julia.quantecon.org/software_engineering/tools_editors.html)\n", 49 | "- [GitHub, Version Control and Collaboration](https://julia.quantecon.org/software_engineering/version_control.html)\n", 50 | "- [Packages, Testing, and Continuous Integration](https://julia.quantecon.org/software_engineering/testing.html)\n", 51 | "- [The Need for Speed](https://julia.quantecon.org/software_engineering/need_for_speed.html)" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "id": "6723f6ee", 57 | "metadata": {}, 58 | "source": [ 59 | "# Tools and Techniques\n", 60 | "\n", 61 | "- [Geometric Series for Elementary Economics](https://julia.quantecon.org/tools_and_techniques/geom_series.html)\n", 62 | "- [Linear Algebra](https://julia.quantecon.org/tools_and_techniques/linear_algebra.html)\n", 63 | "- [Orthogonal Projections and Their Applications](https://julia.quantecon.org/tools_and_techniques/orth_proj.html)\n", 64 | "- [LLN and CLT](https://julia.quantecon.org/tools_and_techniques/lln_clt.html)\n", 65 | "- [Continuous State Markov Chains](https://julia.quantecon.org/tools_and_techniques/stationary_densities.html)\n", 66 | "- [Numerical Linear Algebra and Factorizations](https://julia.quantecon.org/tools_and_techniques/numerical_linear_algebra.html)\n", 67 | "- [Krylov Methods and Matrix Conditioning](https://julia.quantecon.org/tools_and_techniques/iterative_methods_sparsity.html)\n", 68 | "- [Differentiating Models of Economic Dynamics](https://julia.quantecon.org/tools_and_techniques/differentiable_dynamics.html)" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "id": "1cd7c785", 74 | "metadata": {}, 75 | "source": [ 76 | "# Introduction to Dynamics\n", 77 | "\n", 78 | "- [Dynamics in One Dimension](https://julia.quantecon.org/introduction_dynamics/scalar_dynam.html)\n", 79 | "- [AR1 Processes](https://julia.quantecon.org/introduction_dynamics/ar1_processes.html)\n", 80 | "- [Finite Markov Chains](https://julia.quantecon.org/introduction_dynamics/finite_markov.html)\n", 81 | "- [Linear State Space Models](https://julia.quantecon.org/introduction_dynamics/linear_models.html)\n", 82 | "- [Wealth Distribution Dynamics](https://julia.quantecon.org/introduction_dynamics/wealth_dynamics.html)\n", 83 | "- [A First Look at the Kalman Filter](https://julia.quantecon.org/introduction_dynamics/kalman.html)\n", 84 | "- [Shortest Paths](https://julia.quantecon.org/introduction_dynamics/short_path.html)" 85 | ] 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "id": "8bb8288b", 90 | "metadata": {}, 91 | "source": [ 92 | "# Dynamic Programming\n", 93 | "\n", 94 | "- [Job Search I: The McCall Search Model](https://julia.quantecon.org/dynamic_programming/mccall_model.html)\n", 95 | "- [Job Search II: Search and Separation](https://julia.quantecon.org/dynamic_programming/mccall_model_with_separation.html)\n", 96 | "- [A Problem that Stumped Milton Friedman](https://julia.quantecon.org/dynamic_programming/wald_friedman.html)\n", 97 | "- [Job Search III: Search with Learning](https://julia.quantecon.org/dynamic_programming/odu.html)\n", 98 | "- [Job Search IV: Modeling Career Choice](https://julia.quantecon.org/dynamic_programming/career.html)\n", 99 | "- [Job Search V: On-the-Job Search](https://julia.quantecon.org/dynamic_programming/jv.html)\n", 100 | "- [Optimal Growth I: The Stochastic Optimal Growth Model](https://julia.quantecon.org/dynamic_programming/optgrowth.html)\n", 101 | "- [Optimal Growth II: Time Iteration](https://julia.quantecon.org/dynamic_programming/coleman_policy_iter.html)\n", 102 | "- [Optimal Growth III: The Endogenous Grid Method](https://julia.quantecon.org/dynamic_programming/egm_policy_iter.html)\n", 103 | "- [LQ Dynamic Programming Problems](https://julia.quantecon.org/dynamic_programming/lqcontrol.html)\n", 104 | "- [Optimal Savings I: The Permanent Income Model](https://julia.quantecon.org/dynamic_programming/perm_income.html)\n", 105 | "- [Optimal Savings II: LQ Techniques](https://julia.quantecon.org/dynamic_programming/perm_income_cons.html)\n", 106 | "- [Consumption and Tax Smoothing with Complete and Incomplete Markets](https://julia.quantecon.org/dynamic_programming/smoothing.html)\n", 107 | "- [Optimal Savings III: Occasionally Binding Constraints](https://julia.quantecon.org/dynamic_programming/ifp.html)\n", 108 | "- [Robustness](https://julia.quantecon.org/dynamic_programming/robustness.html)\n", 109 | "- [Discrete State Dynamic Programming](https://julia.quantecon.org/dynamic_programming/discrete_dp.html)" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "id": "2626e665", 115 | "metadata": {}, 116 | "source": [ 117 | "# Modeling in Continuous Time\n", 118 | "\n", 119 | "- [Modeling COVID 19 with Differential Equations](https://julia.quantecon.org/continuous_time/seir_model.html)\n", 120 | "- [Modeling Shocks in COVID 19 with Stochastic Differential Equations](https://julia.quantecon.org/continuous_time/covid_sde.html)" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "id": "cd19d72a", 126 | "metadata": {}, 127 | "source": [ 128 | "# Multiple Agent Models\n", 129 | "\n", 130 | "- [Schelling’s Segregation Model](https://julia.quantecon.org/multi_agent_models/schelling.html)\n", 131 | "- [A Lake Model of Employment and Unemployment](https://julia.quantecon.org/multi_agent_models/lake_model.html)\n", 132 | "- [Rational Expectations Equilibrium](https://julia.quantecon.org/multi_agent_models/rational_expectations.html)\n", 133 | "- [Markov Perfect Equilibrium](https://julia.quantecon.org/multi_agent_models/markov_perf.html)\n", 134 | "- [Asset Pricing I: Finite State Models](https://julia.quantecon.org/multi_agent_models/markov_asset.html)\n", 135 | "- [Asset Pricing II: The Lucas Asset Pricing Model](https://julia.quantecon.org/multi_agent_models/lucas_model.html)\n", 136 | "- [Asset Pricing III: Incomplete Markets](https://julia.quantecon.org/multi_agent_models/harrison_kreps.html)\n", 137 | "- [Uncertainty Traps](https://julia.quantecon.org/multi_agent_models/uncertainty_traps.html)\n", 138 | "- [The Aiyagari Model](https://julia.quantecon.org/multi_agent_models/aiyagari.html)\n", 139 | "- [Default Risk and Income Fluctuations](https://julia.quantecon.org/multi_agent_models/arellano.html)\n", 140 | "- [Globalization and Cycles](https://julia.quantecon.org/multi_agent_models/matsuyama.html)" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "id": "6efb5dee", 146 | "metadata": {}, 147 | "source": [ 148 | "# Other\n", 149 | "\n", 150 | "- [About these Lectures](https://julia.quantecon.org/about_lectures.html)\n", 151 | "- [Troubleshooting](https://julia.quantecon.org/troubleshooting.html)\n", 152 | "- [References](https://julia.quantecon.org/zreferences.html)\n", 153 | "- [Execution Statistics](https://julia.quantecon.org/status.html)" 154 | ] 155 | } 156 | ], 157 | "metadata": { 158 | "date": 1766028220.0014033, 159 | "filename": "intro.md", 160 | "kernelspec": { 161 | "display_name": "Julia", 162 | "language": "julia", 163 | "name": "julia-1.12" 164 | }, 165 | "title": "Quantitative Economics with Julia" 166 | }, 167 | "nbformat": 4, 168 | "nbformat_minor": 5 169 | } -------------------------------------------------------------------------------- /status.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "d74d60d3", 6 | "metadata": {}, 7 | "source": [ 8 | "# Execution Statistics\n", 9 | "\n", 10 | "This table contains the latest execution statistics.\n", 11 | "\n", 12 | "[](https://julia.quantecon.org/about_lectures.html)[](https://julia.quantecon.org/continuous_time/covid_sde.html)[](https://julia.quantecon.org/continuous_time/seir_model.html)[](https://julia.quantecon.org/dynamic_programming/career.html)[](https://julia.quantecon.org/dynamic_programming/coleman_policy_iter.html)[](https://julia.quantecon.org/dynamic_programming/discrete_dp.html)[](https://julia.quantecon.org/dynamic_programming/egm_policy_iter.html)[](https://julia.quantecon.org/dynamic_programming/ifp.html)[](https://julia.quantecon.org/dynamic_programming/jv.html)[](https://julia.quantecon.org/dynamic_programming/lqcontrol.html)[](https://julia.quantecon.org/dynamic_programming/mccall_model.html)[](https://julia.quantecon.org/dynamic_programming/mccall_model_with_separation.html)[](https://julia.quantecon.org/dynamic_programming/odu.html)[](https://julia.quantecon.org/dynamic_programming/optgrowth.html)[](https://julia.quantecon.org/dynamic_programming/perm_income.html)[](https://julia.quantecon.org/dynamic_programming/perm_income_cons.html)[](https://julia.quantecon.org/dynamic_programming/robustness.html)[](https://julia.quantecon.org/dynamic_programming/smoothing.html)[](https://julia.quantecon.org/dynamic_programming/wald_friedman.html)[](https://julia.quantecon.org/getting_started_julia/fundamental_types.html)[](https://julia.quantecon.org/getting_started_julia/getting_started.html)[](https://julia.quantecon.org/getting_started_julia/introduction_to_types.html)[](https://julia.quantecon.org/getting_started_julia/julia_by_example.html)[](https://julia.quantecon.org/getting_started_julia/julia_essentials.html)[](https://julia.quantecon.org/intro.html)[](https://julia.quantecon.org/introduction_dynamics/ar1_processes.html)[](https://julia.quantecon.org/introduction_dynamics/finite_markov.html)[](https://julia.quantecon.org/introduction_dynamics/kalman.html)[](https://julia.quantecon.org/introduction_dynamics/linear_models.html)[](https://julia.quantecon.org/introduction_dynamics/scalar_dynam.html)[](https://julia.quantecon.org/introduction_dynamics/short_path.html)[](https://julia.quantecon.org/introduction_dynamics/wealth_dynamics.html)[](https://julia.quantecon.org/more_julia/auto_differentiation.html)[](https://julia.quantecon.org/more_julia/data_statistical_packages.html)[](https://julia.quantecon.org/more_julia/generic_programming.html)[](https://julia.quantecon.org/more_julia/optimization_solver_packages.html)[](https://julia.quantecon.org/more_julia/quadrature_interpolation.html)[](https://julia.quantecon.org/multi_agent_models/aiyagari.html)[](https://julia.quantecon.org/multi_agent_models/arellano.html)[](https://julia.quantecon.org/multi_agent_models/harrison_kreps.html)[](https://julia.quantecon.org/multi_agent_models/lake_model.html)[](https://julia.quantecon.org/multi_agent_models/lucas_model.html)[](https://julia.quantecon.org/multi_agent_models/markov_asset.html)[](https://julia.quantecon.org/multi_agent_models/markov_perf.html)[](https://julia.quantecon.org/multi_agent_models/matsuyama.html)[](https://julia.quantecon.org/multi_agent_models/rational_expectations.html)[](https://julia.quantecon.org/multi_agent_models/schelling.html)[](https://julia.quantecon.org/multi_agent_models/uncertainty_traps.html)[](https://julia.quantecon.org/software_engineering/need_for_speed.html)[](https://julia.quantecon.org/software_engineering/testing.html)[](https://julia.quantecon.org/software_engineering/tools_editors.html)[](https://julia.quantecon.org/software_engineering/version_control.html)[](https://julia.quantecon.org/.html)[](https://julia.quantecon.org/tools_and_techniques/differentiable_dynamics.html)[](https://julia.quantecon.org/tools_and_techniques/geom_series.html)[](https://julia.quantecon.org/tools_and_techniques/iterative_methods_sparsity.html)[](https://julia.quantecon.org/tools_and_techniques/linear_algebra.html)[](https://julia.quantecon.org/tools_and_techniques/lln_clt.html)[](https://julia.quantecon.org/tools_and_techniques/numerical_linear_algebra.html)[](https://julia.quantecon.org/tools_and_techniques/orth_proj.html)[](https://julia.quantecon.org/tools_and_techniques/stationary_densities.html)[](https://julia.quantecon.org/troubleshooting.html)[](https://julia.quantecon.org/zreferences.html)|Document|Modified|Method|Run Time (s)|Status|\n", 13 | "|:------------------:|:------------------:|:------------------:|:------------------:|:------------------:|\n", 14 | "|about_lectures|2025-12-18 02:07|cache|1.08|✅|\n", 15 | "|continuous_time/covid_sde|2025-12-18 02:10|cache|175.87|✅|\n", 16 | "|continuous_time/seir_model|2025-12-18 02:10|cache|23.9|✅|\n", 17 | "|dynamic_programming/career|2025-12-18 02:11|cache|23.38|✅|\n", 18 | "|dynamic_programming/coleman_policy_iter|2025-12-18 02:12|cache|45.84|✅|\n", 19 | "|dynamic_programming/discrete_dp|2025-12-18 02:13|cache|63.97|✅|\n", 20 | "|dynamic_programming/egm_policy_iter|2025-12-18 02:13|cache|45.53|✅|\n", 21 | "|dynamic_programming/ifp|2025-12-18 02:14|cache|45.58|✅|\n", 22 | "|dynamic_programming/jv|2025-12-18 02:15|cache|34.0|✅|\n", 23 | "|dynamic_programming/lqcontrol|2025-12-18 02:15|cache|21.03|✅|\n", 24 | "|dynamic_programming/mccall_model|2025-12-18 02:16|cache|26.71|✅|\n", 25 | "|dynamic_programming/mccall_model_with_separation|2025-12-18 02:16|cache|17.57|✅|\n", 26 | "|dynamic_programming/odu|2025-12-18 02:17|cache|42.88|✅|\n", 27 | "|dynamic_programming/optgrowth|2025-12-18 02:17|cache|20.56|✅|\n", 28 | "|dynamic_programming/perm_income|2025-12-18 02:17|cache|9.02|✅|\n", 29 | "|dynamic_programming/perm_income_cons|2025-12-18 02:18|cache|25.26|✅|\n", 30 | "|dynamic_programming/robustness|2025-12-18 02:18|cache|23.52|✅|\n", 31 | "|dynamic_programming/smoothing|2025-12-18 02:18|cache|17.73|✅|\n", 32 | "|dynamic_programming/wald_friedman|2025-12-18 02:19|cache|33.07|✅|\n", 33 | "|getting_started_julia/fundamental_types|2025-12-18 02:19|cache|20.44|✅|\n", 34 | "|getting_started_julia/getting_started|2025-12-18 02:19|cache|6.96|✅|\n", 35 | "|getting_started_julia/introduction_to_types|2025-12-18 02:20|cache|24.62|✅|\n", 36 | "|getting_started_julia/julia_by_example|2025-12-18 02:20|cache|35.77|✅|\n", 37 | "|getting_started_julia/julia_essentials|2025-12-18 02:21|cache|30.78|✅|\n", 38 | "|intro|2025-12-18 02:21|cache|0.83|✅|\n", 39 | "|introduction_dynamics/ar1_processes|2025-12-18 02:21|cache|14.74|✅|\n", 40 | "|introduction_dynamics/finite_markov|2025-12-18 02:21|cache|22.8|✅|\n", 41 | "|introduction_dynamics/kalman|2025-12-18 02:22|cache|28.77|✅|\n", 42 | "|introduction_dynamics/linear_models|2025-12-18 02:22|cache|18.86|✅|\n", 43 | "|introduction_dynamics/scalar_dynam|2025-12-18 02:22|cache|11.43|✅|\n", 44 | "|introduction_dynamics/short_path|2025-12-18 02:22|cache|3.0|✅|\n", 45 | "|introduction_dynamics/wealth_dynamics|2025-12-18 02:24|cache|90.94|✅|\n", 46 | "|more_julia/auto_differentiation|2025-12-18 02:25|cache|65.94|✅|\n", 47 | "|more_julia/data_statistical_packages|2025-12-18 02:25|cache|11.25|✅|\n", 48 | "|more_julia/generic_programming|2025-12-18 02:26|cache|23.8|✅|\n", 49 | "|more_julia/optimization_solver_packages|2025-12-18 02:28|cache|123.0|✅|\n", 50 | "|more_julia/quadrature_interpolation|2025-12-18 02:28|cache|36.54|✅|\n", 51 | "|multi_agent_models/aiyagari|2025-12-18 02:29|cache|29.99|✅|\n", 52 | "|multi_agent_models/arellano|2025-12-18 02:29|cache|22.92|✅|\n", 53 | "|multi_agent_models/harrison_kreps|2025-12-18 02:29|cache|13.12|✅|\n", 54 | "|multi_agent_models/lake_model|2025-12-18 02:31|cache|85.46|✅|\n", 55 | "|multi_agent_models/lucas_model|2025-12-18 02:31|cache|17.71|✅|\n", 56 | "|multi_agent_models/markov_asset|2025-12-18 02:32|cache|23.89|✅|\n", 57 | "|multi_agent_models/markov_perf|2025-12-18 02:32|cache|28.73|✅|\n", 58 | "|multi_agent_models/matsuyama|2025-12-18 02:32|cache|13.07|✅|\n", 59 | "|multi_agent_models/rational_expectations|2025-12-18 02:33|cache|14.34|✅|\n", 60 | "|multi_agent_models/schelling|2025-12-18 02:33|cache|12.17|✅|\n", 61 | "|multi_agent_models/uncertainty_traps|2025-12-18 02:33|cache|14.55|✅|\n", 62 | "|software_engineering/need_for_speed|2025-12-18 02:35|cache|120.94|✅|\n", 63 | "|software_engineering/testing|2025-12-18 02:35|cache|3.62|✅|\n", 64 | "|software_engineering/tools_editors|2025-12-18 02:07|cache|1.08|✅|\n", 65 | "|software_engineering/version_control|2025-12-18 02:07|cache|1.08|✅|\n", 66 | "|status|2025-12-18 02:07|cache|1.08|✅|\n", 67 | "|tools_and_techniques/differentiable_dynamics|2025-12-18 02:38|cache|179.94|✅|\n", 68 | "|tools_and_techniques/geom_series|2025-12-18 02:39|cache|44.9|✅|\n", 69 | "|tools_and_techniques/iterative_methods_sparsity|2025-12-18 02:42|cache|164.58|✅|\n", 70 | "|tools_and_techniques/linear_algebra|2025-12-18 02:42|cache|24.44|✅|\n", 71 | "|tools_and_techniques/lln_clt|2025-12-18 02:43|cache|35.24|✅|\n", 72 | "|tools_and_techniques/numerical_linear_algebra|2025-12-18 02:45|cache|133.48|✅|\n", 73 | "|tools_and_techniques/orth_proj|2025-12-18 02:45|cache|4.86|✅|\n", 74 | "|tools_and_techniques/stationary_densities|2025-12-18 02:46|cache|55.47|✅|\n", 75 | "|troubleshooting|2025-12-18 02:07|cache|1.08|✅|\n", 76 | "|zreferences|2025-12-18 02:07|cache|1.08|✅|\n", 77 | "These lectures are built on `linux` instances through `github actions` so are\n", 78 | "executed using the following [hardware specifications](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-runners-and-hardware-resources)" 79 | ] 80 | } 81 | ], 82 | "metadata": { 83 | "date": 1766028221.786113, 84 | "filename": "status.md", 85 | "kernelspec": { 86 | "display_name": "Julia", 87 | "language": "julia", 88 | "name": "julia-1.12" 89 | }, 90 | "title": "Execution Statistics" 91 | }, 92 | "nbformat": 4, 93 | "nbformat_minor": 5 94 | } -------------------------------------------------------------------------------- /multi_agent_models/schelling.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "e06a4dbb", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "b24a4098", 15 | "metadata": {}, 16 | "source": [ 17 | "# Schelling’s Segregation Model\n", 18 | "\n", 19 | "\n", 20 | "" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "396e40e4", 26 | "metadata": {}, 27 | "source": [ 28 | "## Contents\n", 29 | "\n", 30 | "- [Schelling’s Segregation Model](#Schelling’s-Segregation-Model) \n", 31 | " - [Overview](#Overview) \n", 32 | " - [The Model](#The-Model) \n", 33 | " - [Results](#Results) \n", 34 | " - [Exercises](#Exercises) \n", 35 | " - [Solutions](#Solutions) " 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "id": "d5985f9d", 41 | "metadata": {}, 42 | "source": [ 43 | "## Overview\n", 44 | "\n", 45 | "In 1969, Thomas C. Schelling developed a simple but striking model of racial segregation [[Sch69](https://julia.quantecon.org/../zreferences.html#id127)].\n", 46 | "\n", 47 | "His model studies the dynamics of racially mixed neighborhoods.\n", 48 | "\n", 49 | "Like much of Schelling’s work, the model shows how local interactions can lead to surprising aggregate structure.\n", 50 | "\n", 51 | "In particular, it shows that relatively mild preference for neighbors of similar race can lead in aggregate to the collapse of mixed neighborhoods, and high levels of segregation.\n", 52 | "\n", 53 | "In recognition of this and other research, Schelling was awarded the 2005 Nobel Prize in Economic Sciences (joint with Robert Aumann).\n", 54 | "\n", 55 | "In this lecture we (in fact you) will build and run a version of Schelling’s model." 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "id": "9cd0fc4d", 61 | "metadata": {}, 62 | "source": [ 63 | "## The Model\n", 64 | "\n", 65 | "We will cover a variation of Schelling’s model that is easy to program and captures the main idea.\n", 66 | "\n", 67 | "Suppose we have two types of people: orange people and green people.\n", 68 | "\n", 69 | "For the purpose of this lecture, we will assume there are 250 of each type.\n", 70 | "\n", 71 | "These agents all live on a single unit square.\n", 72 | "\n", 73 | "The location of an agent is just a point $ (x, y) $, where $ 0 < x, y < 1 $." 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "id": "86d1e9de", 79 | "metadata": {}, 80 | "source": [ 81 | "### Preferences\n", 82 | "\n", 83 | "We will say that an agent is *happy* if half or more of her 10 nearest neighbors are of the same type.\n", 84 | "\n", 85 | "Here ‘nearest’ is in terms of [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance).\n", 86 | "\n", 87 | "An agent who is not happy is called *unhappy*.\n", 88 | "\n", 89 | "An important point here is that agents are not averse to living in mixed areas.\n", 90 | "\n", 91 | "They are perfectly happy if half their neighbors are of the other color." 92 | ] 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "id": "3f367575", 97 | "metadata": {}, 98 | "source": [ 99 | "### Behavior\n", 100 | "\n", 101 | "Initially, agents are mixed together (integrated).\n", 102 | "\n", 103 | "In particular, the initial location of each agent is an independent draw from a bivariate uniform distribution on $ S = (0, 1)^2 $.\n", 104 | "\n", 105 | "Now, cycling through the set of all agents, each agent is now given the chance to stay or move.\n", 106 | "\n", 107 | "We assume that each agent will stay put if they are happy and move if unhappy.\n", 108 | "\n", 109 | "The algorithm for moving is as follows\n", 110 | "\n", 111 | "1. Draw a random location in $ S $ \n", 112 | "1. If happy at new location, move there \n", 113 | "1. Else, go to step 1 \n", 114 | "\n", 115 | "\n", 116 | "In this way, we cycle continuously through the agents, moving as required.\n", 117 | "\n", 118 | "We continue to cycle until no one wishes to move." 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "id": "d6372480", 124 | "metadata": {}, 125 | "source": [ 126 | "## Results\n", 127 | "\n", 128 | "Let’s have a look at the results we got when we coded and ran this model.\n", 129 | "\n", 130 | "As discussed above, agents are initially mixed randomly together\n", 131 | "\n", 132 | "![https://julia.quantecon.org/_static/figures/schelling_fig1.png](https://julia.quantecon.org/_static/figures/schelling_fig1.png)\n", 133 | "\n", 134 | " \n", 135 | "But after several cycles they become segregated into distinct regions\n", 136 | "\n", 137 | "![https://julia.quantecon.org/_static/figures/schelling_fig2.png](https://julia.quantecon.org/_static/figures/schelling_fig2.png)\n", 138 | "\n", 139 | " \n", 140 | "![https://julia.quantecon.org/_static/figures/schelling_fig3.png](https://julia.quantecon.org/_static/figures/schelling_fig3.png)\n", 141 | "\n", 142 | " \n", 143 | "![https://julia.quantecon.org/_static/figures/schelling_fig4.png](https://julia.quantecon.org/_static/figures/schelling_fig4.png)\n", 144 | "\n", 145 | " \n", 146 | "In this instance, the program terminated after 4 cycles through the set of\n", 147 | "agents, indicating that all agents had reached a state of happiness.\n", 148 | "\n", 149 | "What is striking about the pictures is how rapidly racial integration breaks down.\n", 150 | "\n", 151 | "This is despite the fact that people in the model don’t actually mind living mixed with the other type.\n", 152 | "\n", 153 | "Even with these preferences, the outcome is a high degree of segregation." 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "id": "5e5c5c74", 159 | "metadata": {}, 160 | "source": [ 161 | "## Exercises\n", 162 | "\n", 163 | "\n", 164 | "" 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "id": "00b34c89", 170 | "metadata": {}, 171 | "source": [ 172 | "### Exercise 1\n", 173 | "\n", 174 | "Implement and run this simulation for yourself.\n", 175 | "\n", 176 | "Use 250 agents of each type." 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "id": "cc08d59e", 182 | "metadata": {}, 183 | "source": [ 184 | "## Solutions" 185 | ] 186 | }, 187 | { 188 | "cell_type": "markdown", 189 | "id": "559c12bb", 190 | "metadata": {}, 191 | "source": [ 192 | "### Exercise 1\n", 193 | "\n", 194 | "Here’s one solution that does the job we want. If you feel like a\n", 195 | "further exercise you can probably speed up some of the computations and\n", 196 | "then increase the number of agents." 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "id": "a430e54e", 203 | "metadata": { 204 | "hide-output": false 205 | }, 206 | "outputs": [], 207 | "source": [ 208 | "using Plots, LinearAlgebra, Statistics" 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": null, 214 | "id": "7232dae1", 215 | "metadata": { 216 | "hide-output": false 217 | }, 218 | "outputs": [], 219 | "source": [ 220 | "Agent(; kind, location = rand(2)) = (; kind, location)\n", 221 | "\n", 222 | "draw_location!(a) = a.location .= rand(2)\n", 223 | "\n", 224 | "# distance is just 2 norm: uses our subtraction function\n", 225 | "get_distance(a, agent) = norm(a.location - agent.location)\n", 226 | "\n", 227 | "function is_happy(a)\n", 228 | " distances = [(get_distance(a, agent), agent) for agent in agents]\n", 229 | " sort!(distances)\n", 230 | " neighbors = [agent for (d, agent) in distances[1:neighborhood_size]]\n", 231 | " share = mean(isequal(a.kind), other.kind for other in neighbors)\n", 232 | "\n", 233 | " # can also do\n", 234 | " # share = mean(isequal(a.kind),\n", 235 | " # first(agents[idx]) for idx in\n", 236 | " # partialsortperm(get_distance.(Ref(a), agents),\n", 237 | " # 1:neighborhood_size))\n", 238 | "\n", 239 | " return share >= preference\n", 240 | "end\n", 241 | "\n", 242 | "function update!(a)\n", 243 | " # If not happy, then randomly choose new locations until happy.\n", 244 | " while !is_happy(a)\n", 245 | " draw_location!(a)\n", 246 | " end\n", 247 | "end\n", 248 | "\n", 249 | "function plot_distribution(agents)\n", 250 | " x_vals_0, y_vals_0 = zeros(0), zeros(0)\n", 251 | " x_vals_1, y_vals_1 = zeros(0), zeros(0)\n", 252 | "\n", 253 | " # obtain locations of each type\n", 254 | " for agent in agents\n", 255 | " x, y = agent.location\n", 256 | " if agent.kind == 0\n", 257 | " push!(x_vals_0, x)\n", 258 | " push!(y_vals_0, y)\n", 259 | " else\n", 260 | " push!(x_vals_1, x)\n", 261 | " push!(y_vals_1, y)\n", 262 | " end\n", 263 | " end\n", 264 | "\n", 265 | " p = scatter(x_vals_0, y_vals_0, color = :orange, markersize = 8,\n", 266 | " alpha = 0.6)\n", 267 | " scatter!(x_vals_1, y_vals_1, color = :green, markersize = 8, alpha = 0.6)\n", 268 | " return plot!(legend = :none)\n", 269 | "end" 270 | ] 271 | }, 272 | { 273 | "cell_type": "code", 274 | "execution_count": null, 275 | "id": "9eb01365", 276 | "metadata": { 277 | "hide-output": false 278 | }, 279 | "outputs": [], 280 | "source": [ 281 | "num_of_type_0 = 250\n", 282 | "num_of_type_1 = 250\n", 283 | "neighborhood_size = 10 # Number of agents regarded as neighbors\n", 284 | "preference = 0.5 # Want their kind to make at least this share of the neighborhood\n", 285 | "\n", 286 | "# Create a list of agents\n", 287 | "agents = vcat([Agent(kind = 0) for i in 1:num_of_type_0],\n", 288 | " [Agent(kind = 1) for i in 1:num_of_type_1])\n", 289 | "\n", 290 | "plot_array = Any[]\n", 291 | "\n", 292 | "# loop until none wishes to move\n", 293 | "while true\n", 294 | " push!(plot_array, plot_distribution(agents))\n", 295 | " no_one_moved = true\n", 296 | " for agent in agents\n", 297 | " old_location = copy(agent.location)\n", 298 | " update!(agent)\n", 299 | " if norm(old_location - agent.location) ≉ 0\n", 300 | " no_one_moved = false\n", 301 | " end\n", 302 | " end\n", 303 | " if no_one_moved\n", 304 | " break\n", 305 | " end\n", 306 | "end\n", 307 | "n = length(plot_array)\n", 308 | "plot(plot_array...,\n", 309 | " layout = (n, 1),\n", 310 | " size = (600, 400n),\n", 311 | " title = reshape([\"Cycle $i\" for i in 1:n], 1, n))" 312 | ] 313 | } 314 | ], 315 | "metadata": { 316 | "date": 1766028221.4153612, 317 | "filename": "schelling.md", 318 | "kernelspec": { 319 | "display_name": "Julia", 320 | "language": "julia", 321 | "name": "julia-1.12" 322 | }, 323 | "title": "Schelling’s Segregation Model" 324 | }, 325 | "nbformat": 4, 326 | "nbformat_minor": 5 327 | } -------------------------------------------------------------------------------- /more_julia/general_packages.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "bb168c81", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "29d61523", 15 | "metadata": {}, 16 | "source": [ 17 | "# General Purpose Packages" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "id": "73b99ce1", 23 | "metadata": {}, 24 | "source": [ 25 | "## Contents\n", 26 | "\n", 27 | "- [General Purpose Packages](#General-Purpose-Packages) \n", 28 | " - [Overview](#Overview) \n", 29 | " - [Numerical Integration](#Numerical-Integration) \n", 30 | " - [Interpolation](#Interpolation) \n", 31 | " - [Linear Algebra](#Linear-Algebra) \n", 32 | " - [General Tools](#General-Tools) " 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "id": "0dab8d56", 38 | "metadata": {}, 39 | "source": [ 40 | "## Overview\n", 41 | "\n", 42 | "Julia has both a large number of useful, well written libraries and many incomplete poorly maintained proofs of concept.\n", 43 | "\n", 44 | "A major advantage of Julia libraries is that, because Julia itself is sufficiently fast, there is less need to mix in low level languages like C and Fortran.\n", 45 | "\n", 46 | "As a result, most Julia libraries are written exclusively in Julia.\n", 47 | "\n", 48 | "Not only does this make the libraries more portable, it makes them much easier to dive into, read, learn from and modify.\n", 49 | "\n", 50 | "In this lecture we introduce a few of the Julia libraries that we’ve found particularly useful for quantitative work in economics.\n", 51 | "\n", 52 | "Also see [data and statistical packages](https://julia.quantecon.org/data_statistical_packages.html) and [optimization, solver, and related packages](https://julia.quantecon.org/optimization_solver_packages.html) for more domain specific packages." 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "id": "897ab4c8", 59 | "metadata": { 60 | "hide-output": false 61 | }, 62 | "outputs": [], 63 | "source": [ 64 | "using LinearAlgebra, Statistics\n", 65 | "using QuadGK, FastGaussQuadrature, Distributions, Expectations\n", 66 | "using Interpolations, Plots, ProgressMeter" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "id": "c3f0a42e", 72 | "metadata": {}, 73 | "source": [ 74 | "## Numerical Integration\n", 75 | "\n", 76 | "Many applications require directly calculating a numerical derivative and calculating expectations." 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "id": "71fba106", 82 | "metadata": {}, 83 | "source": [ 84 | "### Adaptive Quadrature\n", 85 | "\n", 86 | "A high accuracy solution for calculating numerical integrals is [QuadGK](https://github.com/JuliaMath/QuadGK.jl)." 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "id": "0b021bdc", 93 | "metadata": { 94 | "hide-output": false 95 | }, 96 | "outputs": [], 97 | "source": [ 98 | "using QuadGK\n", 99 | "@show value, tol = quadgk(cos, -2π, 2π);" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "id": "882efebb", 105 | "metadata": {}, 106 | "source": [ 107 | "This is an adaptive Gauss-Kronrod integration technique that’s relatively accurate for smooth functions.\n", 108 | "\n", 109 | "However, its adaptive implementation makes it slow and not well suited to inner loops." 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "id": "2cac0035", 115 | "metadata": {}, 116 | "source": [ 117 | "### Gaussian Quadrature\n", 118 | "\n", 119 | "Alternatively, many integrals can be done efficiently with (non-adaptive) [Gaussian quadrature](https://en.wikipedia.org/wiki/Gaussian_quadrature).\n", 120 | "\n", 121 | "For example, using [FastGaussQuadrature.jl](https://github.com/ajt60gaibb/FastGaussQuadrature.jl)" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": null, 127 | "id": "5dd25134", 128 | "metadata": { 129 | "hide-output": false 130 | }, 131 | "outputs": [], 132 | "source": [ 133 | "using FastGaussQuadrature\n", 134 | "x, w = gausslegendre(100_000); # i.e. find 100,000 nodes\n", 135 | "\n", 136 | "# integrates f(x) = x^2 from -1 to 1\n", 137 | "f(x) = x^2\n", 138 | "@show w ⋅ f.(x); # calculate integral" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "id": "91ab9e74", 144 | "metadata": {}, 145 | "source": [ 146 | "The only problem with the `FastGaussQuadrature` package is that you will need to deal with affine transformations to the non-default domains yourself." 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "id": "85cc7ac7", 152 | "metadata": {}, 153 | "source": [ 154 | "### Expectations\n", 155 | "\n", 156 | "If the calculations of the numerical integral is simply for calculating mathematical expectations of a particular distribution, then [Expectations.jl](https://github.com/QuantEcon/Expectations.jl) provides a convenient interface.\n", 157 | "\n", 158 | "Under the hood, it is finding the appropriate Gaussian quadrature scheme for the distribution using `FastGaussQuadrature`." 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": null, 164 | "id": "75019dd0", 165 | "metadata": { 166 | "hide-output": false 167 | }, 168 | "outputs": [], 169 | "source": [ 170 | "using Distributions, Expectations\n", 171 | "dist = Normal()\n", 172 | "E = expectation(dist)\n", 173 | "f(x) = x\n", 174 | "@show E(f) #i.e. identity\n", 175 | "\n", 176 | "# Or using as a linear operator\n", 177 | "f(x) = x^2\n", 178 | "x = nodes(E)\n", 179 | "w = weights(E)\n", 180 | "E * f.(x) == f.(x) ⋅ w" 181 | ] 182 | }, 183 | { 184 | "cell_type": "markdown", 185 | "id": "6bd959d7", 186 | "metadata": {}, 187 | "source": [ 188 | "## Interpolation\n", 189 | "\n", 190 | "In economics we often wish to interpolate discrete data (i.e., build continuous functions that join discrete sequences of points).\n", 191 | "\n", 192 | "The package we usually turn to for this purpose is [Interpolations.jl](https://github.com/JuliaMath/Interpolations.jl).\n", 193 | "\n", 194 | "There are a variety of options, but we will only demonstrate the convenient notations." 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "id": "9999536d", 200 | "metadata": {}, 201 | "source": [ 202 | "### Univariate with a Regular Grid\n", 203 | "\n", 204 | "Let’s start with the univariate case.\n", 205 | "\n", 206 | "We begin by creating some data points, using a sine function" 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "execution_count": null, 212 | "id": "639b2ea8", 213 | "metadata": { 214 | "hide-output": false 215 | }, 216 | "outputs": [], 217 | "source": [ 218 | "using Interpolations\n", 219 | "using Plots\n", 220 | "\n", 221 | "x = -7:7 # x points, coase grid\n", 222 | "y = sin.(x) # corresponding y points\n", 223 | "\n", 224 | "xf = -7:0.1:7 # fine grid\n", 225 | "plot(xf, sin.(xf), label = \"sin function\")\n", 226 | "scatter!(x, y, label = \"sampled data\", markersize = 4)" 227 | ] 228 | }, 229 | { 230 | "cell_type": "markdown", 231 | "id": "f286ae15", 232 | "metadata": {}, 233 | "source": [ 234 | "To implement linear and cubic [spline](https://en.wikipedia.org/wiki/Spline_%28mathematics%29) interpolation" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": null, 240 | "id": "98e8cac1", 241 | "metadata": { 242 | "hide-output": false 243 | }, 244 | "outputs": [], 245 | "source": [ 246 | "li = LinearInterpolation(x, y)\n", 247 | "li_spline = CubicSplineInterpolation(x, y)\n", 248 | "\n", 249 | "@show li(0.3) # evaluate at a single point\n", 250 | "\n", 251 | "scatter(x, y, label = \"sampled data\", markersize = 4)\n", 252 | "plot!(xf, li.(xf), label = \"linear\")\n", 253 | "plot!(xf, li_spline.(xf), label = \"spline\")" 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "id": "b1e64fe5", 259 | "metadata": {}, 260 | "source": [ 261 | "### Univariate with Irregular Grid\n", 262 | "\n", 263 | "In the above, the `LinearInterpolation` function uses a specialized function\n", 264 | "for regular grids since `x` is a `Range` type.\n", 265 | "\n", 266 | "For an arbitrary, irregular grid" 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": null, 272 | "id": "830be793", 273 | "metadata": { 274 | "hide-output": false 275 | }, 276 | "outputs": [], 277 | "source": [ 278 | "x = log.(range(1, exp(4), length = 10)) .+ 1 # uneven grid\n", 279 | "y = log.(x) # corresponding y points\n", 280 | "\n", 281 | "interp = LinearInterpolation(x, y)\n", 282 | "\n", 283 | "xf = log.(range(1, exp(4), length = 100)) .+ 1 # finer grid\n", 284 | "\n", 285 | "plot(xf, interp.(xf), label = \"linear\")\n", 286 | "scatter!(x, y, label = \"sampled data\", markersize = 4, size = (800, 400))" 287 | ] 288 | }, 289 | { 290 | "cell_type": "markdown", 291 | "id": "f796c847", 292 | "metadata": {}, 293 | "source": [ 294 | "At this point, `Interpolations.jl` does not have support for cubic splines with irregular grids, but there are plenty of other packages that do (e.g. [Dierckx.jl](https://github.com/kbarbary/Dierckx.jl) and [GridInterpolations.jl](https://github.com/sisl/GridInterpolations.jl))." 295 | ] 296 | }, 297 | { 298 | "cell_type": "markdown", 299 | "id": "44f266b6", 300 | "metadata": {}, 301 | "source": [ 302 | "### Multivariate Interpolation\n", 303 | "\n", 304 | "Interpolating a regular multivariate function uses the same function" 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": null, 310 | "id": "4ccb193d", 311 | "metadata": { 312 | "hide-output": false 313 | }, 314 | "outputs": [], 315 | "source": [ 316 | "f(x, y) = log(x + y)\n", 317 | "xs = 1:0.2:5\n", 318 | "ys = 2:0.1:5\n", 319 | "A = [f(x, y) for x in xs, y in ys]\n", 320 | "\n", 321 | "# linear interpolation\n", 322 | "interp_linear = LinearInterpolation((xs, ys), A)\n", 323 | "@show interp_linear(3, 2) # exactly log(3 + 2)\n", 324 | "@show interp_linear(3.1, 2.1) # approximately log(3.1 + 2.1)\n", 325 | "\n", 326 | "# cubic spline interpolation\n", 327 | "interp_cubic = CubicSplineInterpolation((xs, ys), A)\n", 328 | "@show interp_cubic(3, 2) # exactly log(3 + 2)\n", 329 | "@show interp_cubic(3.1, 2.1) # approximately log(3.1 + 2.1);" 330 | ] 331 | }, 332 | { 333 | "cell_type": "markdown", 334 | "id": "0dd5ec3c", 335 | "metadata": {}, 336 | "source": [ 337 | "See [Interpolations.jl documentation](https://github.com/JuliaMath/Interpolations.jl#convenience-notation) for more details on options and settings." 338 | ] 339 | }, 340 | { 341 | "cell_type": "markdown", 342 | "id": "f032b1fb", 343 | "metadata": {}, 344 | "source": [ 345 | "## Linear Algebra" 346 | ] 347 | }, 348 | { 349 | "cell_type": "markdown", 350 | "id": "e3a6d2c2", 351 | "metadata": {}, 352 | "source": [ 353 | "### Standard Library\n", 354 | "\n", 355 | "The standard library contains many useful routines for linear algebra, in\n", 356 | "addition to standard functions such as `det()`, `inv()`, `factorize()`, etc.\n", 357 | "\n", 358 | "Routines are available for\n", 359 | "\n", 360 | "- Cholesky factorization \n", 361 | "- LU decomposition \n", 362 | "- Singular value decomposition, \n", 363 | "- Schur factorization, etc. \n", 364 | "\n", 365 | "\n", 366 | "See [here](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/) for further details." 367 | ] 368 | }, 369 | { 370 | "cell_type": "markdown", 371 | "id": "c73fbde4", 372 | "metadata": {}, 373 | "source": [ 374 | "## General Tools" 375 | ] 376 | }, 377 | { 378 | "cell_type": "markdown", 379 | "id": "d931882d", 380 | "metadata": {}, 381 | "source": [ 382 | "### ProgressMeter.jl\n", 383 | "\n", 384 | "For long-running operations, you can use the [ProgressMeter.jl](https://github.com/timholy/ProgressMeter.jl) package.\n", 385 | "\n", 386 | "To use the package, you simply put a macro in front of `for` loops, etc.\n", 387 | "\n", 388 | "From the documentation" 389 | ] 390 | }, 391 | { 392 | "cell_type": "code", 393 | "execution_count": null, 394 | "id": "1594b41e", 395 | "metadata": { 396 | "hide-output": false 397 | }, 398 | "outputs": [], 399 | "source": [ 400 | "using ProgressMeter\n", 401 | "\n", 402 | "@showprogress 1 \"Computing...\" for i in 1:50\n", 403 | " sleep(0.1) # some computation....\n", 404 | "end" 405 | ] 406 | } 407 | ], 408 | "metadata": { 409 | "date": 1732137475.421049, 410 | "filename": "general_packages.md", 411 | "kernelspec": { 412 | "display_name": "Julia", 413 | "language": "julia", 414 | "name": "julia-1.11" 415 | }, 416 | "title": "General Purpose Packages" 417 | }, 418 | "nbformat": 4, 419 | "nbformat_minor": 5 420 | } -------------------------------------------------------------------------------- /more_julia/data_statistical_packages.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "4a39cf0e", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "8f6b15fe", 15 | "metadata": {}, 16 | "source": [ 17 | "# General, Data, and Statistics Packages" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "id": "6c0b5ccb", 23 | "metadata": {}, 24 | "source": [ 25 | "## Contents\n", 26 | "\n", 27 | "- [General, Data, and Statistics Packages](#General,-Data,-and-Statistics-Packages) \n", 28 | " - [Overview](#Overview) \n", 29 | " - [DataFrames](#DataFrames) \n", 30 | " - [Statistics and Econometrics](#Statistics-and-Econometrics) " 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "id": "e7c76704", 36 | "metadata": {}, 37 | "source": [ 38 | "## Overview\n", 39 | "\n", 40 | "This lecture explores some of the key packages for working with data and doing statistics in Julia.\n", 41 | "\n", 42 | "In particular, we will examine the `DataFrame` object in detail (i.e., construction, manipulation, querying, visualization, and nuances like missing data).\n", 43 | "\n", 44 | "While Julia is not an ideal language for pure cookie-cutter statistical analysis, it has many useful packages to provide those tools as part of a more general solution.\n", 45 | "\n", 46 | "This list is not exhaustive, and others can be found in organizations such as [JuliaStats](https://github.com/JuliaStats), [JuliaData](https://github.com/JuliaData/), and [QueryVerse](https://github.com/queryverse)." 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "id": "e8107d30", 53 | "metadata": { 54 | "hide-output": false 55 | }, 56 | "outputs": [], 57 | "source": [ 58 | "using LinearAlgebra, Statistics, DataFrames" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "id": "7e39e43b", 64 | "metadata": {}, 65 | "source": [ 66 | "## DataFrames\n", 67 | "\n", 68 | "A useful package for working with data is [DataFrames.jl](https://github.com/JuliaStats/DataFrames.jl).\n", 69 | "\n", 70 | "The most important data type provided is a `DataFrame`, a two dimensional array for storing heterogeneous data.\n", 71 | "\n", 72 | "Although data can be heterogeneous within a `DataFrame`, the contents of the columns must be homogeneous\n", 73 | "(of the same type).\n", 74 | "\n", 75 | "This is analogous to a `data.frame` in R, a `DataFrame` in Pandas (Python) or, more loosely, a spreadsheet in Excel.\n", 76 | "\n", 77 | "There are a few different ways to create a DataFrame." 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "id": "0f39133d", 83 | "metadata": {}, 84 | "source": [ 85 | "### Constructing and Accessing a DataFrame\n", 86 | "\n", 87 | "The first is to set up columns and construct a dataframe by assigning names" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": null, 93 | "id": "ba0e6d1d", 94 | "metadata": { 95 | "hide-output": false 96 | }, 97 | "outputs": [], 98 | "source": [ 99 | "using DataFrames\n", 100 | "\n", 101 | "# note use of missing\n", 102 | "commodities = [\"crude\", \"gas\", \"gold\", \"silver\"]\n", 103 | "last_price = [4.2, 11.3, 12.1, missing]\n", 104 | "df = DataFrame(commod = commodities, price = last_price)" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "id": "832851b8", 110 | "metadata": {}, 111 | "source": [ 112 | "Columns of the `DataFrame` can be accessed by name using `df.col`, as below" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": null, 118 | "id": "c9229d75", 119 | "metadata": { 120 | "hide-output": false 121 | }, 122 | "outputs": [], 123 | "source": [ 124 | "df.price" 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "id": "2ea0d65f", 130 | "metadata": {}, 131 | "source": [ 132 | "Note that the type of this array has values `Union{Missing, Float64}` since it was created with a `missing` value." 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": null, 138 | "id": "1ef8d242", 139 | "metadata": { 140 | "hide-output": false 141 | }, 142 | "outputs": [], 143 | "source": [ 144 | "df.commod" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "id": "6cd2bbd1", 150 | "metadata": {}, 151 | "source": [ 152 | "The `DataFrames.jl` package provides a number of methods for acting on `DataFrame`’s, such as `describe`." 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": null, 158 | "id": "3ad6564f", 159 | "metadata": { 160 | "hide-output": false 161 | }, 162 | "outputs": [], 163 | "source": [ 164 | "DataFrames.describe(df)" 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "id": "412e78ff", 170 | "metadata": {}, 171 | "source": [ 172 | "While often data will be generated all at once, or read from a file, you can add to a `DataFrame` by providing the key parameters." 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": null, 178 | "id": "c0c5da79", 179 | "metadata": { 180 | "hide-output": false 181 | }, 182 | "outputs": [], 183 | "source": [ 184 | "nt = (commod = \"nickel\", price = 5.1)\n", 185 | "push!(df, nt)" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "id": "ca02c81c", 191 | "metadata": {}, 192 | "source": [ 193 | "Named tuples can also be used to construct a `DataFrame`, and have it properly deduce all types." 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": null, 199 | "id": "b4fee885", 200 | "metadata": { 201 | "hide-output": false 202 | }, 203 | "outputs": [], 204 | "source": [ 205 | "nt = (t = 1, col1 = 3.0)\n", 206 | "df2 = DataFrame([nt])\n", 207 | "push!(df2, (t = 2, col1 = 4.0))" 208 | ] 209 | }, 210 | { 211 | "cell_type": "markdown", 212 | "id": "164e47e5", 213 | "metadata": {}, 214 | "source": [ 215 | "In order to modify a column, access the mutating version by the symbol `df[!, :col]`." 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": null, 221 | "id": "ee59c206", 222 | "metadata": { 223 | "hide-output": false 224 | }, 225 | "outputs": [], 226 | "source": [ 227 | "df[!, :price]" 228 | ] 229 | }, 230 | { 231 | "cell_type": "markdown", 232 | "id": "d03ecaa2", 233 | "metadata": {}, 234 | "source": [ 235 | "Which allows modifications, like other mutating `!` functions in julia." 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": null, 241 | "id": "b33aa343", 242 | "metadata": { 243 | "hide-output": false 244 | }, 245 | "outputs": [], 246 | "source": [ 247 | "df[!, :price] *= 2.0 # double prices" 248 | ] 249 | }, 250 | { 251 | "cell_type": "markdown", 252 | "id": "5c813762", 253 | "metadata": {}, 254 | "source": [ 255 | "As discussed in the next section, note that the [fundamental types](https://julia.quantecon.org/../getting_started_julia/fundamental_types.html#missing), is propagated, i.e. `missing * 2 === missing`." 256 | ] 257 | }, 258 | { 259 | "cell_type": "markdown", 260 | "id": "662cfe8a", 261 | "metadata": {}, 262 | "source": [ 263 | "### Working with Missing\n", 264 | "\n", 265 | "As we discussed in [fundamental types](https://julia.quantecon.org/../getting_started_julia/fundamental_types.html#missing), the semantics of `missing` are that mathematical operations will not silently ignore it.\n", 266 | "\n", 267 | "In order to allow `missing` in a column, you can create/load the `DataFrame`\n", 268 | "from a source with `missing`’s, or call `allowmissing!` on a column." 269 | ] 270 | }, 271 | { 272 | "cell_type": "code", 273 | "execution_count": null, 274 | "id": "d04b606d", 275 | "metadata": { 276 | "hide-output": false 277 | }, 278 | "outputs": [], 279 | "source": [ 280 | "allowmissing!(df2, :col1) # necessary to add in a for col1\n", 281 | "push!(df2, (t = 3, col1 = missing))\n", 282 | "push!(df2, (t = 4, col1 = 5.1))" 283 | ] 284 | }, 285 | { 286 | "cell_type": "markdown", 287 | "id": "b3ca975a", 288 | "metadata": {}, 289 | "source": [ 290 | "We can see the propagation of `missing` to caller functions, as well as a way to efficiently calculate with non-missing data." 291 | ] 292 | }, 293 | { 294 | "cell_type": "code", 295 | "execution_count": null, 296 | "id": "dbfa893c", 297 | "metadata": { 298 | "hide-output": false 299 | }, 300 | "outputs": [], 301 | "source": [ 302 | "@show mean(df2.col1)\n", 303 | "@show mean(skipmissing(df2.col1))" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "id": "e2313c43", 309 | "metadata": {}, 310 | "source": [ 311 | "And to replace the `missing`" 312 | ] 313 | }, 314 | { 315 | "cell_type": "code", 316 | "execution_count": null, 317 | "id": "9c4863ea", 318 | "metadata": { 319 | "hide-output": false 320 | }, 321 | "outputs": [], 322 | "source": [ 323 | "df2.col1 .= coalesce.(df2.col1, 0.0) # replace all missing with 0.0" 324 | ] 325 | }, 326 | { 327 | "cell_type": "markdown", 328 | "id": "cb259af2", 329 | "metadata": {}, 330 | "source": [ 331 | "### Manipulating and Transforming DataFrames\n", 332 | "\n", 333 | "One way to do an additional calculation with a `DataFrame` is to use the `@transform` macro from `DataFramesMeta.jl`.\n", 334 | "\n", 335 | "The following are code only blocks, which would require installation of the packages in a separate environment." 336 | ] 337 | }, 338 | { 339 | "cell_type": "code", 340 | "execution_count": null, 341 | "id": "dab36641", 342 | "metadata": { 343 | "hide-output": false 344 | }, 345 | "outputs": [], 346 | "source": [ 347 | "using DataFramesMeta\n", 348 | "f(x) = x^2\n", 349 | "df2 = @transform(df2, :col2=f.(:col1))" 350 | ] 351 | }, 352 | { 353 | "cell_type": "markdown", 354 | "id": "f6bc3d7e", 355 | "metadata": {}, 356 | "source": [ 357 | "### Categorical Data\n", 358 | "\n", 359 | "For data that is [categorical](https://juliadata.github.io/DataFrames.jl/stable/man/categorical/)" 360 | ] 361 | }, 362 | { 363 | "cell_type": "code", 364 | "execution_count": null, 365 | "id": "be639815", 366 | "metadata": { 367 | "hide-output": false 368 | }, 369 | "outputs": [], 370 | "source": [ 371 | "using CategoricalArrays\n", 372 | "id = [1, 2, 3, 4]\n", 373 | "y = [\"old\", \"young\", \"young\", \"old\"]\n", 374 | "y = CategoricalArray(y)\n", 375 | "df = DataFrame(id = id, y = y)" 376 | ] 377 | }, 378 | { 379 | "cell_type": "code", 380 | "execution_count": null, 381 | "id": "1b1bb814", 382 | "metadata": { 383 | "hide-output": false 384 | }, 385 | "outputs": [], 386 | "source": [ 387 | "levels(df.y)" 388 | ] 389 | }, 390 | { 391 | "cell_type": "markdown", 392 | "id": "a2cd1baf", 393 | "metadata": {}, 394 | "source": [ 395 | "### Visualization, Querying, and Plots\n", 396 | "\n", 397 | "The `DataFrame` (and similar types that fulfill a standard generic interface) can fit into a variety of packages.\n", 398 | "\n", 399 | "One set of them is the [QueryVerse](https://github.com/queryverse).\n", 400 | "\n", 401 | "**Note:** The QueryVerse, in the same spirit as R’s tidyverse, makes heavy use of the pipeline syntax `|>`." 402 | ] 403 | }, 404 | { 405 | "cell_type": "markdown", 406 | "id": "42e88255", 407 | "metadata": {}, 408 | "source": [ 409 | "## Statistics and Econometrics\n", 410 | "\n", 411 | "While Julia is not intended as a replacement for R, Stata, and similar specialty languages, it has a growing number of packages aimed at statistics and econometrics.\n", 412 | "\n", 413 | "Many of the packages live in the [JuliaStats organization](https://github.com/JuliaStats/).\n", 414 | "\n", 415 | "A few to point out\n", 416 | "\n", 417 | "- [StatsBase](https://github.com/JuliaStats/StatsBase.jl) has basic statistical functions such as geometric and harmonic means, auto-correlations, robust statistics, etc. \n", 418 | "- [StatsFuns](https://github.com/JuliaStats/StatsFuns.jl) has a variety of mathematical functions and constants such as pdf and cdf of many distributions, softmax, etc. " 419 | ] 420 | }, 421 | { 422 | "cell_type": "markdown", 423 | "id": "2de64aaa", 424 | "metadata": {}, 425 | "source": [ 426 | "### General Linear Models\n", 427 | "\n", 428 | "To run linear regressions and similar statistics, use the [GLM](http://juliastats.github.io/GLM.jl/latest/) package." 429 | ] 430 | }, 431 | { 432 | "cell_type": "code", 433 | "execution_count": null, 434 | "id": "a4c4e4bc", 435 | "metadata": { 436 | "hide-output": false 437 | }, 438 | "outputs": [], 439 | "source": [ 440 | "using GLM\n", 441 | "\n", 442 | "x = randn(100)\n", 443 | "y = 0.9 .* x + 0.5 * rand(100)\n", 444 | "df = DataFrame(x = x, y = y)\n", 445 | "ols = lm(@formula(y~x), df) # R-style notation" 446 | ] 447 | }, 448 | { 449 | "cell_type": "markdown", 450 | "id": "481e666f", 451 | "metadata": {}, 452 | "source": [ 453 | "To display the results in a useful tables for LaTeX and the REPL, use\n", 454 | "[RegressionTables](https://github.com/jmboehm/RegressionTables.jl/) for output\n", 455 | "similar to the Stata package esttab and the R package stargazer." 456 | ] 457 | }, 458 | { 459 | "cell_type": "code", 460 | "execution_count": null, 461 | "id": "02bd32c2", 462 | "metadata": { 463 | "hide-output": false 464 | }, 465 | "outputs": [], 466 | "source": [ 467 | "using RegressionTables\n", 468 | "regtable(ols)\n", 469 | "# regtable(ols, renderSettings = latexOutput()) # for LaTex output" 470 | ] 471 | } 472 | ], 473 | "metadata": { 474 | "date": 1766028220.5072896, 475 | "filename": "data_statistical_packages.md", 476 | "kernelspec": { 477 | "display_name": "Julia", 478 | "language": "julia", 479 | "name": "julia-1.12" 480 | }, 481 | "title": "General, Data, and Statistics Packages" 482 | }, 483 | "nbformat": 4, 484 | "nbformat_minor": 5 485 | } -------------------------------------------------------------------------------- /about_lectures.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "8dcff0f3", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "d1b9ab94", 15 | "metadata": {}, 16 | "source": [ 17 | "# About these Lectures" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "id": "27f3792c", 23 | "metadata": {}, 24 | "source": [ 25 | "## Overview\n", 26 | "\n", 27 | "Programming, mathematics and statistics are powerful tools for analyzing the functioning of economies.\n", 28 | "\n", 29 | "This lecture series provides a hands-on instruction manual.\n", 30 | "\n", 31 | "Topics include\n", 32 | "\n", 33 | "- algorithms and numerical methods for studying economic problems, \n", 34 | "- related mathematical and statistical concepts, and \n", 35 | "- basics of coding skills and software engineering. \n", 36 | "\n", 37 | "\n", 38 | "The intended audience is undergraduate students, graduate students and\n", 39 | "researchers in economics, finance and related fields." 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "id": "9f65b00d", 45 | "metadata": {}, 46 | "source": [ 47 | "## Julia\n", 48 | "\n", 49 | "The coding language for this lecture series is Julia.\n", 50 | "\n", 51 | "Note that there’s also a related set of [Python lectures](https://python.quantecon.org).\n", 52 | "\n", 53 | "In terms of the differences,\n", 54 | "\n", 55 | "- Python is a general purpose language featuring a huge user community in the sciences and an outstanding scientific and general ecosystem. \n", 56 | "- Julia is a more focused language primarily used in technical and scientific computing, with an outstanding ecosystem for cutting-edge methods and algorithms. \n", 57 | "\n", 58 | "\n", 59 | "Both are modern, open source, high productivity languages with all the key features needed for\n", 60 | "high performance computing.\n", 61 | "\n", 62 | "While Julia has many features of a general purpose language, its specialization makes it much closer to\n", 63 | "using Matlab or Fortran than using a general purpose language - giving it an advantage in being closer\n", 64 | "to both mathematical notation and direct implementation of mathematical abstractions.\n", 65 | "\n", 66 | "Julia has both a large number of useful, well written libraries and many incomplete poorly maintained proofs of concept.\n", 67 | "\n", 68 | "A major advantage of Julia libraries is that, because Julia itself is sufficiently fast, there is less need to mix in low level languages like C and Fortran.\n", 69 | "\n", 70 | "As a result, most Julia libraries are written exclusively in Julia.\n", 71 | "\n", 72 | "Not only does this make the libraries more portable, it makes them much easier to dive into, read, learn from and modify." 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "id": "cc86629d", 78 | "metadata": {}, 79 | "source": [ 80 | "### A Word of Caution\n", 81 | "\n", 82 | "The disadvantage of specialization is that Julia tends to be used by domain experts, and consequently\n", 83 | "the ecosystem and language for non-mathematical/non-scientific computing tasks is inferior to Python.\n", 84 | "\n", 85 | "Another disadvantage is that, since it tends to be used by experts and is on the cutting edge, the tooling is\n", 86 | "much more fragile and rudimentary than Matlab.\n", 87 | "\n", 88 | "Thankfully, with the v1.x release of Julia the fragility no longer applies to the language itself - now stable and\n", 89 | "carefully managed for [version compatibility](https://semver.org/). However, casual users should\n", 90 | "not expect the development tools to quite as stable, or to be comparable to Matlab.\n", 91 | "\n", 92 | "Nevertheless, the end-result will always be elegant and grounded in mathematical notation and abstractions." 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "id": "3bf854d7", 98 | "metadata": {}, 99 | "source": [ 100 | "## Advantages of Julia\n", 101 | "\n", 102 | "Despite the short-term cautions, Julia has both immediate and long-run advantages.\n", 103 | "\n", 104 | "The advantages of the language itself show clearly in the high quality packages, such as\n", 105 | "\n", 106 | "- Differential Equations: [DifferentialEquations.jl](http://docs.juliadiffeq.org/latest/) \n", 107 | "- Function approximation and manipulation: [ApproxFun.jl](https://github.com/JuliaApproximation/ApproxFun.jl) \n", 108 | "- Interval Constraint Programming and rigorous root finding: [IntervalRootFinding.jl](https://github.com/JuliaIntervals/IntervalRootFinding.jl) \n", 109 | "- GPUs: [CuArrays.jl](https://github.com/JuliaGPU/CuArrays.jl) \n", 110 | "- Linear algebra for large-systems (e.g. structured matrices, matrix-free methods, etc.): [IterativeSolvers.jl](https://juliamath.github.io/IterativeSolvers.jl/dev/), [BlockBandedMatrices.jl](https://github.com/JuliaMatrices/BlockBandedMatrices.jl), [InfiniteLinearAlgebra.jl](https://github.com/JuliaMatrices/InfiniteLinearAlgebra.jl), and many others \n", 111 | "- Automatic differentiation: [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) and [Enzyme.jl](https://github.com/EnzymeAD/Enzyme.jl) \n", 112 | "\n", 113 | "\n", 114 | "These are in addition to the many mundane but essential packages available. While there are examples of these packages in other languages, no\n", 115 | "other language can achieve the combination of performance, mathematical notation, and composition that Julia provides.\n", 116 | "\n", 117 | "The composition of packages is especially important, and is made possible through Julia’s use of something called [multiple-dispatch](https://en.wikipedia.org/wiki/Multiple_dispatch)." 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "id": "3cb97082", 123 | "metadata": {}, 124 | "source": [ 125 | "## Open Source\n", 126 | "\n", 127 | "All the computing environments we work with are free and open source.\n", 128 | "\n", 129 | "This means that you, your coauthors and your students can install them and their libraries on all of your computers without cost or concern about licenses.\n", 130 | "\n", 131 | "Another advantage of open source libraries is that you can read them and learn\n", 132 | "how they work.\n", 133 | "\n", 134 | "For example, let’s say you want to know exactly how [Distributions.jl](https://github.com/JuliaStats/Distributions.jl) implements mean of the exponential function\n", 135 | "\n", 136 | "No problem: You can go ahead and [read the code](https://github.com/JuliaStats/Distributions.jl/blob/master/src/univariate/continuous/exponential.jl#L56).\n", 137 | "\n", 138 | "This goes even further since most of Julia is written in Julia. For example, you could see the code for how the standard library calculates the [eigenvalues of a triangular matrix](https://github.com/JuliaLang/julia/blob/master/stdlib/LinearAlgebra/src/triangular.jl#L2594) or calculates the [mean of a range](https://github.com/JuliaLang/julia/blob/master/stdlib/Statistics/src/Statistics.jl#L162)\n", 139 | "\n", 140 | "Those two examples also provide examples where the “multiple dispatch” allows exploitation of the structure of a problem, leading to specialized algorithms (e.g. if the user calls `eigvals` on a matrix that happens to be triangular, it just needs to return the diagonal).\n", 141 | "\n", 142 | "While dipping into external code libraries takes a bit of coding maturity, it’s very useful for\n", 143 | "\n", 144 | "1. helping you understand the details of a particular implementation, and \n", 145 | "1. building your programming skills by showing you code written by first rate programmers. \n", 146 | "\n", 147 | "\n", 148 | "Also, you can modify the library to suit your needs: if the functionality provided is not exactly what you want, you are free to change it.\n", 149 | "\n", 150 | "Another, more philosophical advantage of open source software is that it conforms to the [scientific ideal of reproducibility](https://en.wikipedia.org/wiki/Scientific_method)." 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "id": "f9fbfd9e", 156 | "metadata": {}, 157 | "source": [ 158 | "## How about Other Languages?\n", 159 | "\n", 160 | "But why don’t you use language XYZ?" 161 | ] 162 | }, 163 | { 164 | "cell_type": "markdown", 165 | "id": "85b3eb8d", 166 | "metadata": {}, 167 | "source": [ 168 | "### MATLAB\n", 169 | "\n", 170 | "While MATLAB has many nice features, it’s starting to show its age.\n", 171 | "\n", 172 | "It can no longer match Python or Julia in terms of performance and design.\n", 173 | "\n", 174 | "MATLAB is also proprietary, which comes with its own set of disadvantages.\n", 175 | "\n", 176 | "In particular, the Achilles Heel of Matlab is its lack of a package management\n", 177 | "system, which means that either you need to (1) rely on Matlab’s own packages, which\n", 178 | "are mostly written for engineers and not economists; (2) write the code\n", 179 | "yourself; or (3) use unreliable and manual ways to share code (e.g. email or downloading a zip).\n", 180 | "\n", 181 | "If you are a structural engineer or designing a microcontroller, then Matlab provides a coherent set of packages that takes care of all of your needs.\n", 182 | "\n", 183 | "For economists, on the other hand, the expansion in complexity of numerical methods, the need for researchers to\n", 184 | "collaborate on code, fix bugs, deploy improvements, and have dependencies (i.e. packages relying on other packges) has increased past what Matlab can handle.\n", 185 | "\n", 186 | "Given what’s available now, it’s hard to find any good reasons to invest in MATLAB.\n", 187 | "\n", 188 | "Incidentally, if you decide to jump from MATLAB to Julia, [this cheat-sheet](http://cheatsheets.quantecon.org/) will be useful." 189 | ] 190 | }, 191 | { 192 | "cell_type": "markdown", 193 | "id": "5eb74100", 194 | "metadata": {}, 195 | "source": [ 196 | "### R\n", 197 | "\n", 198 | "[R](https://cran.r-project.org/) is a very useful open source statistical environment and programming language\n", 199 | "\n", 200 | "Its primary strength is its [vast collection](https://cran.r-project.org/web/packages) of extension packages\n", 201 | "\n", 202 | "Julia is more general purpose than R and hence a better fit for this course" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "id": "b7c10d09", 208 | "metadata": {}, 209 | "source": [ 210 | "### C / C++ / Fortran?\n", 211 | "\n", 212 | "Isn’t Fortran / C / C++ faster than Julia? In which case it must be better, right?\n", 213 | "\n", 214 | "For the same algorithms, as a compiled language Julia can often achieve a similar level of performance to those languages.\n", 215 | "\n", 216 | "But even when it doesn’t, keep in mind that the correct objective function to minimize: total time = development time + execution time\n", 217 | "\n", 218 | "In assessing this trade off, it’s necessary to bear in mind that\n", 219 | "\n", 220 | "- Your time is a far more valuable resource than the computer’s time. \n", 221 | "- Languages like Julia are much faster to write and debug in. \n", 222 | "- In any one program, the vast majority of CPU time will be spent iterating over just a few lines of your code. \n", 223 | "\n", 224 | "\n", 225 | "The other issue with all three languages, as with Matlab, is the lack of a package management system. Collaborating on C++ or Fortran packages and distributing code between researchers is difficult, and many\n", 226 | "of the criticisms of matlab equally apply.\n", 227 | "\n", 228 | "Finally, the first-order question of performance is which algorithm you are using, and whether it exploits the structure of the problem. The right algorithm in Matlab or Python is typically faster than the wrong\n", 229 | "algorithm in Fortran - and the right algorithm in Fortran and Julia can be made roughly comparable.\n", 230 | "\n", 231 | "When considering the performance advantages, remember that the design and package system of Julia make it easy to try out algorithms that exploit structure of the problem. We will investigate this more in [Introductory Examples](https://julia.quantecon.org/getting_started_julia/julia_by_example.html#julia-by-example)" 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "id": "407c6117", 237 | "metadata": {}, 238 | "source": [ 239 | "#### Last Word\n", 240 | "\n", 241 | "Writing your entire program in Fortran / C / C++ is best thought of as “premature optimization”\n", 242 | "\n", 243 | "On this topic we quote the godfather:\n", 244 | "\n", 245 | "[](https://en.wikipedia.org/wiki/Donald_Knuth)> We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. – Donald Knuth\n", 246 | "\n", 247 | "But, to put the final part of the quote\n", 248 | "\n", 249 | "[](https://en.wikipedia.org/wiki/Donald_Knuth)> … Yet we should not pass up our opportunities in that critical 3%. – Donald Knuth\n", 250 | "\n", 251 | "Julia is an excellent language to attain those last few percent, without having to resort to C or Fortran code and mix languages in your project" 252 | ] 253 | }, 254 | { 255 | "cell_type": "markdown", 256 | "id": "b2feccdd", 257 | "metadata": {}, 258 | "source": [ 259 | "## Credits\n", 260 | "\n", 261 | "These lectures have benefited greatly from comments and suggestions from our\n", 262 | "colleagues, students and friends. Special thanks are due to our sponsoring\n", 263 | "organization the Alfred P. Sloan Foundation and our research assistants Chase\n", 264 | "Coleman, Spencer Lyon and Matthew McKay for innumerable contributions to the\n", 265 | "code library and functioning of the website.\n", 266 | "\n", 267 | "We also thank [Andrij Stachurski](http://drdrij.com/) for his great web\n", 268 | "skills, and the many others who have contributed suggestions, bug fixes or\n", 269 | "improvements. They include but are not limited to Anmol Bhandari, Long Bui,\n", 270 | "Jeong-Hun Choi, David Evans, Xiaojun Guan, Shunsuke Hori, Chenghan Hou, Doc-Jin Jang, Adam Jozefiak,\n", 271 | "Qingyin Ma, Akira Matsushita, Tomohito Okabe, Daisuke Oyama, David Pugh, Alex\n", 272 | "Olssen, Nathan Palmer, Pooya Rashidi Ravari, Arnav Sood, Bill Tubbs, Dawie van Lill, Natasha Watkins, Pablo Winant, Kaan Yolsever, James Yu, and Yixiao\n", 273 | "Zhou." 274 | ] 275 | } 276 | ], 277 | "metadata": { 278 | "date": 1766028217.9975955, 279 | "filename": "about_lectures.md", 280 | "kernelspec": { 281 | "display_name": "Julia", 282 | "language": "julia", 283 | "name": "julia-1.12" 284 | }, 285 | "title": "About these Lectures" 286 | }, 287 | "nbformat": 4, 288 | "nbformat_minor": 5 289 | } -------------------------------------------------------------------------------- /multi_agent_models/aiyagari.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "59d21468", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "6dde30df", 15 | "metadata": {}, 16 | "source": [ 17 | "# The Aiyagari Model" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "id": "9e208f4a", 23 | "metadata": {}, 24 | "source": [ 25 | "## Contents\n", 26 | "\n", 27 | "- [The Aiyagari Model](#The-Aiyagari-Model) \n", 28 | " - [Overview](#Overview) \n", 29 | " - [The Economy](#The-Economy) \n", 30 | " - [Firms](#Firms) \n", 31 | " - [Code](#Code) " 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "id": "c0b564b9", 37 | "metadata": {}, 38 | "source": [ 39 | "## Overview\n", 40 | "\n", 41 | "In this lecture we describe the structure of a class of models that build on work by Truman Bewley [[Bew77](https://julia.quantecon.org/../zreferences.html#id92)].\n", 42 | "\n", 43 | "The model features\n", 44 | "\n", 45 | "- Heterogeneous agents. \n", 46 | "- A single exogenous vehicle for borrowing and lending. \n", 47 | "- Limits on amounts individual agents may borrow. \n", 48 | "\n", 49 | "\n", 50 | "The Aiyagari model has been used to investigate many topics, including\n", 51 | "\n", 52 | "- precautionary savings and the effect of liquidity constraints [[Aiy94](https://julia.quantecon.org/../zreferences.html#id57)] \n", 53 | "- risk sharing and asset pricing [[HL96](https://julia.quantecon.org/../zreferences.html#id48)] \n", 54 | "- the shape of the wealth distribution [[BBZ15](https://julia.quantecon.org/../zreferences.html#id49)] \n", 55 | "- etc., etc., etc. " 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "id": "abf100b8", 61 | "metadata": {}, 62 | "source": [ 63 | "### References\n", 64 | "\n", 65 | "The primary reference for this lecture is [[Aiy94](https://julia.quantecon.org/../zreferences.html#id57)].\n", 66 | "\n", 67 | "A textbook treatment is available in chapter 18 of [[LS18](https://julia.quantecon.org/../zreferences.html#id101)].\n", 68 | "\n", 69 | "A continuous time version of the model by SeHyoun Ahn and Benjamin Moll can be found [here](http://nbviewer.jupyter.org/github/QuantEcon/QuantEcon.notebooks/blob/master/aiyagari_continuous_time.ipynb)." 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "id": "94d716aa", 75 | "metadata": {}, 76 | "source": [ 77 | "## The Economy" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "id": "46d7a3f3", 83 | "metadata": {}, 84 | "source": [ 85 | "### Households\n", 86 | "\n", 87 | "Infinitely lived households / consumers face idiosyncratic income shocks.\n", 88 | "\n", 89 | "A unit interval of *ex ante* identical households face a common borrowing constraint.\n", 90 | "\n", 91 | "The savings problem faced by a typical household is\n", 92 | "\n", 93 | "$$\n", 94 | "\\max \\mathbb E \\sum_{t=0}^{\\infty} \\beta^t u(c_t)\n", 95 | "$$\n", 96 | "\n", 97 | "subject to\n", 98 | "\n", 99 | "$$\n", 100 | "a_{t+1} + c_t \\leq w z_t + (1 + r) a_t\n", 101 | "\\quad\n", 102 | "c_t \\geq 0,\n", 103 | "\\quad \\text{and} \\quad\n", 104 | "a_t \\geq -B\n", 105 | "$$\n", 106 | "\n", 107 | "where\n", 108 | "\n", 109 | "- $ c_t $ is current consumption \n", 110 | "- $ a_t $ is assets \n", 111 | "- $ z_t $ is an exogenous component of labor income capturing stochastic unemployment risk, etc. \n", 112 | "- $ w $ is a wage rate \n", 113 | "- $ r $ is a net interest rate \n", 114 | "- $ B $ is the maximum amount that the agent is allowed to borrow \n", 115 | "\n", 116 | "\n", 117 | "The exogenous process $ \\{z_t\\} $ follows a finite state Markov chain with given stochastic matrix $ P $.\n", 118 | "\n", 119 | "The wage and interest rate are fixed over time.\n", 120 | "\n", 121 | "In this simple version of the model, households supply labor inelastically because they do not value leisure." 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "id": "fa664b5c", 127 | "metadata": {}, 128 | "source": [ 129 | "## Firms\n", 130 | "\n", 131 | "Firms produce output by hiring capital and labor.\n", 132 | "\n", 133 | "Firms act competitively and face constant returns to scale.\n", 134 | "\n", 135 | "Since returns to scale are constant the number of firms does not matter.\n", 136 | "\n", 137 | "Hence we can consider a single (but nonetheless competitive) representative firm.\n", 138 | "\n", 139 | "The firm’s output is\n", 140 | "\n", 141 | "$$\n", 142 | "Y_t = A K_t^{\\alpha} N^{1 - \\alpha}\n", 143 | "$$\n", 144 | "\n", 145 | "where\n", 146 | "\n", 147 | "- $ A $ and $ \\alpha $ are parameters with $ A > 0 $ and $ \\alpha \\in (0, 1) $ \n", 148 | "- $ K_t $ is aggregate capital \n", 149 | "- $ N $ is total labor supply (which is constant in this simple version of the model) \n", 150 | "\n", 151 | "\n", 152 | "The firm’s problem is\n", 153 | "\n", 154 | "$$\n", 155 | "max_{K, N} \\left\\{ A K_t^{\\alpha} N^{1 - \\alpha} - (r + \\delta) K - w N \\right\\}\n", 156 | "$$\n", 157 | "\n", 158 | "The parameter $ \\delta $ is the depreciation rate.\n", 159 | "\n", 160 | "From the first-order condition with respect to capital, the firm’s inverse demand for capital is\n", 161 | "\n", 162 | "\n", 163 | "\n", 164 | "$$\n", 165 | "r = A \\alpha \\left( \\frac{N}{K} \\right)^{1 - \\alpha} - \\delta \\tag{56.1}\n", 166 | "$$\n", 167 | "\n", 168 | "Using this expression and the firm’s first-order condition for labor, we can pin down\n", 169 | "the equilibrium wage rate as a function of $ r $ as\n", 170 | "\n", 171 | "\n", 172 | "\n", 173 | "$$\n", 174 | "w(r) = A (1 - \\alpha) (A \\alpha / (r + \\delta))^{\\alpha / (1 - \\alpha)} \\tag{56.2}\n", 175 | "$$" 176 | ] 177 | }, 178 | { 179 | "cell_type": "markdown", 180 | "id": "0b1ddb97", 181 | "metadata": {}, 182 | "source": [ 183 | "### Equilibrium\n", 184 | "\n", 185 | "We construct a *stationary rational expectations equilibrium* (SREE).\n", 186 | "\n", 187 | "In such an equilibrium\n", 188 | "\n", 189 | "- prices induce behavior that generates aggregate quantities consistent with the prices \n", 190 | "- aggregate quantities and prices are constant over time \n", 191 | "\n", 192 | "\n", 193 | "In more detail, an SREE lists a set of prices, savings and production policies such that\n", 194 | "\n", 195 | "- households want to choose the specified savings policies taking the prices as given \n", 196 | "- firms maximize profits taking the same prices as given \n", 197 | "- the resulting aggregate quantities are consistent with the prices; in particular, the demand for capital equals the supply \n", 198 | "- aggregate quantities (defined as cross-sectional averages) are constant \n", 199 | "\n", 200 | "\n", 201 | "In practice, once parameter values are set, we can check for an SREE by the following steps\n", 202 | "\n", 203 | "1. pick a proposed quantity $ K $ for aggregate capital \n", 204 | "1. determine corresponding prices, with interest rate $ r $ determined by [(56.1)](#equation-aiy-rgk) and a wage rate $ w(r) $ as given in [(56.2)](#equation-aiy-wgr) \n", 205 | "1. determine the common optimal savings policy of the households given these prices \n", 206 | "1. compute aggregate capital as the mean of steady state capital given this savings policy \n", 207 | "\n", 208 | "\n", 209 | "If this final quantity agrees with $ K $ then we have a SREE." 210 | ] 211 | }, 212 | { 213 | "cell_type": "markdown", 214 | "id": "c249ad9f", 215 | "metadata": {}, 216 | "source": [ 217 | "## Code\n", 218 | "\n", 219 | "Let’s look at how we might compute such an equilibrium in practice.\n", 220 | "\n", 221 | "To solve the household’s dynamic programming problem we’ll use the [DiscreteDP](https://github.com/QuantEcon/QuantEcon.jl/blob/master/src/markov/ddp.jl) type from [QuantEcon.jl](http://quantecon.org/quantecon-jl).\n", 222 | "\n", 223 | "Our first task is the least exciting one: write code that maps parameters for a household problem into the `R` and `Q` matrices needed to generate an instance of `DiscreteDP`.\n", 224 | "\n", 225 | "Below is a piece of boilerplate code that does just this.\n", 226 | "\n", 227 | "In reading the code, the following information will be helpful\n", 228 | "\n", 229 | "- `R` needs to be a matrix where `R[s, a]` is the reward at state `s` under action `a`. \n", 230 | "- `Q` needs to be a three dimensional array where `Q[s, a, s']` is the probability of transitioning to state `s'` when the current state is `s` and the current action is `a`. \n", 231 | "\n", 232 | "\n", 233 | "(For a detailed discussion of `DiscreteDP` see [this lecture](https://julia.quantecon.org/../dynamic_programming/discrete_dp.html))\n", 234 | "\n", 235 | "Here we take the state to be $ s_t := (a_t, z_t) $, where $ a_t $ is assets and $ z_t $ is the shock.\n", 236 | "\n", 237 | "The action is the choice of next period asset level $ a_{t+1} $.\n", 238 | "\n", 239 | "The object also includes a default set of parameters that we’ll adopt unless otherwise specified." 240 | ] 241 | }, 242 | { 243 | "cell_type": "code", 244 | "execution_count": null, 245 | "id": "58c8bfd4", 246 | "metadata": { 247 | "hide-output": false 248 | }, 249 | "outputs": [], 250 | "source": [ 251 | "using LinearAlgebra, Statistics\n", 252 | "using LaTeXStrings, Plots, QuantEcon" 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": null, 258 | "id": "ca9a108c", 259 | "metadata": { 260 | "hide-output": false 261 | }, 262 | "outputs": [], 263 | "source": [ 264 | "function Household(; r = 0.01,\n", 265 | " w = 1.0,\n", 266 | " sigma = 1.0,\n", 267 | " beta = 0.96,\n", 268 | " z_chain = MarkovChain([0.9 0.1; 0.1 0.9], [0.1; 1.0]),\n", 269 | " a_min = 1e-10,\n", 270 | " a_max = 18.0,\n", 271 | " a_size = 200,\n", 272 | " a_vals = range(a_min, a_max, length = a_size),\n", 273 | " # -Inf is the utility of dying (0 consumption)\n", 274 | " u = sigma == 1 ? x -> log(x) :\n", 275 | " x -> (x^(1 - sigma) - 1) / (1 - sigma))\n", 276 | "\n", 277 | " # Create grids\n", 278 | " z_size = length(z_chain.state_values)\n", 279 | " n = a_size * z_size\n", 280 | " s_vals = gridmake(a_vals, z_chain.state_values)\n", 281 | " s_i_vals = gridmake(1:a_size, 1:z_size)\n", 282 | "\n", 283 | " # Fill in the Q and R\n", 284 | " Q = zeros(n, a_size, n)\n", 285 | " for next_s_i in 1:size(Q, 3)\n", 286 | " for a_i in 1:size(Q, 2)\n", 287 | " for s_i in 1:size(Q, 1)\n", 288 | " z_i = s_i_vals[s_i, 2]\n", 289 | " next_z_i = s_i_vals[next_s_i, 2]\n", 290 | " next_a_i = s_i_vals[next_s_i, 1]\n", 291 | " if next_a_i == a_i\n", 292 | " Q[s_i, a_i, next_s_i] = z_chain.p[z_i, next_z_i]\n", 293 | " end\n", 294 | " end\n", 295 | " end\n", 296 | " end\n", 297 | "\n", 298 | " R = fill(-Inf, n, a_size)\n", 299 | " for new_a_i in 1:size(R, 2)\n", 300 | " a_new = a_vals[new_a_i]\n", 301 | " for s_i in 1:size(R, 1)\n", 302 | " a = s_vals[s_i, 1]\n", 303 | " z = s_vals[s_i, 2]\n", 304 | " c = w * z + (1 + r) * a - a_new\n", 305 | " if c > 0\n", 306 | " R[s_i, new_a_i] = u(c)\n", 307 | " end\n", 308 | " end\n", 309 | " end\n", 310 | " return (; r, w, sigma, beta, z_chain, a_min, a_max, a_size, a_vals, z_size,\n", 311 | " n, s_vals, s_i_vals, u, R, Q)\n", 312 | "end" 313 | ] 314 | }, 315 | { 316 | "cell_type": "markdown", 317 | "id": "9c5a8f15", 318 | "metadata": {}, 319 | "source": [ 320 | "As a first example of what we can do, let’s compute and plot an optimal accumulation policy at fixed prices" 321 | ] 322 | }, 323 | { 324 | "cell_type": "code", 325 | "execution_count": null, 326 | "id": "4b0ffc3a", 327 | "metadata": { 328 | "hide-output": false 329 | }, 330 | "outputs": [], 331 | "source": [ 332 | "# Create an instance of Household\n", 333 | "am = Household(; a_max = 20.0, r = 0.03, w = 0.956)\n", 334 | "\n", 335 | "# Use the instance to build a discrete dynamic program\n", 336 | "am_ddp = DiscreteDP(am.R, am.Q, am.beta)\n", 337 | "\n", 338 | "# Solve using policy function iteration\n", 339 | "results = solve(am_ddp, PFI)\n", 340 | "\n", 341 | "# Simplify names\n", 342 | "(; z_size, a_size, n, a_vals) = am\n", 343 | "z_vals = am.z_chain.state_values\n", 344 | "\n", 345 | "# Get all optimal actions across the set of\n", 346 | "# a indices with z fixed in each column\n", 347 | "a_star = reshape([a_vals[results.sigma[s_i]] for s_i in 1:n], a_size, z_size)\n", 348 | "\n", 349 | "labels = [L\"z = %$(z_vals[1])\" L\"z = %$(z_vals[2])\"]\n", 350 | "plot(a_vals, a_star, label = labels, lw = 2, alpha = 0.6)\n", 351 | "plot!(a_vals, a_vals, label = \"\", color = :black, linestyle = :dash)\n", 352 | "plot!(xlabel = \"current assets\", ylabel = \"next period assets\", grid = false)" 353 | ] 354 | }, 355 | { 356 | "cell_type": "markdown", 357 | "id": "4067fa84", 358 | "metadata": {}, 359 | "source": [ 360 | "The plot shows asset accumulation policies at different values of the exogenous state.\n", 361 | "\n", 362 | "Now we want to calculate the equilibrium.\n", 363 | "\n", 364 | "Let’s do this visually as a first pass.\n", 365 | "\n", 366 | "The following code draws aggregate supply and demand curves.\n", 367 | "\n", 368 | "The intersection gives equilibrium interest rates and capital" 369 | ] 370 | }, 371 | { 372 | "cell_type": "code", 373 | "execution_count": null, 374 | "id": "fb65b202", 375 | "metadata": { 376 | "hide-output": false 377 | }, 378 | "outputs": [], 379 | "source": [ 380 | "# Calculate supply of capital for a given r\n", 381 | "function prices_to_capital_stock(r; beta, A, N, alpha, delta, a_max)\n", 382 | " # Create an instance of Household given the parameters\n", 383 | "\n", 384 | " # Calculate the equilibrium wages\n", 385 | " w = A * (1 - alpha) * (A * alpha / (r + delta))^(alpha / (1 - alpha))\n", 386 | " am = Household(; beta, a_max, w, r)\n", 387 | "\n", 388 | " aiyagari_ddp = DiscreteDP(am.R, am.Q, am.beta)\n", 389 | "\n", 390 | " # Compute the optimal policy\n", 391 | " results = solve(aiyagari_ddp, PFI)\n", 392 | "\n", 393 | " # Compute the stationary distribution\n", 394 | " stationary_probs = stationary_distributions(results.mc)[:, 1][1]\n", 395 | "\n", 396 | " # Return K\n", 397 | " K = dot(am.s_vals[:, 1], stationary_probs)\n", 398 | "\n", 399 | " # Return capital\n", 400 | " return K\n", 401 | "end\n", 402 | "\n", 403 | "# Inverse Demand for capital\n", 404 | "function r_inverse_demand(K; A, N, alpha, delta)\n", 405 | " return A * alpha * (N / K)^(1 - alpha) - delta\n", 406 | "end\n", 407 | "\n", 408 | "# Create a grid of r values at which to compute demand and supply of capital\n", 409 | "r_vals = range(0.005, 0.04, length = 20)\n", 410 | "\n", 411 | "# Firms' parameters\n", 412 | "A = 1\n", 413 | "N = 1\n", 414 | "alpha = 0.33\n", 415 | "beta = 0.96\n", 416 | "delta = 0.05\n", 417 | "a_max = 20.0\n", 418 | "\n", 419 | "prices_to_capital_stock(r_vals[1]; A, N, alpha, beta, delta, a_max)\n", 420 | "\n", 421 | "# Compute supply of capital\n", 422 | "k_vals = prices_to_capital_stock.(r_vals; A, N, alpha, beta, delta, a_max)\n", 423 | "\n", 424 | "r_inverse_demand_vals = r_inverse_demand.(k_vals; A, N, alpha, delta)\n", 425 | "\n", 426 | "# Plot against demand for capital by firms\n", 427 | "labels = [\"demand for capital\" \"supply of capital\"]\n", 428 | "plot(k_vals, [r_inverse_demand_vals r_vals], label = labels, lw = 2,\n", 429 | " alpha = 0.6)\n", 430 | "plot!(xlabel = \"capital\", ylabel = \"interest rate\", xlim = (2, 14),\n", 431 | " ylim = (0.0, 0.1))" 432 | ] 433 | } 434 | ], 435 | "metadata": { 436 | "date": 1766028220.8154867, 437 | "filename": "aiyagari.md", 438 | "kernelspec": { 439 | "display_name": "Julia", 440 | "language": "julia", 441 | "name": "julia-1.12" 442 | }, 443 | "title": "The Aiyagari Model" 444 | }, 445 | "nbformat": 4, 446 | "nbformat_minor": 5 447 | } -------------------------------------------------------------------------------- /introduction_dynamics/short_path.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "7e4c9593", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "e748d744", 15 | "metadata": {}, 16 | "source": [ 17 | "# Shortest Paths\n", 18 | "\n", 19 | "\n", 20 | "" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "9634e376", 26 | "metadata": {}, 27 | "source": [ 28 | "## Contents\n", 29 | "\n", 30 | "- [Shortest Paths](#Shortest-Paths) \n", 31 | " - [Overview](#Overview) \n", 32 | " - [Outline of the Problem](#Outline-of-the-Problem) \n", 33 | " - [Finding Least-Cost Paths](#Finding-Least-Cost-Paths) \n", 34 | " - [Solving for $ J $](#Solving-for-$-J-$) \n", 35 | " - [Exercises](#Exercises) \n", 36 | " - [Solutions](#Solutions) " 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "id": "a2133e7f", 42 | "metadata": {}, 43 | "source": [ 44 | "## Overview\n", 45 | "\n", 46 | "The shortest path problem is a [classic problem](https://en.wikipedia.org/wiki/Shortest_path) in mathematics and computer science with applications in\n", 47 | "\n", 48 | "- Economics (sequential decision making, analysis of social networks, etc.) \n", 49 | "- Operations research and transportation \n", 50 | "- Robotics and artificial intelligence \n", 51 | "- Telecommunication network design and routing \n", 52 | "- etc., etc. \n", 53 | "\n", 54 | "\n", 55 | "Variations of the methods we discuss in this lecture are used millions of times every day, in applications such as\n", 56 | "\n", 57 | "- Google Maps \n", 58 | "- routing packets on the internet \n", 59 | "\n", 60 | "\n", 61 | "For us, the shortest path problem also provides a nice introduction to the logic of **dynamic programming**.\n", 62 | "\n", 63 | "Dynamic programming is an extremely powerful optimization technique that we apply in many lectures on this site." 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "id": "bb071d48", 69 | "metadata": {}, 70 | "source": [ 71 | "## Outline of the Problem\n", 72 | "\n", 73 | "The shortest path problem is one of finding how to traverse a [graph](https://en.wikipedia.org/wiki/Graph_%28mathematics%29) from one specified node to another at minimum cost.\n", 74 | "\n", 75 | "Consider the following graph\n", 76 | "\n", 77 | "![https://julia.quantecon.org/_static/figures/graph.png](https://julia.quantecon.org/_static/figures/graph.png)\n", 78 | "\n", 79 | " \n", 80 | "We wish to travel from node (vertex) A to node G at minimum cost.\n", 81 | "\n", 82 | "- Arrows (edges) indicate the movements we can take. \n", 83 | "- Numbers on edges indicate the cost of traveling that edge. \n", 84 | "\n", 85 | "\n", 86 | "Possible interpretations of the graph include\n", 87 | "\n", 88 | "- Minimum cost for supplier to reach a destination. \n", 89 | "- Routing of packets on the internet (minimize time). \n", 90 | "- Etc., etc. \n", 91 | "\n", 92 | "\n", 93 | "For this simple graph, a quick scan of the edges shows that the optimal paths are\n", 94 | "\n", 95 | "- A, C, F, G at cost 8 \n", 96 | "\n", 97 | "\n", 98 | "![https://julia.quantecon.org/_static/figures/graph4.png](https://julia.quantecon.org/_static/figures/graph4.png)\n", 99 | "\n", 100 | " \n", 101 | "- A, D, F, G at cost 8 \n", 102 | "\n", 103 | "\n", 104 | "![https://julia.quantecon.org/_static/figures/graph3.png](https://julia.quantecon.org/_static/figures/graph3.png)" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "id": "206e29a7", 110 | "metadata": {}, 111 | "source": [ 112 | "## Finding Least-Cost Paths\n", 113 | "\n", 114 | "For large graphs we need a systematic solution.\n", 115 | "\n", 116 | "Let $ J(v) $ denote the minimum cost-to-go from node $ v $, understood as the total cost from $ v $ if we take the best route.\n", 117 | "\n", 118 | "Suppose that we know $ J(v) $ for each node $ v $, as shown below for the graph from the preceding example\n", 119 | "\n", 120 | "![https://julia.quantecon.org/_static/figures/graph2.png](https://julia.quantecon.org/_static/figures/graph2.png)\n", 121 | "\n", 122 | " \n", 123 | "Note that $ J(G) = 0 $.\n", 124 | "\n", 125 | "The best path can now be found as follows\n", 126 | "\n", 127 | "- Start at A. \n", 128 | "- From node v, move to any node that solves \n", 129 | "\n", 130 | "\n", 131 | "\n", 132 | "\n", 133 | "$$\n", 134 | "\\min_{w \\in F_v} \\{ c(v, w) + J(w) \\} \\tag{29.1}\n", 135 | "$$\n", 136 | "\n", 137 | "where\n", 138 | "\n", 139 | "- $ F_v $ is the set of nodes that can be reached from $ v $ in one step \n", 140 | "- $ c(v, w) $ is the cost of traveling from $ v $ to $ w $ \n", 141 | "\n", 142 | "\n", 143 | "Hence, if we know the function $ J $, then finding the best path is almost trivial.\n", 144 | "\n", 145 | "But how to find $ J $?\n", 146 | "\n", 147 | "Some thought will convince you that, for every node $ v $,\n", 148 | "the function $ J $ satisfies\n", 149 | "\n", 150 | "\n", 151 | "\n", 152 | "$$\n", 153 | "J(v) = \\min_{w \\in F_v} \\{ c(v, w) + J(w) \\} \\tag{29.2}\n", 154 | "$$\n", 155 | "\n", 156 | "This is known as the *Bellman equation*, after the mathematician Richard Bellman." 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "id": "3473c845", 162 | "metadata": {}, 163 | "source": [ 164 | "## Solving for $ J $\n", 165 | "\n", 166 | "The standard algorithm for finding $ J $ is to start with\n", 167 | "\n", 168 | "\n", 169 | "\n", 170 | "$$\n", 171 | "J_0(v) = M \\text{ if } v \\not= \\text{ destination, else } J_0(v) = 0 \\tag{29.3}\n", 172 | "$$\n", 173 | "\n", 174 | "where $ M $ is some large number.\n", 175 | "\n", 176 | "Now we use the following algorithm\n", 177 | "\n", 178 | "1. Set $ n = 0 $. \n", 179 | "1. Set $ J_{n+1} (v) = \\min_{w \\in F_v} \\{ c(v, w) + J_n(w) \\} $ for all $ v $. \n", 180 | "1. If $ J_{n+1} $ and $ J_n $ are not equal then increment $ n $, go to 2. \n", 181 | "\n", 182 | "\n", 183 | "In general, this sequence converges to $ J $—the proof is omitted." 184 | ] 185 | }, 186 | { 187 | "cell_type": "markdown", 188 | "id": "bab226df", 189 | "metadata": {}, 190 | "source": [ 191 | "## Exercises\n", 192 | "\n", 193 | "\n", 194 | "" 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "id": "8a3461bf", 200 | "metadata": {}, 201 | "source": [ 202 | "### Exercise 1\n", 203 | "\n", 204 | "Use the algorithm given above to find the optimal path (and its cost) for the\n", 205 | "following graph.\n", 206 | "\n", 207 | "The graph is **directed**: from each node you may move only to the destinations\n", 208 | "listed in its adjacency list (e.g., you can travel from `0` to `1`, but not from\n", 209 | "`1` back to `0` unless that edge is explicitly listed). Treat node `0` as the\n", 210 | "start and node `99` as the destination. As an extension, you can symmetrize the\n", 211 | "edges to create an undirected version and compare the resulting path and cost." 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": null, 217 | "id": "54cd4bce", 218 | "metadata": { 219 | "hide-output": false 220 | }, 221 | "outputs": [], 222 | "source": [ 223 | "using LinearAlgebra, Statistics" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": null, 229 | "id": "7fb8e535", 230 | "metadata": { 231 | "hide-output": false 232 | }, 233 | "outputs": [], 234 | "source": [ 235 | "graph = Dict(zip(0:99,\n", 236 | " [\n", 237 | " [(14, 72.21), (8, 11.11), (1, 0.04)],\n", 238 | " [(13, 64.94), (6, 20.59), (46, 1247.25)],\n", 239 | " [(45, 1561.45), (31, 166.8), (66, 54.18)],\n", 240 | " [(11, 42.43), (6, 2.06), (20, 133.65)],\n", 241 | " [(7, 1.02), (5, 0.73), (75, 3706.67)],\n", 242 | " [(11, 34.54), (7, 3.33), (45, 1382.97)],\n", 243 | " [(10, 13.1), (9, 0.72), (31, 63.17)],\n", 244 | " [(10, 5.85), (9, 3.15), (50, 478.14)],\n", 245 | " [(12, 3.18), (11, 7.45), (69, 577.91)],\n", 246 | " [(20, 16.53), (13, 4.42), (70, 2454.28)],\n", 247 | " [(16, 25.16), (12, 1.87), (89, 5352.79)],\n", 248 | " [(20, 65.08), (18, 37.55), (94, 4961.32)],\n", 249 | " [(28, 170.04), (24, 34.32), (84, 3914.62)],\n", 250 | " [(40, 475.33), (38, 236.33), (60, 2135.95)],\n", 251 | " [(24, 38.65), (16, 2.7), (67, 1878.96)],\n", 252 | " [(18, 2.57), (17, 1.01), (91, 3597.11)],\n", 253 | " [(38, 278.71), (19, 3.49), (36, 392.92)],\n", 254 | " [(23, 26.45), (22, 24.78), (76, 783.29)],\n", 255 | " [(28, 55.84), (23, 16.23), (91, 3363.17)],\n", 256 | " [(28, 70.54), (20, 0.24), (26, 20.09)],\n", 257 | " [(33, 145.8), (24, 9.81), (98, 3523.33)],\n", 258 | " [(31, 27.06), (28, 36.65), (56, 626.04)],\n", 259 | " [(40, 124.22), (39, 136.32), (72, 1447.22)],\n", 260 | " [(33, 22.37), (26, 2.66), (52, 336.73)],\n", 261 | " [(28, 14.25), (26, 1.8), (66, 875.19)],\n", 262 | " [(35, 45.55), (32, 36.58), (70, 1343.63)],\n", 263 | " [(42, 122.0), (27, 0.01), (47, 135.78)],\n", 264 | " [(43, 246.24), (35, 48.1), (65, 480.55)],\n", 265 | " [(36, 15.52), (34, 21.79), (82, 2538.18)],\n", 266 | " [(33, 12.61), (32, 4.22), (64, 635.52)],\n", 267 | " [(35, 13.95), (33, 5.61), (98, 2616.03)],\n", 268 | " [(44, 125.88), (36, 20.44), (98, 3350.98)],\n", 269 | " [(35, 1.46), (34, 3.33), (97, 2613.92)],\n", 270 | " [(47, 111.54), (41, 3.23), (81, 1854.73)],\n", 271 | " [(48, 129.45), (42, 51.52), (73, 1075.38)],\n", 272 | " [(50, 78.81), (41, 2.09), (52, 17.57)],\n", 273 | " [(57, 260.46), (54, 101.08), (71, 1171.6)],\n", 274 | " [(46, 80.49), (38, 0.36), (75, 269.97)],\n", 275 | " [(42, 8.78), (40, 1.79), (93, 2767.85)],\n", 276 | " [(41, 1.34), (40, 0.95), (50, 39.88)],\n", 277 | " [(54, 53.46), (47, 28.57), (75, 548.68)],\n", 278 | " [(54, 162.24), (46, 0.28), (53, 18.23)],\n", 279 | " [(72, 437.49), (47, 10.08), (59, 141.86)],\n", 280 | " [(60, 116.23), (54, 95.06), (98, 2984.83)],\n", 281 | " [(47, 2.14), (46, 1.56), (91, 807.39)],\n", 282 | " [(49, 15.51), (47, 3.68), (58, 79.93)],\n", 283 | " [(67, 65.48), (57, 27.5), (52, 22.68)],\n", 284 | " [(61, 172.64), (56, 49.31), (50, 2.82)],\n", 285 | " [(60, 66.44), (59, 34.52), (99, 2564.12)],\n", 286 | " [(56, 10.89), (50, 0.51), (78, 53.79)],\n", 287 | " [(55, 20.1), (53, 1.38), (85, 251.76)],\n", 288 | " [(60, 73.79), (59, 23.67), (98, 2110.67)],\n", 289 | " [(66, 123.03), (64, 102.41), (94, 1471.8)],\n", 290 | " [(67, 88.35), (56, 4.33), (72, 22.85)],\n", 291 | " [(73, 238.61), (59, 24.3), (88, 967.59)],\n", 292 | " [(64, 60.8), (57, 2.13), (84, 86.09)],\n", 293 | " [(61, 11.06), (57, 0.02), (76, 197.03)],\n", 294 | " [(60, 7.01), (58, 0.46), (86, 701.09)],\n", 295 | " [(65, 34.32), (64, 29.85), (83, 556.7)],\n", 296 | " [(71, 0.67), (60, 0.72), (90, 820.66)],\n", 297 | " [(67, 1.63), (65, 4.76), (76, 48.03)],\n", 298 | " [(64, 4.88), (63, 0.95), (98, 1057.59)],\n", 299 | " [(76, 38.43), (64, 2.94), (91, 132.23)],\n", 300 | " [(75, 56.34), (72, 70.08), (66, 4.43)],\n", 301 | " [(76, 11.98), (65, 0.3), (80, 47.73)],\n", 302 | " [(73, 33.23), (66, 0.64), (94, 594.93)],\n", 303 | " [(73, 37.53), (68, 2.66), (98, 395.63)],\n", 304 | " [(70, 0.98), (68, 0.09), (82, 153.53)],\n", 305 | " [(71, 1.66), (70, 3.35), (94, 232.1)],\n", 306 | " [(73, 8.99), (70, 0.06), (99, 247.8)],\n", 307 | " [(73, 8.37), (72, 1.5), (76, 27.18)],\n", 308 | " [(91, 284.64), (74, 8.86), (89, 104.5)],\n", 309 | " [(92, 133.06), (84, 102.77), (76, 15.32)],\n", 310 | " [(90, 243.0), (76, 1.4), (83, 52.22)],\n", 311 | " [(78, 8.08), (76, 0.52), (81, 1.07)],\n", 312 | " [(77, 1.19), (76, 0.81), (92, 68.53)],\n", 313 | " [(78, 2.36), (77, 0.45), (85, 13.18)],\n", 314 | " [(86, 64.32), (78, 0.98), (80, 8.94)],\n", 315 | " [(81, 2.59), (98, 355.9)],\n", 316 | " [(91, 22.35), (85, 1.45), (81, 0.09)],\n", 317 | " [(98, 264.34), (88, 28.78), (92, 121.87)],\n", 318 | " [(92, 99.89), (89, 39.52), (94, 99.78)],\n", 319 | " [(93, 11.99), (88, 28.05), (91, 47.44)],\n", 320 | " [(88, 5.78), (86, 8.75), (94, 114.95)],\n", 321 | " [(98, 121.05), (94, 30.41), (89, 19.14)],\n", 322 | " [(89, 4.9), (87, 2.66), (97, 94.51)],\n", 323 | " [(97, 85.09)],\n", 324 | " [(92, 21.23), (91, 11.14), (88, 0.21)],\n", 325 | " [(98, 6.12), (91, 6.83), (93, 1.31)],\n", 326 | " [(99, 82.12), (97, 36.97)],\n", 327 | " [(99, 50.99), (94, 10.47), (96, 23.53)],\n", 328 | " [(97, 22.17)],\n", 329 | " [(99, 34.68), (97, 11.24), (96, 10.83)],\n", 330 | " [(99, 32.77), (97, 6.71), (94, 0.19)],\n", 331 | " [(96, 2.03), (98, 5.91)],\n", 332 | " [(99, 0.27), (98, 6.17)],\n", 333 | " [(99, 5.87), (97, 0.43), (98, 3.32)],\n", 334 | " [(98, 0.3)],\n", 335 | " [(99, 0.33)],\n", 336 | " [(99, 0.0)],\n", 337 | " ]))" 338 | ] 339 | }, 340 | { 341 | "cell_type": "markdown", 342 | "id": "62b769ff", 343 | "metadata": {}, 344 | "source": [ 345 | "The cost from node 68 to node 71 is 1.66 and so on." 346 | ] 347 | }, 348 | { 349 | "cell_type": "markdown", 350 | "id": "b5e9ff01", 351 | "metadata": {}, 352 | "source": [ 353 | "## Solutions" 354 | ] 355 | }, 356 | { 357 | "cell_type": "markdown", 358 | "id": "e820ddcc", 359 | "metadata": {}, 360 | "source": [ 361 | "### Exercise 1" 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": null, 367 | "id": "95dc60a0", 368 | "metadata": { 369 | "hide-output": false 370 | }, 371 | "outputs": [], 372 | "source": [ 373 | "function value_iteration(graph; dest = maximum(keys(graph)))\n", 374 | " J = Dict(node => (node == dest ? 0.0 : Inf) for node in keys(graph))\n", 375 | " updated = true\n", 376 | " while updated\n", 377 | " updated = false\n", 378 | " for (node, edges) in graph\n", 379 | " node == dest && continue\n", 380 | " best = minimum(cost + J[child] for (child, cost) in edges)\n", 381 | " if best != J[node]\n", 382 | " J[node] = best\n", 383 | " updated = true\n", 384 | " end\n", 385 | " end\n", 386 | " end\n", 387 | " return J\n", 388 | "end\n", 389 | "\n", 390 | "function best_path(J, graph; start = minimum(keys(graph)), dest = maximum(keys(graph)))\n", 391 | " path = Int[]\n", 392 | " cost = 0.0\n", 393 | " current = start\n", 394 | " while current != dest\n", 395 | " push!(path, current)\n", 396 | " edges = graph[current]\n", 397 | " next_node, edge_cost = edges[1]\n", 398 | " best_total = edge_cost + J[next_node]\n", 399 | " for (child, c) in Iterators.drop(edges, 1)\n", 400 | " total = c + J[child]\n", 401 | " if total < best_total\n", 402 | " best_total = total\n", 403 | " next_node = child\n", 404 | " edge_cost = c\n", 405 | " end\n", 406 | " end\n", 407 | " current = next_node\n", 408 | " cost += edge_cost\n", 409 | " end\n", 410 | " push!(path, dest)\n", 411 | " return path, cost\n", 412 | "end\n", 413 | "\n", 414 | "J = value_iteration(graph)\n", 415 | "path, total_cost = best_path(J, graph)\n", 416 | "total_cost = round(total_cost; digits = 2)\n", 417 | "\n", 418 | "for node in path\n", 419 | " println(\"node $node\")\n", 420 | "end\n", 421 | "println(\"Cost: $total_cost\")" 422 | ] 423 | } 424 | ], 425 | "metadata": { 426 | "date": 1766028220.4153385, 427 | "filename": "short_path.md", 428 | "kernelspec": { 429 | "display_name": "Julia", 430 | "language": "julia", 431 | "name": "julia-1.12" 432 | }, 433 | "title": "Shortest Paths" 434 | }, 435 | "nbformat": 4, 436 | "nbformat_minor": 5 437 | } -------------------------------------------------------------------------------- /zreferences.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "47d7ed6b", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "c80d726c", 15 | "metadata": {}, 16 | "source": [ 17 | "# References\n", 18 | "\n", 19 | "\n", 20 | "\\[Aiy94\\] S Rao Aiyagari. Uninsured Idiosyncratic Risk and Aggregate Saving. *The Quarterly Journal of Economics*, 109(3):659–684, 1994.\n", 21 | "\n", 22 | "\n", 23 | "\\[AM05\\] D. B. O. Anderson and J. B. Moore. *Optimal Filtering*. Dover Publications, 2005.\n", 24 | "\n", 25 | "\n", 26 | "\\[AHMS96\\] E. W. Anderson, L. P. Hansen, E. R. McGrattan, and T. J. Sargent. Mechanics of Forming and Estimating Dynamic Linear Economies. In *Handbook of Computational Economics*. Elsevier, vol 1 edition, 1996.\n", 27 | "\n", 28 | "\n", 29 | "\\[Are08\\] Cristina Arellano. Default risk and income fluctuations in emerging economies. *The American Economic Review*, pages 690–712, 2008.\n", 30 | "\n", 31 | "\n", 32 | "\\[Bar79\\] Robert J Barro. On the Determination of the Public Debt. *Journal of Political Economy*, 87(5):940–971, 1979.\n", 33 | "\n", 34 | "\n", 35 | "\\[BB18\\] Jess Benhabib and Alberto Bisin. Skewed wealth distributions: theory and empirics. *Journal of Economic Literature*, 56(4):1261–91, 2018.\n", 36 | "\n", 37 | "\n", 38 | "\\[BBZ15\\] Jess Benhabib, Alberto Bisin, and Shenghao Zhu. The wealth distribution in bewley economies with capital income risk. *Journal of Economic Theory*, 159:489–515, 2015.\n", 39 | "\n", 40 | "\n", 41 | "\\[BS79\\] L M Benveniste and J A Scheinkman. On the Differentiability of the Value Function in Dynamic Models of Economics. *Econometrica*, 47(3):727–732, 1979.\n", 42 | "\n", 43 | "\n", 44 | "\\[Ber75\\] Dmitri Bertsekas. *Dynamic Programming and Stochastic Control*. Academic Press, New York, 1975.\n", 45 | "\n", 46 | "\n", 47 | "\\[Bew77\\] Truman Bewley. The permanent income hypothesis: a theoretical formulation. *Journal of Economic Theory*, 16(2):252–292, 1977.\n", 48 | "\n", 49 | "\n", 50 | "\\[Bew86\\] Truman F Bewley. Stationary monetary equilibrium with a continuum of independently fluctuating consumers. In Werner Hildenbran and Andreu Mas-Colell, editors, *Contributions to Mathematical Economics in Honor of Gerard Debreu*, pages 27–102. North-Holland, Amsterdam, 1986.\n", 51 | "\n", 52 | "\n", 53 | "\\[Bis06\\] C. M. Bishop. *Pattern Recognition and Machine Learning*. Springer, 2006.\n", 54 | "\n", 55 | "\n", 56 | "\\[Car01\\] Christopher D Carroll. A Theory of the Consumption Function, with and without Liquidity Constraints. *Journal of Economic Perspectives*, 15(3):23–45, 2001.\n", 57 | "\n", 58 | "\n", 59 | "\\[Car06\\] Christopher D Carroll. The method of endogenous gridpoints for solving dynamic stochastic optimization problems. *Economics Letters*, 91(3):312–320, 2006.\n", 60 | "\n", 61 | "\n", 62 | "\\[Col90\\] Wilbur John Coleman. Solving the Stochastic Growth Model by Policy-Function Iteration. *Journal of Business & Economic Statistics*, 8(1):27–29, 1990.\n", 63 | "\n", 64 | "\n", 65 | "\\[DFH06\\] Steven J Davis, R Jason Faberman, and John Haltiwanger. The flow approach to labor markets: new data sources, micro-macro links and the recent downturn. *Journal of Economic Perspectives*, 2006.\n", 66 | "\n", 67 | "\n", 68 | "\\[Dea91\\] Angus Deaton. Saving and Liquidity Constraints. *Econometrica*, 59(5):1221–1248, 1991.\n", 69 | "\n", 70 | "\n", 71 | "\\[DP94\\] Angus Deaton and Christina Paxson. Intertemporal Choice and Inequality. *Journal of Political Economy*, 102(3):437–467, 1994.\n", 72 | "\n", 73 | "\n", 74 | "\\[DH10\\] Wouter J Den Haan. Comparison of solutions to the incomplete markets model with aggregate uncertainty. *Journal of Economic Dynamics and Control*, 34(1):4–27, 2010.\n", 75 | "\n", 76 | "\n", 77 | "\\[DJ92\\] Raymond J Deneckere and Kenneth L Judd. Cyclical and chaotic behavior in a dynamic equilibrium model, with implications for fiscal policy. *Cycles and chaos in economic equilibrium*, pages 308–329, 1992.\n", 78 | "\n", 79 | "\n", 80 | "\\[DS10\\] Ulrich Doraszelski and Mark Satterthwaite. Computable markov-perfect industry dynamics. *The RAND Journal of Economics*, 41(2):215–243, 2010.\n", 81 | "\n", 82 | "\n", 83 | "\\[DLP13\\] Y E Du, Ehud Lehrer, and A D Y Pauzner. Competitive economy as a ranking device over networks. submitted, 2013.\n", 84 | "\n", 85 | "\n", 86 | "\\[Dud02\\] R M Dudley. *Real Analysis and Probability*. Cambridge Studies in Advanced Mathematics. Cambridge University Press, 2002.\n", 87 | "\n", 88 | "\n", 89 | "\\[EG87\\] Robert F Engle and Clive W J Granger. Co-integration and Error Correction: Representation, Estimation, and Testing. *Econometrica*, 55(2):251–276, 1987.\n", 90 | "\n", 91 | "\n", 92 | "\\[EP95\\] Richard Ericson and Ariel Pakes. Markov-perfect industry dynamics: a framework for empirical work. *The Review of Economic Studies*, 62(1):53–82, 1995.\n", 93 | "\n", 94 | "\n", 95 | "\\[EH01\\] G W Evans and S Honkapohja. *Learning and Expectations in Macroeconomics*. Frontiers of Economic Research. Princeton University Press, 2001.\n", 96 | "\n", 97 | "\n", 98 | "\\[FSTD15\\] Pablo Fajgelbaum, Edouard Schaal, and Mathieu Taschereau-Dumouchel. Uncertainty traps. Technical Report, National Bureau of Economic Research, 2015.\n", 99 | "\n", 100 | "\n", 101 | "\\[FVJ20\\] Jesús Fernández-Villaverde and Charles I Jones. Estimating and simulating a sird model of covid-19 for many countries, states, and cities. Working Paper 27128, National Bureau of Economic Research, May 2020. URL: [http://www.nber.org/papers/w27128](http://www.nber.org/papers/w27128), [doi:10.3386/w27128](https://doi.org/10.3386/w27128).\n", 102 | "\n", 103 | "\n", 104 | "\\[Fri56\\] M. Friedman. *A Theory of the Consumption Function*. Princeton University Press, 1956.\n", 105 | "\n", 106 | "\n", 107 | "\\[FF98\\] Milton Friedman and Rose D Friedman. *Two Lucky People*. University of Chicago Press, 1998.\n", 108 | "\n", 109 | "\n", 110 | "\\[Gab09\\] Xavier Gabaix. Power laws in economics and finance. *Annual Review of Economics*, 1(1):255–294, 2009. [doi:10.1146/annurev.economics.050708.142940](https://doi.org/10.1146/annurev.economics.050708.142940).\n", 111 | "\n", 112 | "\n", 113 | "\\[Gal37\\] Albert Gallatin. Report on the finances**, november, 1807. In *Reports of the Secretary of the Treasury of the United States, Vol 1*. Government printing office, Washington, DC, 1837.\n", 114 | "\n", 115 | "\n", 116 | "\\[Hal78\\] Robert E Hall. Stochastic Implications of the Life Cycle-Permanent Income Hypothesis: Theory and Evidence. *Journal of Political Economy*, 86(6):971–987, 1978.\n", 117 | "\n", 118 | "\n", 119 | "\\[HM82\\] Robert E Hall and Frederic S Mishkin. The Sensitivity of Consumption to Transitory Income: Estimates from Panel Data on Households. *National Bureau of Economic Research Working Paper Series*, 1982.\n", 120 | "\n", 121 | "\n", 122 | "\\[Ham05\\] James D Hamilton. What's real about the business cycle? *Federal Reserve Bank of St. Louis Review*, pages 435–452, 2005.\n", 123 | "\n", 124 | "\n", 125 | "\\[HS08\\] L P Hansen and T J Sargent. *Robustness*. Princeton University Press, 2008.\n", 126 | "\n", 127 | "\n", 128 | "\\[HS13\\] L P Hansen and T J Sargent. *Recursive Models of Dynamic Linear Economies*. The Gorman Lectures in Economics. Princeton University Press, 2013.\n", 129 | "\n", 130 | "\n", 131 | "\\[HR87\\] Lars Peter Hansen and Scott F Richard. The Role of Conditioning Information in Deducing Testable. *Econometrica*, 55(3):587–613, May 1987.\n", 132 | "\n", 133 | "\n", 134 | "\\[HS00\\] Lars Peter Hansen and Thomas J Sargent. Wanting robustness in macroeconomics. *Manuscript, Department of Economics, Stanford University.*, 2000.\n", 135 | "\n", 136 | "\n", 137 | "\\[HK78\\] J. Michael Harrison and David M. Kreps. Speculative investor behavior in a stock market with heterogeneous expectations. *The Quarterly Journal of Economics*, 92(2):323–336, 1978.\n", 138 | "\n", 139 | "\n", 140 | "\\[HK79\\] J. Michael Harrison and David M. Kreps. Martingales and arbitrage in multiperiod securities markets. *Journal of Economic Theory*, 20(3):381–408, June 1979.\n", 141 | "\n", 142 | "\n", 143 | "\\[HL96\\] John Heaton and Deborah J Lucas. Evaluating the effects of incomplete markets on risk sharing and asset pricing. *Journal of Political Economy*, pages 443–487, 1996.\n", 144 | "\n", 145 | "\n", 146 | "\\[HSW05\\] Jane M Heffernan, Robert J Smith, and Lindi M Wahl. Perspectives on the basic reproductive ratio. *Journal of the Royal Society Interface*, 2(4):281–293, 2005.\n", 147 | "\n", 148 | "\n", 149 | "\\[HK85\\] Elhanan Helpman and Paul Krugman. *Market structure and international trade*. MIT Press Cambridge, 1985.\n", 150 | "\n", 151 | "\n", 152 | "\\[HLL96\\] O Hernandez-Lerma and J B Lasserre. *Discrete-Time Markov Control Processes: Basic Optimality Criteria*. Number Vol 1 in Applications of Mathematics Stochastic Modelling and Applied Probability. Springer, 1996.\n", 153 | "\n", 154 | "\n", 155 | "\\[HP92\\] Hugo A Hopenhayn and Edward C Prescott. Stochastic Monotonicity and Stationary Distributions for Dynamic Economies. *Econometrica*, 60(6):1387–1406, 1992.\n", 156 | "\n", 157 | "\n", 158 | "\\[HR93\\] Hugo A Hopenhayn and Richard Rogerson. Job Turnover and Policy Evaluation: A General Equilibrium Analysis. *Journal of Political Economy*, 101(5):915–938, 1993.\n", 159 | "\n", 160 | "\n", 161 | "\\[Hug93\\] Mark Huggett. The risk-free rate in heterogeneous-agent incomplete-insurance economies. *Journal of Economic Dynamics and Control*, 17(5-6):953–969, 1993.\n", 162 | "\n", 163 | "\n", 164 | "\\[Haggstrom02\\] Olle Häggström. *Finite Markov chains and algorithmic applications*. Volume 52. Cambridge University Press, 2002.\n", 165 | "\n", 166 | "\n", 167 | "\\[Janich94\\] K Jänich. *Linear Algebra*. Springer Undergraduate Texts in Mathematics and Technology. Springer, 1994.\n", 168 | "\n", 169 | "\n", 170 | "\\[JYC88\\] Robert J. Shiller John Y. Campbell. The Dividend-Price Ratio and Expectations of Future Dividends and Discount Factors. *Review of Financial Studies*, 1(3):195–228, 1988.\n", 171 | "\n", 172 | "\n", 173 | "\\[Jud90\\] K L Judd. Cournot versus bertrand: a dynamic resolution. Technical Report, Hoover Institution, Stanford University, 1990.\n", 174 | "\n", 175 | "\n", 176 | "\\[Jud85\\] Kenneth L Judd. On the performance of patents. *Econometrica*, pages 567–585, 1985.\n", 177 | "\n", 178 | "\n", 179 | "\\[Kam12\\] Takashi Kamihigashi. Elementary results on solutions to the bellman equation of dynamic programming: existence, uniqueness, and convergence. Technical Report, Kobe University, 2012.\n", 180 | "\n", 181 | "\n", 182 | "\\[Kre88\\] David M. Kreps. *Notes on the Theory of Choice*. Westview Press, Boulder, Colorado, 1988.\n", 183 | "\n", 184 | "\n", 185 | "\\[Kuh13\\] Moritz Kuhn. Recursive Equilibria In An Aiyagari-Style Economy With Permanent Income Shocks. *International Economic Review*, 54:807–835, 2013.\n", 186 | "\n", 187 | "\n", 188 | "\\[LM94\\] A Lasota and M C MacKey. *Chaos, Fractals, and Noise: Stochastic Aspects of Dynamics*. Applied Mathematical Sciences. Springer-Verlag, 1994.\n", 189 | "\n", 190 | "\n", 191 | "\\[LL01\\] Martin Lettau and Sydney Ludvigson. Consumption, Aggregate Wealth, and Expected Stock Returns. *Journal of Finance*, 56(3):815–849, 06 2001.\n", 192 | "\n", 193 | "\n", 194 | "\\[LL04\\] Martin Lettau and Sydney C. Ludvigson. Understanding Trend and Cycle in Asset Values: Reevaluating the Wealth Effect on Consumption. *American Economic Review*, 94(1):276–299, March 2004.\n", 195 | "\n", 196 | "\n", 197 | "\\[LM80\\] David Levhari and Leonard J Mirman. The great fish war: an example using a dynamic cournot-nash solution. *The Bell Journal of Economics*, pages 322–334, 1980.\n", 198 | "\n", 199 | "\n", 200 | "\\[LS18\\] L Ljungqvist and T J Sargent. *Recursive Macroeconomic Theory*. MIT Press, 4 edition, 2018.\n", 201 | "\n", 202 | "\n", 203 | "\\[Luc78\\] Robert E Lucas, Jr. Asset prices in an exchange economy. *Econometrica: Journal of the Econometric Society*, 46(6):1429–1445, 1978.\n", 204 | "\n", 205 | "\n", 206 | "\\[LP71\\] Robert E Lucas, Jr. and Edward C Prescott. Investment under uncertainty. *Econometrica: Journal of the Econometric Society*, pages 659–681, 1971.\n", 207 | "\n", 208 | "\n", 209 | "\\[LS83\\] Robert E Lucas, Jr. and Nancy L Stokey. Optimal Fiscal and Monetary Policy in an Economy without Capital. *Journal of monetary Economics*, 12(3):55–93, 1983.\n", 210 | "\n", 211 | "\n", 212 | "\\[MS89\\] Albert Marcet and Thomas J Sargent. Convergence of Least-Squares Learning in Environments with Hidden State Variables and Private Information. *Journal of Political Economy*, 97(6):1306–1322, 1989.\n", 213 | "\n", 214 | "\n", 215 | "\\[MdRV10\\] V Filipe Martins-da-Rocha and Yiannis Vailakis. Existence and Uniqueness of a Fixed Point for Local Contractions. *Econometrica*, 78(3):1127–1141, 2010.\n", 216 | "\n", 217 | "\n", 218 | "\\[MCWG95\\] A Mas-Colell, M D Whinston, and J R Green. *Microeconomic Theory*. Volume 1. Oxford University Press, 1995.\n", 219 | "\n", 220 | "\n", 221 | "\\[McC70\\] J J McCall. Economics of Information and Job Search. *The Quarterly Journal of Economics*, 84(1):113–126, 1970.\n", 222 | "\n", 223 | "\n", 224 | "\\[MT09\\] S P Meyn and R L Tweedie. *Markov Chains and Stochastic Stability*. Cambridge University Press, 2009.\n", 225 | "\n", 226 | "\n", 227 | "\\[MF02\\] Mario J Miranda and P L Fackler. *Applied Computational Economics and Finance*. Cambridge: MIT Press, 2002.\n", 228 | "\n", 229 | "\n", 230 | "\\[MB54\\] F. Modigliani and R. Brumberg. Utility analysis and the consumption function: An interpretation of cross-section data. In K.K Kurihara, editor, *Post-Keynesian Economics*. 1954.\n", 231 | "\n", 232 | "\n", 233 | "\\[Nea99\\] Derek Neal. The Complexity of Job Mobility among Young Men. *Journal of Labor Economics*, 17(2):237–261, 1999.\n", 234 | "\n", 235 | "\n", 236 | "\\[Par99\\] Jonathan A Parker. The Reaction of Household Consumption to Predictable Changes in Social Security Taxes. *American Economic Review*, 89(4):959–973, 1999.\n", 237 | "\n", 238 | "\n", 239 | "\\[Per19\\] Jesse Perla. A model of product awareness and industry life cycles. Working Paper, University of British Columbia, 2019.\n", 240 | "\n", 241 | "\n", 242 | "\\[Put05\\] Martin L Puterman. *Markov decision processes: discrete stochastic dynamic programming*. John Wiley & Sons, 2005.\n", 243 | "\n", 244 | "\n", 245 | "\\[PalS13\\] Jenő Pál and John Stachurski. Fitted value function iteration with probability one contractions. *Journal of Economic Dynamics and Control*, 37(1):251–264, 2013.\n", 246 | "\n", 247 | "\n", 248 | "\\[Rab02\\] Guillaume Rabault. When do borrowing constraints bind? Some new results on the income fluctuation problem. *Journal of Economic Dynamics and Control*, 26(2):217–245, 2002.\n", 249 | "\n", 250 | "\n", 251 | "\\[Rei09\\] Michael Reiter. Solving heterogeneous-agent models by projection and perturbation. *Journal of Economic Dynamics and Control*, 33(3):649–665, 2009.\n", 252 | "\n", 253 | "\n", 254 | "\\[Rom05\\] Steven Roman. *Advanced linear algebra*. Volume 3. Springer, 2005.\n", 255 | "\n", 256 | "\n", 257 | "\\[Rus96\\] John Rust. Numerical dynamic programming in economics. *Handbook of computational economics*, 1:619–729, 1996.\n", 258 | "\n", 259 | "\n", 260 | "\\[Rya12\\] Stephen P Ryan. The costs of environmental regulation in a concentrated industry. *Econometrica*, 80(3):1019–1061, 2012.\n", 261 | "\n", 262 | "\n", 263 | "\\[Sar87\\] Thomas J Sargent. *Macroeconomic Theory*. Academic Press, New York, 2nd edition, 1987.\n", 264 | "\n", 265 | "\n", 266 | "\\[SE77\\] Jack Schechtman and Vera L S Escudero. Some results on an income fluctuation problem. *Journal of Economic Theory*, 16(2):151–166, 1977.\n", 267 | "\n", 268 | "\n", 269 | "\\[Sch14\\] Jose A. Scheinkman. *Speculation, Trading, and Bubbles*. Columbia University Press, New York, 2014.\n", 270 | "\n", 271 | "\n", 272 | "\\[Sch69\\] Thomas C Schelling. Models of Segregation. *American Economic Review*, 59(2):488–493, 1969.\n", 273 | "\n", 274 | "\n", 275 | "\\[SR14\\] Alexander A. Stepanov and Daniel E. Rose. *From mathematics to generic programming*. Addison-Wesley, 2014. ISBN 978-0-321-94204-3.\n", 276 | "\n", 277 | "\n", 278 | "\\[SLP89\\] N L Stokey, R E Lucas, and E C Prescott. *Recursive Methods in Economic Dynamics*. Harvard University Press, 1989.\n", 279 | "\n", 280 | "\n", 281 | "\\[STY04\\] Kjetil Storesletten, Christopher I Telmer, and Amir Yaron. Consumption and risk sharing over the life cycle. *Journal of Monetary Economics*, 51(3):609–633, 2004.\n", 282 | "\n", 283 | "\n", 284 | "\\[Sun96\\] R K Sundaram. *A First Course in Optimization Theory*. Cambridge University Press, 1996.\n", 285 | "\n", 286 | "\n", 287 | "\\[Tau86\\] George Tauchen. Finite state markov-chain approximations to univariate and vector autoregressions. *Economics Letters*, 20(2):177–181, 1986.\n", 288 | "\n", 289 | "\n", 290 | "\\[VL11\\] Ngo Van Long. Dynamic games in the economics of natural resources: a survey. *Dynamic Games and Applications*, 1(1):115–148, 2011.\n", 291 | "\n", 292 | "\n", 293 | "\\[Wal47\\] Abraham Wald. *Sequential Analysis*. John Wiley and Sons, New York, 1947.\n", 294 | "\n", 295 | "\n", 296 | "\\[YS05\\] G Alastair Young and Richard L Smith. *Essentials of statistical inference*. Cambridge University Press, 2005." 297 | ] 298 | } 299 | ], 300 | "metadata": { 301 | "date": 1766028222.40479, 302 | "filename": "zreferences.md", 303 | "kernelspec": { 304 | "display_name": "Julia", 305 | "language": "julia", 306 | "name": "julia-1.12" 307 | }, 308 | "title": "References" 309 | }, 310 | "nbformat": 4, 311 | "nbformat_minor": 5 312 | } -------------------------------------------------------------------------------- /dynamic_programming/egm_policy_iter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "6d27621b", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "e83e84e7", 15 | "metadata": {}, 16 | "source": [ 17 | "# Optimal Growth III: The Endogenous Grid Method" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "id": "288da64b", 23 | "metadata": {}, 24 | "source": [ 25 | "## Contents\n", 26 | "\n", 27 | "- [Optimal Growth III: The Endogenous Grid Method](#Optimal-Growth-III:-The-Endogenous-Grid-Method) \n", 28 | " - [Overview](#Overview) \n", 29 | " - [Key Idea](#Key-Idea) \n", 30 | " - [Implementation](#Implementation) \n", 31 | " - [Speed](#Speed) " 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "id": "70dfc847", 37 | "metadata": {}, 38 | "source": [ 39 | "## Overview\n", 40 | "\n", 41 | "We solved the stochastic optimal growth model using\n", 42 | "\n", 43 | "1. [value function iteration](https://julia.quantecon.org/optgrowth.html) \n", 44 | "1. [Euler equation based time iteration](https://julia.quantecon.org/coleman_policy_iter.html) \n", 45 | "\n", 46 | "\n", 47 | "We found time iteration to be significantly more accurate at each step.\n", 48 | "\n", 49 | "In this lecture we’ll look at an ingenious twist on the time iteration technique called the **endogenous grid method** (EGM).\n", 50 | "\n", 51 | "EGM is a numerical method for implementing policy iteration invented by [Chris Carroll](http://www.econ2.jhu.edu/people/ccarroll/).\n", 52 | "\n", 53 | "It is a good example of how a clever algorithm can save a massive amount of computer time.\n", 54 | "\n", 55 | "(Massive when we multiply saved CPU cycles on each implementation times the number of implementations worldwide)\n", 56 | "\n", 57 | "The original reference is [[Car06](https://julia.quantecon.org/../zreferences.html#id70)]." 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "id": "e806944f", 63 | "metadata": {}, 64 | "source": [ 65 | "## Key Idea\n", 66 | "\n", 67 | "Let’s start by reminding ourselves of the theory and then see how the numerics fit in." 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "id": "2c1af87e", 73 | "metadata": {}, 74 | "source": [ 75 | "### Theory\n", 76 | "\n", 77 | "Take the model set out in [the time iteration lecture](https://julia.quantecon.org/coleman_policy_iter.html), following the same terminology and notation.\n", 78 | "\n", 79 | "The Euler equation is\n", 80 | "\n", 81 | "\n", 82 | "\n", 83 | "$$\n", 84 | "(u'\\circ c^*)(y)\n", 85 | "= \\beta \\int (u'\\circ c^*)(f(y - c^*(y)) z) f'(y - c^*(y)) z \\phi(dz) \\tag{38.1}\n", 86 | "$$\n", 87 | "\n", 88 | "As we saw, the Coleman operator is a nonlinear operator $ K $ engineered so that $ c^* $ is a fixed point of $ K $.\n", 89 | "\n", 90 | "It takes as its argument a continuous strictly increasing consumption policy $ g \\in \\Sigma $.\n", 91 | "\n", 92 | "It returns a new function $ Kg $, where $ (Kg)(y) $ is the $ c \\in (0, \\infty) $ that solves\n", 93 | "\n", 94 | "\n", 95 | "\n", 96 | "$$\n", 97 | "u'(c)\n", 98 | "= \\beta \\int (u' \\circ g) (f(y - c) z ) f'(y - c) z \\phi(dz) \\tag{38.2}\n", 99 | "$$" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "id": "7019bc01", 105 | "metadata": {}, 106 | "source": [ 107 | "### Exogenous Grid\n", 108 | "\n", 109 | "As discussed in [the lecture on time iteration](https://julia.quantecon.org/coleman_policy_iter.html), to implement the method on a computer we need numerical approximation.\n", 110 | "\n", 111 | "In particular, we represent a policy function by a set of values on a finite grid.\n", 112 | "\n", 113 | "The function itself is reconstructed from this representation when necessary, using interpolation or some other method.\n", 114 | "\n", 115 | "[Previously](https://julia.quantecon.org/coleman_policy_iter.html), to obtain a finite representation of an updated consumption policy we\n", 116 | "\n", 117 | "- fixed a grid of income points $ \\{y_i\\} $ \n", 118 | "- calculated the consumption value $ c_i $ corresponding to each\n", 119 | " $ y_i $ using [(38.2)](#equation-egm-coledef) and a root finding routine \n", 120 | "\n", 121 | "\n", 122 | "Each $ c_i $ is then interpreted as the value of the function $ K g $ at $ y_i $.\n", 123 | "\n", 124 | "Thus, with the points $ \\{y_i, c_i\\} $ in hand, we can reconstruct $ Kg $ via approximation.\n", 125 | "\n", 126 | "Iteration then continues…" 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "id": "01c732f1", 132 | "metadata": {}, 133 | "source": [ 134 | "### Endogenous Grid\n", 135 | "\n", 136 | "The method discussed above requires a root finding routine to find the\n", 137 | "$ c_i $ corresponding to a given income value $ y_i $.\n", 138 | "\n", 139 | "Root finding is costly because it typically involves a significant number of\n", 140 | "function evaluations.\n", 141 | "\n", 142 | "As pointed out by Carroll [[Car06](https://julia.quantecon.org/../zreferences.html#id70)], we can avoid this if\n", 143 | "$ y_i $ is chosen endogenously.\n", 144 | "\n", 145 | "The only assumption required is that $ u' $ is invertible on $ (0, \\infty) $.\n", 146 | "\n", 147 | "The idea is this:\n", 148 | "\n", 149 | "First we fix an *exogenous* grid $ \\{k_i\\} $ for capital ($ k = y - c $).\n", 150 | "\n", 151 | "Then we obtain $ c_i $ via\n", 152 | "\n", 153 | "\n", 154 | "\n", 155 | "$$\n", 156 | "c_i =\n", 157 | "(u')^{-1}\n", 158 | "\\left\\{\n", 159 | " \\beta \\int (u' \\circ g) (f(k_i) z ) \\, f'(k_i) \\, z \\, \\phi(dz)\n", 160 | "\\right\\} \\tag{38.3}\n", 161 | "$$\n", 162 | "\n", 163 | "where $ (u')^{-1} $ is the inverse function of $ u' $.\n", 164 | "\n", 165 | "Finally, for each $ c_i $ we set $ y_i = c_i + k_i $.\n", 166 | "\n", 167 | "It is clear that each $ (y_i, c_i) $ pair constructed in this manner satisfies [(38.2)](#equation-egm-coledef).\n", 168 | "\n", 169 | "With the points $ \\{y_i, c_i\\} $ in hand, we can reconstruct $ Kg $ via approximation as before.\n", 170 | "\n", 171 | "The name EGM comes from the fact that the grid $ \\{y_i\\} $ is determined **endogenously**." 172 | ] 173 | }, 174 | { 175 | "cell_type": "markdown", 176 | "id": "9edaa9ab", 177 | "metadata": {}, 178 | "source": [ 179 | "## Implementation\n", 180 | "\n", 181 | "Let’s implement this version of the Coleman operator and see how it performs." 182 | ] 183 | }, 184 | { 185 | "cell_type": "markdown", 186 | "id": "d8ff74b1", 187 | "metadata": {}, 188 | "source": [ 189 | "### The Operator\n", 190 | "\n", 191 | "Here’s an implementation of $ K $ using EGM as described above." 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": null, 197 | "id": "efa61d42", 198 | "metadata": { 199 | "hide-output": false 200 | }, 201 | "outputs": [], 202 | "source": [ 203 | "using LinearAlgebra, Statistics\n", 204 | "using BenchmarkTools, Interpolations, LaTeXStrings, Plots, Random, Roots" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": null, 210 | "id": "0664b512", 211 | "metadata": { 212 | "hide-output": false 213 | }, 214 | "outputs": [], 215 | "source": [ 216 | "function coleman_egm(g, k_grid, beta, u_prime, u_prime_inv, f, f_prime, shocks)\n", 217 | "\n", 218 | " # Allocate memory for value of consumption on endogenous grid points\n", 219 | " c = similar(k_grid)\n", 220 | "\n", 221 | " # Solve for updated consumption value\n", 222 | " for (i, k) in enumerate(k_grid)\n", 223 | " vals = u_prime.(g.(f(k) * shocks)) .* f_prime(k) .* shocks\n", 224 | " c[i] = u_prime_inv(beta * mean(vals))\n", 225 | " end\n", 226 | "\n", 227 | " # Determine endogenous grid\n", 228 | " y = k_grid + c # y_i = k_i + c_i\n", 229 | "\n", 230 | " # Update policy function and return\n", 231 | " Kg = LinearInterpolation(y, c, extrapolation_bc = Line())\n", 232 | " Kg_f(x) = Kg(x)\n", 233 | " return Kg_f\n", 234 | "end" 235 | ] 236 | }, 237 | { 238 | "cell_type": "markdown", 239 | "id": "d697af2c", 240 | "metadata": {}, 241 | "source": [ 242 | "Note the lack of any root finding algorithm.\n", 243 | "\n", 244 | "We’ll also run our original implementation, which uses an exogenous grid and requires root finding, so we can perform some comparisons" 245 | ] 246 | }, 247 | { 248 | "cell_type": "code", 249 | "execution_count": null, 250 | "id": "d7c7ef36", 251 | "metadata": { 252 | "hide-output": false 253 | }, 254 | "outputs": [], 255 | "source": [ 256 | "function K!(Kg, g, grid, beta, u_prime, f, f_prime, shocks)\n", 257 | "\n", 258 | " # This function requires the container of the output value as argument Kg\n", 259 | "\n", 260 | " # Construct linear interpolation object #\n", 261 | " g_func = LinearInterpolation(grid, g, extrapolation_bc = Line())\n", 262 | "\n", 263 | " # solve for updated consumption value #\n", 264 | " for (i, y) in enumerate(grid)\n", 265 | " function h(c)\n", 266 | " vals = u_prime.(g_func.(f(y - c) * shocks)) .* f_prime(y - c) .*\n", 267 | " shocks\n", 268 | " return u_prime(c) - beta * mean(vals)\n", 269 | " end\n", 270 | " Kg[i] = find_zero(h, (1e-10, y - 1e-10))\n", 271 | " end\n", 272 | " return Kg\n", 273 | "end\n", 274 | "\n", 275 | "# The following function does NOT require the container of the output value as argument\n", 276 | "function K(g, grid, beta, u_prime, f, f_prime, shocks)\n", 277 | " K!(similar(g), g, grid, beta, u_prime, f, f_prime, shocks)\n", 278 | "end" 279 | ] 280 | }, 281 | { 282 | "cell_type": "markdown", 283 | "id": "78d0ee57", 284 | "metadata": {}, 285 | "source": [ 286 | "Let’s test out the code above on some example parameterizations, after the following imports." 287 | ] 288 | }, 289 | { 290 | "cell_type": "markdown", 291 | "id": "233340c9", 292 | "metadata": {}, 293 | "source": [ 294 | "### Testing on the Log / Cobb–Douglas case\n", 295 | "\n", 296 | "As we [did for value function iteration](https://julia.quantecon.org/optgrowth.html) and [time iteration](https://julia.quantecon.org/coleman_policy_iter.html), let’s start by testing our method with the log-linear benchmark.\n", 297 | "\n", 298 | "The first step is to bring in the model that we used in the [Coleman policy function iteration](https://julia.quantecon.org/coleman_policy_iter.html)" 299 | ] 300 | }, 301 | { 302 | "cell_type": "code", 303 | "execution_count": null, 304 | "id": "7e07f18a", 305 | "metadata": { 306 | "hide-output": false 307 | }, 308 | "outputs": [], 309 | "source": [ 310 | "# model\n", 311 | "\n", 312 | "function Model(; alpha = 0.65, # productivity parameter\n", 313 | " beta = 0.95, # discount factor\n", 314 | " gamma = 1.0, # risk aversion\n", 315 | " mu = 0.0, # lognorm(mu, sigma)\n", 316 | " s = 0.1, # lognorm(mu, sigma)\n", 317 | " grid_min = 1e-6, # smallest grid point\n", 318 | " grid_max = 4.0, # largest grid point\n", 319 | " grid_size = 200, # grid size\n", 320 | " u = gamma == 1 ? log : c -> (c^(1 - gamma) - 1) / (1 - gamma), # utility function\n", 321 | " u_prime = c -> c^(-gamma), # u'\n", 322 | " f = k -> k^alpha, # production function\n", 323 | " f_prime = k -> alpha * k^(alpha - 1), # f'\n", 324 | " grid = range(grid_min, grid_max, length = grid_size)) # grid\n", 325 | " return (; alpha, beta, gamma, mu, s, grid_min, grid_max, grid_size, u,\n", 326 | " u_prime,\n", 327 | " f, f_prime, grid)\n", 328 | "end" 329 | ] 330 | }, 331 | { 332 | "cell_type": "markdown", 333 | "id": "cddefd2d", 334 | "metadata": {}, 335 | "source": [ 336 | "Next we generate an instance" 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": null, 342 | "id": "f5fc3cf3", 343 | "metadata": { 344 | "hide-output": false 345 | }, 346 | "outputs": [], 347 | "source": [ 348 | "mlog = Model(); # Log Linear model" 349 | ] 350 | }, 351 | { 352 | "cell_type": "markdown", 353 | "id": "51ebf63f", 354 | "metadata": {}, 355 | "source": [ 356 | "We also need some shock draws for Monte Carlo integration" 357 | ] 358 | }, 359 | { 360 | "cell_type": "code", 361 | "execution_count": null, 362 | "id": "eaa45738", 363 | "metadata": { 364 | "hide-output": false 365 | }, 366 | "outputs": [], 367 | "source": [ 368 | "Random.seed!(42); # For reproducible behavior.\n", 369 | "\n", 370 | "shock_size = 250 # Number of shock draws in Monte Carlo integral\n", 371 | "shocks = exp.(mlog.mu .+ mlog.s * randn(shock_size));" 372 | ] 373 | }, 374 | { 375 | "cell_type": "markdown", 376 | "id": "e8a55e4a", 377 | "metadata": {}, 378 | "source": [ 379 | "As a preliminary test, let’s see if $ K c^* = c^* $, as implied by the theory" 380 | ] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "execution_count": null, 385 | "id": "9a65ed6a", 386 | "metadata": { 387 | "hide-output": false 388 | }, 389 | "outputs": [], 390 | "source": [ 391 | "c_star(y) = (1 - mlog.alpha * mlog.beta) * y\n", 392 | "\n", 393 | "# some useful constants\n", 394 | "ab = mlog.alpha * mlog.beta\n", 395 | "c1 = log(1 - ab) / (1 - mlog.beta)\n", 396 | "c2 = (mlog.mu + mlog.alpha * log(ab)) / (1 - mlog.alpha)\n", 397 | "c3 = 1 / (1 - mlog.beta)\n", 398 | "c4 = 1 / (1 - ab)\n", 399 | "\n", 400 | "v_star(y) = c1 + c2 * (c3 - c4) + c4 * log(y)" 401 | ] 402 | }, 403 | { 404 | "cell_type": "code", 405 | "execution_count": null, 406 | "id": "d01b7de8", 407 | "metadata": { 408 | "hide-output": false 409 | }, 410 | "outputs": [], 411 | "source": [ 412 | "function verify_true_policy(m, shocks, c_star)\n", 413 | " k_grid = m.grid\n", 414 | " c_star_new = coleman_egm(c_star, k_grid, m.beta, m.u_prime, m.u_prime, m.f,\n", 415 | " m.f_prime, shocks)\n", 416 | "\n", 417 | " plt = plot()\n", 418 | " plot!(plt, k_grid, c_star.(k_grid), lw = 2, label = L\"optimal policy $c^*$\")\n", 419 | " plot!(plt, k_grid, c_star_new.(k_grid), lw = 2, label = L\"Kc^*\")\n", 420 | " plot!(plt, legend = :topleft)\n", 421 | "end" 422 | ] 423 | }, 424 | { 425 | "cell_type": "code", 426 | "execution_count": null, 427 | "id": "045c4e69", 428 | "metadata": { 429 | "hide-output": false 430 | }, 431 | "outputs": [], 432 | "source": [ 433 | "verify_true_policy(mlog, shocks, c_star)" 434 | ] 435 | }, 436 | { 437 | "cell_type": "markdown", 438 | "id": "492821bb", 439 | "metadata": {}, 440 | "source": [ 441 | "Notice that we’re passing u_prime to coleman_egm twice.\n", 442 | "\n", 443 | "The reason is that, in the case of log utility, $ u'(c) = (u')^{-1}(c) = 1/c $.\n", 444 | "\n", 445 | "Hence u_prime and u_prime_inv are the same.\n", 446 | "\n", 447 | "We can’t really distinguish the two plots.\n", 448 | "\n", 449 | "In fact it’s easy to see that the difference is essentially zero:" 450 | ] 451 | }, 452 | { 453 | "cell_type": "code", 454 | "execution_count": null, 455 | "id": "abcfe6c2", 456 | "metadata": { 457 | "hide-output": false 458 | }, 459 | "outputs": [], 460 | "source": [ 461 | "c_star_new = coleman_egm(c_star, mlog.grid, mlog.beta, mlog.u_prime,\n", 462 | " mlog.u_prime, mlog.f, mlog.f_prime, shocks)\n", 463 | "maximum(abs(c_star_new(g) - c_star(g)) for g in mlog.grid)" 464 | ] 465 | }, 466 | { 467 | "cell_type": "markdown", 468 | "id": "5708405b", 469 | "metadata": {}, 470 | "source": [ 471 | "Next let’s try iterating from an arbitrary initial condition and see if we\n", 472 | "converge towards $ c^* $.\n", 473 | "\n", 474 | "Let’s start from the consumption policy that eats the whole pie: $ c(y) = y $" 475 | ] 476 | }, 477 | { 478 | "cell_type": "code", 479 | "execution_count": null, 480 | "id": "f852174b", 481 | "metadata": { 482 | "hide-output": false 483 | }, 484 | "outputs": [], 485 | "source": [ 486 | "n = 15\n", 487 | "function check_convergence(m, shocks, c_star, g_init, n_iter)\n", 488 | " k_grid = m.grid\n", 489 | " g = g_init\n", 490 | " plt = plot()\n", 491 | " plot!(plt, m.grid, g.(m.grid),\n", 492 | " color = RGBA(0, 0, 0, 1), lw = 2, alpha = 0.6,\n", 493 | " label = L\"initial condition $c(y) = y$\")\n", 494 | " for i in 1:n_iter\n", 495 | " new_g = coleman_egm(g, k_grid, m.beta, m.u_prime, m.u_prime, m.f,\n", 496 | " m.f_prime,\n", 497 | " shocks)\n", 498 | " g = new_g\n", 499 | " plot!(plt, k_grid, new_g.(k_grid), alpha = 0.6,\n", 500 | " color = RGBA(0, 0, (i / n_iter), 1),\n", 501 | " lw = 2, label = \"\")\n", 502 | " end\n", 503 | "\n", 504 | " plot!(plt, k_grid, c_star.(k_grid),\n", 505 | " color = :black, lw = 2, alpha = 0.8,\n", 506 | " label = L\"true policy function $c^*$\")\n", 507 | " plot!(plt, legend = :topleft)\n", 508 | "end" 509 | ] 510 | }, 511 | { 512 | "cell_type": "code", 513 | "execution_count": null, 514 | "id": "e297ad02", 515 | "metadata": { 516 | "hide-output": false 517 | }, 518 | "outputs": [], 519 | "source": [ 520 | "check_convergence(mlog, shocks, c_star, identity, n)" 521 | ] 522 | }, 523 | { 524 | "cell_type": "markdown", 525 | "id": "75db2666", 526 | "metadata": {}, 527 | "source": [ 528 | "We see that the policy has converged nicely, in only a few steps." 529 | ] 530 | }, 531 | { 532 | "cell_type": "markdown", 533 | "id": "d9bbd89e", 534 | "metadata": {}, 535 | "source": [ 536 | "## Speed\n", 537 | "\n", 538 | "Now let’s compare the clock times per iteration for the standard Coleman\n", 539 | "operator (with exogenous grid) and the EGM version.\n", 540 | "\n", 541 | "We’ll do so using the CRRA model adopted in the exercises of the [Euler equation time iteration lecture](https://julia.quantecon.org/coleman_policy_iter.html).\n", 542 | "\n", 543 | "Here’s the model and some convenient functions" 544 | ] 545 | }, 546 | { 547 | "cell_type": "code", 548 | "execution_count": null, 549 | "id": "cc3fd6fa", 550 | "metadata": { 551 | "hide-output": false 552 | }, 553 | "outputs": [], 554 | "source": [ 555 | "mcrra = Model(alpha = 0.65, beta = 0.95, gamma = 1.5)\n", 556 | "u_prime_inv(c) = c^(-1 / mcrra.gamma)" 557 | ] 558 | }, 559 | { 560 | "cell_type": "markdown", 561 | "id": "61d9296e", 562 | "metadata": {}, 563 | "source": [ 564 | "Here’s the result" 565 | ] 566 | }, 567 | { 568 | "cell_type": "code", 569 | "execution_count": null, 570 | "id": "d07ca661", 571 | "metadata": { 572 | "hide-output": false 573 | }, 574 | "outputs": [], 575 | "source": [ 576 | "function crra_coleman(g, m, shocks)\n", 577 | " K(g, m.grid, m.beta, m.u_prime, m.f, m.f_prime, shocks)\n", 578 | "end\n", 579 | "function crra_coleman_egm(g, m, shocks)\n", 580 | " coleman_egm(g, m.grid, m.beta, m.u_prime,\n", 581 | " u_prime_inv, m.f, m.f_prime, shocks)\n", 582 | "end\n", 583 | "function coleman(m = m, shocks = shocks; sim_length = 20)\n", 584 | " g = m.grid\n", 585 | " for i in 1:sim_length\n", 586 | " g = crra_coleman(g, m, shocks)\n", 587 | " end\n", 588 | " return g\n", 589 | "end\n", 590 | "function egm(m, g = identity, shocks = shocks; sim_length = 20)\n", 591 | " for i in 1:sim_length\n", 592 | " g = crra_coleman_egm(g, m, shocks)\n", 593 | " end\n", 594 | " return g.(m.grid)\n", 595 | "end" 596 | ] 597 | }, 598 | { 599 | "cell_type": "code", 600 | "execution_count": null, 601 | "id": "661b6982", 602 | "metadata": { 603 | "hide-output": false 604 | }, 605 | "outputs": [], 606 | "source": [ 607 | "@benchmark coleman($mcrra)" 608 | ] 609 | }, 610 | { 611 | "cell_type": "code", 612 | "execution_count": null, 613 | "id": "65bfae82", 614 | "metadata": { 615 | "hide-output": false 616 | }, 617 | "outputs": [], 618 | "source": [ 619 | "@benchmark egm($mcrra)" 620 | ] 621 | }, 622 | { 623 | "cell_type": "markdown", 624 | "id": "5bff83ec", 625 | "metadata": {}, 626 | "source": [ 627 | "We see that the EGM version is about 30 times faster.\n", 628 | "\n", 629 | "At the same time, the absence of numerical root finding means that it is\n", 630 | "typically more accurate at each step as well." 631 | ] 632 | } 633 | ], 634 | "metadata": { 635 | "date": 1766028218.3011012, 636 | "filename": "egm_policy_iter.md", 637 | "kernelspec": { 638 | "display_name": "Julia", 639 | "language": "julia", 640 | "name": "julia-1.12" 641 | }, 642 | "title": "Optimal Growth III: The Endogenous Grid Method" 643 | }, 644 | "nbformat": 4, 645 | "nbformat_minor": 5 646 | } -------------------------------------------------------------------------------- /dynamic_programming/mccall_model_with_separation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "9f877d5a", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "90efbfb4", 15 | "metadata": {}, 16 | "source": [ 17 | "# Job Search II: Search and Separation\n", 18 | "\n", 19 | "\n", 20 | "" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "f3e33f08", 26 | "metadata": {}, 27 | "source": [ 28 | "## Contents\n", 29 | "\n", 30 | "- [Job Search II: Search and Separation](#Job-Search-II:-Search-and-Separation) \n", 31 | " - [Overview](#Overview) \n", 32 | " - [The Model](#The-Model) \n", 33 | " - [Solving the Model using Dynamic Programming](#Solving-the-Model-using-Dynamic-Programming) \n", 34 | " - [Implementation](#Implementation) \n", 35 | " - [The Reservation Wage](#The-Reservation-Wage) \n", 36 | " - [Exercises](#Exercises) \n", 37 | " - [Solutions](#Solutions) " 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "id": "fe3ff46a", 43 | "metadata": {}, 44 | "source": [ 45 | "## Overview\n", 46 | "\n", 47 | "Previously [we looked](https://julia.quantecon.org/mccall_model.html) at the McCall job search model [[McC70](https://julia.quantecon.org/../zreferences.html#id109)] as a way of understanding unemployment and worker decisions.\n", 48 | "\n", 49 | "One unrealistic feature of the model is that every job is permanent.\n", 50 | "\n", 51 | "In this lecture we extend the McCall model by introducing job separation.\n", 52 | "\n", 53 | "Once separation enters the picture, the agent comes to view\n", 54 | "\n", 55 | "- the loss of a job as a capital loss, and \n", 56 | "- a spell of unemployment as an *investment* in searching for an acceptable job " 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "id": "1bad93b1", 63 | "metadata": { 64 | "hide-output": false 65 | }, 66 | "outputs": [], 67 | "source": [ 68 | "using LinearAlgebra, Statistics\n", 69 | "using Distributions, LaTeXStrings, NLsolve, Plots" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "id": "30d6dee3", 75 | "metadata": {}, 76 | "source": [ 77 | "## The Model\n", 78 | "\n", 79 | "The model concerns the life of an infinitely lived worker and\n", 80 | "\n", 81 | "- the opportunities he or she (let’s say he to save one character) has to work at different wages \n", 82 | "- exogenous events that destroy his current job \n", 83 | "- his decision making process while unemployed \n", 84 | "\n", 85 | "\n", 86 | "The worker can be in one of two states: employed or unemployed.\n", 87 | "\n", 88 | "He wants to maximize\n", 89 | "\n", 90 | "\n", 91 | "\n", 92 | "$$\n", 93 | "{\\mathbb E} \\sum_{t=0}^\\infty \\beta^t u(Y_t) \\tag{31.1}\n", 94 | "$$\n", 95 | "\n", 96 | "The only difference from the [baseline model](https://julia.quantecon.org/mccall_model.html) is that\n", 97 | "we’ve added some flexibility over preferences by introducing a utility function $ u $.\n", 98 | "\n", 99 | "It satisfies $ u'> 0 $ and $ u'' < 0 $." 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "id": "c38d3c78", 105 | "metadata": {}, 106 | "source": [ 107 | "### Timing and Decisions\n", 108 | "\n", 109 | "Here’s what happens at the start of a given period in our model with search and separation.\n", 110 | "\n", 111 | "If currently *employed*, the worker consumes his wage $ w $, receiving utility $ u(w) $.\n", 112 | "\n", 113 | "If currently *unemployed*, he\n", 114 | "\n", 115 | "- receives and consumes unemployment compensation $ c $ \n", 116 | "- receives an offer to start work *next period* at a wage $ w' $ drawn from a known distribution $ p_1, \\ldots, p_n $ \n", 117 | "\n", 118 | "\n", 119 | "He can either accept or reject the offer.\n", 120 | "\n", 121 | "If he accepts the offer, he enters next period employed with wage $ w' $.\n", 122 | "\n", 123 | "If he rejects the offer, he enters next period unemployed.\n", 124 | "\n", 125 | "When employed, the agent faces a constant probability $ \\alpha $ of becoming unemployed at the end of the period.\n", 126 | "\n", 127 | "(Note: we do not allow for job search while employed—this topic is taken\n", 128 | "up in a [later lecture](https://julia.quantecon.org/jv.html))" 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "id": "170229f4", 134 | "metadata": {}, 135 | "source": [ 136 | "## Solving the Model using Dynamic Programming\n", 137 | "\n", 138 | "Let\n", 139 | "\n", 140 | "- $ V(w) $ be the total lifetime value accruing to a worker who enters the current period *employed* with wage $ w $. \n", 141 | "- $ U $ be the total lifetime value accruing to a worker who is *unemployed* this period. \n", 142 | "\n", 143 | "\n", 144 | "Here *value* means the value of the objective function [(31.1)](#equation-objective) when the worker makes optimal decisions at all future points in time.\n", 145 | "\n", 146 | "Suppose for now that the worker can calculate the function $ V $ and the constant $ U $ and use them in his decision making.\n", 147 | "\n", 148 | "Then $ V $ and $ U $ should satisfy\n", 149 | "\n", 150 | "\n", 151 | "\n", 152 | "$$\n", 153 | "V(w) = u(w) + \\beta [(1-\\alpha)V(w) + \\alpha U ] \\tag{31.2}\n", 154 | "$$\n", 155 | "\n", 156 | "and\n", 157 | "\n", 158 | "\n", 159 | "\n", 160 | "$$\n", 161 | "U = u(c) + \\beta \\sum_i \\max \\left\\{ U, V(w_i) \\right\\} p_i \\tag{31.3}\n", 162 | "$$\n", 163 | "\n", 164 | "Let’s interpret these two equations in light of the fact that today’s tomorrow is tomorrow’s today.\n", 165 | "\n", 166 | "- The left hand sides of equations [(31.2)](#equation-bell1-mccall) and [(31.3)](#equation-bell2-mccall) are the values of a worker in a particular situation *today*. \n", 167 | "- The right hand sides of the equations are the discounted (by $ \\beta $) expected values of the possible situations that worker can be in *tomorrow*. \n", 168 | "- But *tomorrow* the worker can be in only one of the situations whose values *today* are on the left sides of our two equations. \n", 169 | "\n", 170 | "\n", 171 | "Equation [(31.3)](#equation-bell2-mccall) incorporates the fact that a currently unemployed worker will maximize his own welfare.\n", 172 | "\n", 173 | "In particular, if his next period wage offer is $ w' $, he will choose to remain unemployed unless $ U < V(w') $.\n", 174 | "\n", 175 | "Equations [(31.2)](#equation-bell1-mccall) and [(31.3)](#equation-bell2-mccall) are the Bellman equations\n", 176 | "for this model.\n", 177 | "\n", 178 | "Equations [(31.2)](#equation-bell1-mccall) and [(31.3)](#equation-bell2-mccall) provide enough information to solve out for both $ V $ and $ U $.\n", 179 | "\n", 180 | "Before discussing this, however, let’s make a small extension to the model." 181 | ] 182 | }, 183 | { 184 | "cell_type": "markdown", 185 | "id": "3aa3d1f9", 186 | "metadata": {}, 187 | "source": [ 188 | "### Stochastic Offers\n", 189 | "\n", 190 | "Let’s suppose now that unemployed workers don’t always receive job offers.\n", 191 | "\n", 192 | "Instead, let’s suppose that unemployed workers only receive an offer with probability $ \\gamma $.\n", 193 | "\n", 194 | "If our worker does receive an offer, the wage offer is drawn from $ p $ as before.\n", 195 | "\n", 196 | "He either accepts or rejects the offer.\n", 197 | "\n", 198 | "Otherwise the model is the same.\n", 199 | "\n", 200 | "With some thought, you will be able to convince yourself that $ V $ and $ U $ should now satisfy\n", 201 | "\n", 202 | "\n", 203 | "\n", 204 | "$$\n", 205 | "V(w) = u(w) + \\beta [(1-\\alpha)V(w) + \\alpha U ] \\tag{31.4}\n", 206 | "$$\n", 207 | "\n", 208 | "and\n", 209 | "\n", 210 | "\n", 211 | "\n", 212 | "$$\n", 213 | "U = u(c) +\n", 214 | " \\beta (1 - \\gamma) U +\n", 215 | " \\beta \\gamma \\sum_i \\max \\left\\{ U, V(w_i) \\right\\} p_i \\tag{31.5}\n", 216 | "$$" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "id": "bcf73f5a", 222 | "metadata": {}, 223 | "source": [ 224 | "### Solving the Bellman Equations\n", 225 | "\n", 226 | "We’ll use the same iterative approach to solving the Bellman equations that we\n", 227 | "adopted in the [first job search lecture](https://julia.quantecon.org/mccall_model.html).\n", 228 | "\n", 229 | "Here this amounts to\n", 230 | "\n", 231 | "1. make guesses for $ U $ and $ V $ \n", 232 | "1. plug these guesses into the right hand sides of [(31.4)](#equation-bell01-mccall) and [(31.5)](#equation-bell02-mccall) \n", 233 | "1. update the left hand sides from this rule and then repeat \n", 234 | "\n", 235 | "\n", 236 | "In other words, we are iterating using the rules\n", 237 | "\n", 238 | "\n", 239 | "\n", 240 | "$$\n", 241 | "V_{n+1} (w_i) = u(w_i) + \\beta [(1-\\alpha)V_n (w_i) + \\alpha U_n ] \\tag{31.6}\n", 242 | "$$\n", 243 | "\n", 244 | "and\n", 245 | "\n", 246 | "\n", 247 | "\n", 248 | "$$\n", 249 | "U_{n+1} = u(c) +\n", 250 | " \\beta (1 - \\gamma) U_n +\n", 251 | " \\beta \\gamma \\sum_i \\max \\{ U_n, V_n(w_i) \\} p_i \\tag{31.7}\n", 252 | "$$\n", 253 | "\n", 254 | "starting from some initial conditions $ U_0, V_0 $.\n", 255 | "\n", 256 | "Formally, we can define a “Bellman operator” T which maps:\n", 257 | "\n", 258 | "\n", 259 | "\n", 260 | "$$\n", 261 | "TV(\\cdot) = u(\\cdot) + \\beta (1-\\alpha)V(\\cdot) + \\alpha U \\tag{31.8}\n", 262 | "$$\n", 263 | "\n", 264 | "In which case we are searching for a fixed point\n", 265 | "\n", 266 | "\n", 267 | "\n", 268 | "$$\n", 269 | "TV^{*} = V^* \\tag{31.9}\n", 270 | "$$\n", 271 | "\n", 272 | "As before, the system always converges to the true solutions—in this case,\n", 273 | "the $ V $ and $ U $ that solve [(31.4)](#equation-bell01-mccall) and [(31.5)](#equation-bell02-mccall).\n", 274 | "\n", 275 | "A proof can be obtained via the Banach contraction mapping theorem." 276 | ] 277 | }, 278 | { 279 | "cell_type": "markdown", 280 | "id": "47f85504", 281 | "metadata": {}, 282 | "source": [ 283 | "## Implementation\n", 284 | "\n", 285 | "Let’s implement this iterative process" 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": null, 291 | "id": "e61216b6", 292 | "metadata": { 293 | "hide-output": false 294 | }, 295 | "outputs": [], 296 | "source": [ 297 | "using Distributions, LinearAlgebra, NLsolve, Plots\n", 298 | "\n", 299 | "function solve_mccall_model(mcm; U_iv = 1.0, V_iv = ones(length(mcm.w)),\n", 300 | " tol = 1e-5,\n", 301 | " iter = 2_000)\n", 302 | " (; alpha, beta, sigma, c, gamma, w, dist, u, p) = mcm\n", 303 | "\n", 304 | " # parameter validation\n", 305 | " @assert c > 0.0\n", 306 | " @assert minimum(w) > 0.0 # perhaps not strictly necessary, but useful here\n", 307 | "\n", 308 | " # necessary objects\n", 309 | " u_w = mcm.u.(w, sigma)\n", 310 | " u_c = mcm.u(c, sigma)\n", 311 | "\n", 312 | " # Bellman operator T. Fixed point is x* s.t. T(x*) = x*\n", 313 | " function T(x)\n", 314 | " V = x[1:(end - 1)]\n", 315 | " U = x[end]\n", 316 | " V_p = u_w + beta * ((1 - alpha) * V .+ alpha * U)\n", 317 | " U_p = u_c + beta * (1 - gamma) * U +\n", 318 | " beta * gamma * sum(max(U, V[i]) * p[i] for i in 1:length(w))\n", 319 | " return [V_p; U_p]\n", 320 | " end\n", 321 | "\n", 322 | " # value function iteration\n", 323 | " x_iv = [V_iv; U_iv] # initial x val\n", 324 | " xstar = fixedpoint(T, x_iv, iterations = iter, xtol = tol, m = 0).zero\n", 325 | " V = xstar[1:(end - 1)]\n", 326 | " U = xstar[end]\n", 327 | "\n", 328 | " # compute the reservation wage\n", 329 | " wbarindex = searchsortedfirst(V .- U, 0.0)\n", 330 | " if wbarindex >= length(w) # if this is true, you never want to accept\n", 331 | " w_bar = Inf\n", 332 | " else\n", 333 | " w_bar = w[wbarindex] # otherwise, return the number\n", 334 | " end\n", 335 | "\n", 336 | " # return a NamedTuple, so we can select values by name\n", 337 | " return (; V, U, w_bar)\n", 338 | "end" 339 | ] 340 | }, 341 | { 342 | "cell_type": "markdown", 343 | "id": "5bf4c4ad", 344 | "metadata": {}, 345 | "source": [ 346 | "The approach is to iterate until successive iterates are closer together than some small tolerance level.\n", 347 | "\n", 348 | "We then return the current iterate as an approximate solution.\n", 349 | "\n", 350 | "Let’s plot the approximate solutions $ U $ and $ V $ to see what they look like.\n", 351 | "\n", 352 | "We’ll use the default parameterizations found in the code above." 353 | ] 354 | }, 355 | { 356 | "cell_type": "code", 357 | "execution_count": null, 358 | "id": "a3244b0e", 359 | "metadata": { 360 | "hide-output": false 361 | }, 362 | "outputs": [], 363 | "source": [ 364 | "function mcall_model(; alpha = 0.2,\n", 365 | " beta = 0.98, # discount rate\n", 366 | " gamma = 0.7,\n", 367 | " c = 6.0, # unemployment compensation\n", 368 | " sigma = 2.0,\n", 369 | " u = (c, sigma) -> (c^(1 - sigma) - 1) / (1 - sigma),\n", 370 | " w = range(10, 20, length = 60), # wage values\n", 371 | " dist = BetaBinomial(59, 600, 400)) # distribution over wage values\n", 372 | " p = pdf.(dist, support(dist))\n", 373 | " return (; alpha, beta, gamma, c, sigma, u, w, dist, p)\n", 374 | "end" 375 | ] 376 | }, 377 | { 378 | "cell_type": "code", 379 | "execution_count": null, 380 | "id": "eda45784", 381 | "metadata": { 382 | "hide-output": false 383 | }, 384 | "outputs": [], 385 | "source": [ 386 | "# plots setting\n", 387 | "\n", 388 | "mcm = mcall_model()\n", 389 | "(; V, U) = solve_mccall_model(mcm)\n", 390 | "U_vec = fill(U, length(mcm.w))\n", 391 | "\n", 392 | "plot(mcm.w, [V U_vec], lw = 2, alpha = 0.7, label = [L\"V\" L\"U\"])" 393 | ] 394 | }, 395 | { 396 | "cell_type": "markdown", 397 | "id": "20f781f3", 398 | "metadata": {}, 399 | "source": [ 400 | "The value $ V $ is increasing because higher $ w $ generates a higher wage flow conditional on staying employed.\n", 401 | "\n", 402 | "At this point, it’s natural to ask how the model would respond if we perturbed the parameters.\n", 403 | "\n", 404 | "These calculations, called comparative statics, are performed in the next section." 405 | ] 406 | }, 407 | { 408 | "cell_type": "markdown", 409 | "id": "ac6a65af", 410 | "metadata": {}, 411 | "source": [ 412 | "## The Reservation Wage\n", 413 | "\n", 414 | "Once $ V $ and $ U $ are known, the agent can use them to make decisions in the face of a given wage offer.\n", 415 | "\n", 416 | "If $ V(w) > U $, then working at wage $ w $ is preferred to unemployment.\n", 417 | "\n", 418 | "If $ V(w) < U $, then remaining unemployed will generate greater lifetime value.\n", 419 | "\n", 420 | "Suppose in particular that $ V $ crosses $ U $ (as it does in the preceding figure).\n", 421 | "\n", 422 | "Then, since $ V $ is increasing, there is a unique smallest $ w $ in the set of possible wages such that $ V(w) \\geq U $.\n", 423 | "\n", 424 | "We denote this wage $ \\bar w $ and call it the reservation wage.\n", 425 | "\n", 426 | "Optimal behavior for the worker is characterized by $ \\bar w $\n", 427 | "\n", 428 | "- if the wage offer $ w $ in hand is greater than or equal to $ \\bar w $, then the worker accepts \n", 429 | "- if the wage offer $ w $ in hand is less than $ \\bar w $, then the worker rejects \n", 430 | "\n", 431 | "\n", 432 | "If $ V(w) < U $ for all $ w $, then the function returns np.inf.\n", 433 | "\n", 434 | "Let’s use it to look at how the reservation wage varies with parameters.\n", 435 | "\n", 436 | "In each instance below we’ll show you a figure and then ask you to reproduce it in the exercises." 437 | ] 438 | }, 439 | { 440 | "cell_type": "markdown", 441 | "id": "394a8802", 442 | "metadata": {}, 443 | "source": [ 444 | "### The Reservation Wage and Unemployment Compensation\n", 445 | "\n", 446 | "First, let’s look at how $ \\bar w $ varies with unemployment compensation.\n", 447 | "\n", 448 | "In the figure below, we use the default parameters in the mcall_model tuple, apart from\n", 449 | "c (which takes the values given on the horizontal axis)\n", 450 | "\n", 451 | "![https://julia.quantecon.org/_static/figures/mccall_resw_c.png](https://julia.quantecon.org/_static/figures/mccall_resw_c.png)\n", 452 | "\n", 453 | " \n", 454 | "As expected, higher unemployment compensation causes the worker to hold out for higher wages.\n", 455 | "\n", 456 | "In effect, the cost of continuing job search is reduced." 457 | ] 458 | }, 459 | { 460 | "cell_type": "markdown", 461 | "id": "be74a8e1", 462 | "metadata": {}, 463 | "source": [ 464 | "### The Reservation Wage and Discounting\n", 465 | "\n", 466 | "Next let’s investigate how $ \\bar w $ varies with the discount rate.\n", 467 | "\n", 468 | "The next figure plots the reservation wage associated with different values of\n", 469 | "$ \\beta $\n", 470 | "\n", 471 | "![https://julia.quantecon.org/_static/figures/mccall_resw_beta.png](https://julia.quantecon.org/_static/figures/mccall_resw_beta.png)\n", 472 | "\n", 473 | " \n", 474 | "Again, the results are intuitive: More patient workers will hold out for higher wages." 475 | ] 476 | }, 477 | { 478 | "cell_type": "markdown", 479 | "id": "09d95497", 480 | "metadata": {}, 481 | "source": [ 482 | "### The Reservation Wage and Job Destruction\n", 483 | "\n", 484 | "Finally, let’s look at how $ \\bar w $ varies with the job separation rate $ \\alpha $.\n", 485 | "\n", 486 | "Higher $ \\alpha $ translates to a greater chance that a worker will face termination in each period once employed.\n", 487 | "\n", 488 | "![https://julia.quantecon.org/_static/figures/mccall_resw_alpha.png](https://julia.quantecon.org/_static/figures/mccall_resw_alpha.png)\n", 489 | "\n", 490 | " \n", 491 | "Once more, the results are in line with our intuition.\n", 492 | "\n", 493 | "If the separation rate is high, then the benefit of holding out for a higher wage falls.\n", 494 | "\n", 495 | "Hence the reservation wage is lower." 496 | ] 497 | }, 498 | { 499 | "cell_type": "markdown", 500 | "id": "127aad16", 501 | "metadata": {}, 502 | "source": [ 503 | "## Exercises" 504 | ] 505 | }, 506 | { 507 | "cell_type": "markdown", 508 | "id": "58219c0e", 509 | "metadata": {}, 510 | "source": [ 511 | "### Exercise 1\n", 512 | "\n", 513 | "Reproduce all the reservation wage figures shown above." 514 | ] 515 | }, 516 | { 517 | "cell_type": "markdown", 518 | "id": "8daac647", 519 | "metadata": {}, 520 | "source": [ 521 | "### Exercise 2\n", 522 | "\n", 523 | "Plot the reservation wage against the job offer rate $ \\gamma $.\n", 524 | "\n", 525 | "Use" 526 | ] 527 | }, 528 | { 529 | "cell_type": "code", 530 | "execution_count": null, 531 | "id": "d0ccef8e", 532 | "metadata": { 533 | "hide-output": false 534 | }, 535 | "outputs": [], 536 | "source": [ 537 | "gamma_vals = range(0.05, 0.95, length = 25)" 538 | ] 539 | }, 540 | { 541 | "cell_type": "markdown", 542 | "id": "c3c40399", 543 | "metadata": {}, 544 | "source": [ 545 | "Interpret your results." 546 | ] 547 | }, 548 | { 549 | "cell_type": "markdown", 550 | "id": "58ce449e", 551 | "metadata": {}, 552 | "source": [ 553 | "## Solutions" 554 | ] 555 | }, 556 | { 557 | "cell_type": "markdown", 558 | "id": "66d204c0", 559 | "metadata": {}, 560 | "source": [ 561 | "### Exercise 1\n", 562 | "\n", 563 | "Using the solve_mccall_model function mentioned earlier in the lecture,\n", 564 | "we can create an array for reservation wages for different values of $ c $,\n", 565 | "$ \\beta $ and $ \\alpha $ and plot the results like so" 566 | ] 567 | }, 568 | { 569 | "cell_type": "code", 570 | "execution_count": null, 571 | "id": "ce6c00b9", 572 | "metadata": { 573 | "hide-output": false 574 | }, 575 | "outputs": [], 576 | "source": [ 577 | "c_vals = range(2, 12, length = 25)\n", 578 | "\n", 579 | "models = [mcall_model(c = cval) for cval in c_vals]\n", 580 | "sols = solve_mccall_model.(models)\n", 581 | "w_bar_vals = [sol.w_bar for sol in sols]\n", 582 | "\n", 583 | "plot(c_vals,\n", 584 | " w_bar_vals,\n", 585 | " lw = 2,\n", 586 | " alpha = 0.7,\n", 587 | " xlabel = \"unemployment compensation\",\n", 588 | " ylabel = \"reservation wage\",\n", 589 | " label = L\"$\\overline{w}$ as a function of $c$\")" 590 | ] 591 | }, 592 | { 593 | "cell_type": "markdown", 594 | "id": "ccbfcddc", 595 | "metadata": {}, 596 | "source": [ 597 | "Note that we could’ve done the above in one pass (which would be important if, for example, the parameter space was quite large)." 598 | ] 599 | }, 600 | { 601 | "cell_type": "code", 602 | "execution_count": null, 603 | "id": "b786b491", 604 | "metadata": { 605 | "hide-output": false 606 | }, 607 | "outputs": [], 608 | "source": [ 609 | "w_bar_vals = [solve_mccall_model(mcall_model(c = cval)).w_bar\n", 610 | " for cval in c_vals];\n", 611 | "# doesn't allocate new arrays for models and solutions" 612 | ] 613 | }, 614 | { 615 | "cell_type": "markdown", 616 | "id": "7e404996", 617 | "metadata": {}, 618 | "source": [ 619 | "### Exercise 2\n", 620 | "\n", 621 | "Similar to above, we can plot $ \\bar w $ against $ \\gamma $ as follows" 622 | ] 623 | }, 624 | { 625 | "cell_type": "code", 626 | "execution_count": null, 627 | "id": "4e4ad1f8", 628 | "metadata": { 629 | "hide-output": false 630 | }, 631 | "outputs": [], 632 | "source": [ 633 | "gamma_vals = range(0.05, 0.95, length = 25)\n", 634 | "\n", 635 | "models = [mcall_model(gamma = gammaval) for gammaval in gamma_vals]\n", 636 | "sols = solve_mccall_model.(models)\n", 637 | "w_bar_vals = [sol.w_bar for sol in sols]\n", 638 | "\n", 639 | "plot(gamma_vals, w_bar_vals, lw = 2, alpha = 0.7, xlabel = \"job offer rate\",\n", 640 | " ylabel = \"reservation wage\",\n", 641 | " label = L\"$\\overline{w}$ as a function of $\\gamma$\")" 642 | ] 643 | }, 644 | { 645 | "cell_type": "markdown", 646 | "id": "5817dc41", 647 | "metadata": {}, 648 | "source": [ 649 | "As expected, the reservation wage increases in $ \\gamma $.\n", 650 | "\n", 651 | "This is because higher $ \\gamma $ translates to a more favorable job\n", 652 | "search environment.\n", 653 | "\n", 654 | "Hence workers are less willing to accept lower offers." 655 | ] 656 | } 657 | ], 658 | "metadata": { 659 | "date": 1766028218.7161026, 660 | "filename": "mccall_model_with_separation.md", 661 | "kernelspec": { 662 | "display_name": "Julia", 663 | "language": "julia", 664 | "name": "julia-1.12" 665 | }, 666 | "title": "Job Search II: Search and Separation" 667 | }, 668 | "nbformat": 4, 669 | "nbformat_minor": 5 670 | } -------------------------------------------------------------------------------- /dynamic_programming/jv.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "a7d07933", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "099aba02", 15 | "metadata": {}, 16 | "source": [ 17 | "# Job Search V: On-the-Job Search\n", 18 | "\n", 19 | "\n", 20 | "" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "cd0d46da", 26 | "metadata": {}, 27 | "source": [ 28 | "## Contents\n", 29 | "\n", 30 | "- [Job Search V: On-the-Job Search](#Job-Search-V:-On-the-Job-Search) \n", 31 | " - [Overview](#Overview) \n", 32 | " - [Model](#Model) \n", 33 | " - [Implementation](#Implementation) \n", 34 | " - [Solving for Policies](#Solving-for-Policies) \n", 35 | " - [Exercises](#Exercises) \n", 36 | " - [Solutions](#Solutions) " 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "id": "bbfdb1a8", 42 | "metadata": {}, 43 | "source": [ 44 | "## Overview" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "id": "d2cb7447", 50 | "metadata": {}, 51 | "source": [ 52 | "### Model features\n", 53 | "\n", 54 | "\n", 55 | "\n", 56 | "- job-specific human capital accumulation combined with on-the-job search \n", 57 | "- infinite horizon dynamic programming with one state variable and two controls " 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "id": "1a217263", 64 | "metadata": { 65 | "hide-output": false 66 | }, 67 | "outputs": [], 68 | "source": [ 69 | "using LinearAlgebra, Statistics\n", 70 | "using Distributions, Interpolations\n", 71 | "using FastGaussQuadrature, SpecialFunctions\n", 72 | "using LaTeXStrings, Plots, NLsolve, Random" 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "id": "86ea18a0", 78 | "metadata": {}, 79 | "source": [ 80 | "## Model\n", 81 | "\n", 82 | "\n", 83 | "\n", 84 | "Let\n", 85 | "\n", 86 | "- $ x_t $ denote the time-$ t $ job-specific human capital of a worker employed at a given firm \n", 87 | "- $ w_t $ denote current wages \n", 88 | "\n", 89 | "\n", 90 | "Let $ w_t = x_t(1 - s_t - \\phi_t) $, where\n", 91 | "\n", 92 | "- $ \\phi_t $ is investment in job-specific human capital for the current role \n", 93 | "- $ s_t $ is search effort, devoted to obtaining new offers from other firms \n", 94 | "\n", 95 | "\n", 96 | "For as long as the worker remains in the current job, evolution of\n", 97 | "$ \\{x_t\\} $ is given by $ x_{t+1} = G(x_t, \\phi_t) $.\n", 98 | "\n", 99 | "When search effort at $ t $ is $ s_t $, the worker receives a new job\n", 100 | "offer with probability $ \\pi(s_t) \\in [0, 1] $.\n", 101 | "\n", 102 | "Value of offer is $ U_{t+1} $, where $ \\{U_t\\} $ is iid with common distribution $ F $.\n", 103 | "\n", 104 | "Worker has the right to reject the current offer and continue with existing job.\n", 105 | "\n", 106 | "In particular, $ x_{t+1} = U_{t+1} $ if accepts and $ x_{t+1} = G(x_t, \\phi_t) $ if rejects.\n", 107 | "\n", 108 | "Letting $ b_{t+1} \\in \\{0,1\\} $ be binary with $ b_{t+1} = 1 $ indicating an offer, we can write\n", 109 | "\n", 110 | "\n", 111 | "\n", 112 | "$$\n", 113 | "x_{t+1}\n", 114 | "= (1 - b_{t+1}) G(x_t, \\phi_t) + b_{t+1}\n", 115 | " \\max \\{ G(x_t, \\phi_t), U_{t+1}\\} \\tag{35.1}\n", 116 | "$$\n", 117 | "\n", 118 | "Agent’s objective: maximize expected discounted sum of wages via controls $ \\{s_t\\} $ and $ \\{\\phi_t\\} $.\n", 119 | "\n", 120 | "Taking the expectation of $ V(x_{t+1}) $ and using [(35.1)](#equation-jd),\n", 121 | "the Bellman equation for this problem can be written as\n", 122 | "\n", 123 | "\n", 124 | "\n", 125 | "$$\n", 126 | "V(x)\n", 127 | "= \\max_{s + \\phi \\leq 1}\n", 128 | " \\left\\{\n", 129 | " x (1 - s - \\phi) + \\beta (1 - \\pi(s)) V[G(x, \\phi)] +\n", 130 | " \\beta \\pi(s) \\int V[G(x, \\phi) \\vee u] F(du)\n", 131 | " \\right\\}. \\tag{35.2}\n", 132 | "$$\n", 133 | "\n", 134 | "Here nonnegativity of $ s $ and $ \\phi $ is understood, while\n", 135 | "$ a \\vee b := \\max\\{a, b\\} $." 136 | ] 137 | }, 138 | { 139 | "cell_type": "markdown", 140 | "id": "bb1f4f75", 141 | "metadata": {}, 142 | "source": [ 143 | "### Parameterization\n", 144 | "\n", 145 | "\n", 146 | "\n", 147 | "In the implementation below, we will focus on the parameterization.\n", 148 | "\n", 149 | "$$\n", 150 | "G(x, \\phi) = A (x \\phi)^{\\alpha},\n", 151 | "\\quad\n", 152 | "\\pi(s) = \\sqrt s\n", 153 | "\\quad \\text{and} \\quad\n", 154 | "F = \\text{Beta}(2, 2)\n", 155 | "$$\n", 156 | "\n", 157 | "with default parameter values\n", 158 | "\n", 159 | "- $ A = 1.4 $ \n", 160 | "- $ \\alpha = 0.6 $ \n", 161 | "- $ \\beta = 0.96 $ \n", 162 | "\n", 163 | "\n", 164 | "The Beta(2,2) distribution is supported on $ (0,1) $. It has a unimodal, symmetric density peaked at 0.5." 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "id": "020286f5", 170 | "metadata": {}, 171 | "source": [ 172 | "### Quadrature\n", 173 | "\n", 174 | "In order to calculate expectations over the continuously valued $ F $ distribution, we need to either draw values\n", 175 | "and use Monte Carlo integration, or discretize.\n", 176 | "\n", 177 | "[Gaussian Quadrature](https://en.wikipedia.org/wiki/Gaussian_quadrature) methods use orthogonal polynomials to generate $ N $ nodes, $ x $ and weights, $ w $, to calculate integrals of the form $ \\int f(x) dx \\approx \\sum_{n=1}^N w_n f(x_n) $ for various bounded domains.\n", 178 | "\n", 179 | "Here we will use [Gauss-Jacobi Quadrature](https://en.wikipedia.org/wiki/Gauss%E2%80%93Jacobi_quadrature) which is ideal for expectations over beta.\n", 180 | "\n", 181 | "See [quadrature and interpolation](https://julia.quantecon.org/../more_julia/quadrature_interpolation.html) for details on the derivation in this particular case." 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": null, 187 | "id": "95075862", 188 | "metadata": { 189 | "hide-output": false 190 | }, 191 | "outputs": [], 192 | "source": [ 193 | "function gauss_jacobi(F::Beta, N)\n", 194 | " s, wj = FastGaussQuadrature.gaussjacobi(N, F.β - 1, F.α - 1)\n", 195 | " x = (s .+ 1) ./ 2\n", 196 | " C = 2.0^(-(F.α + F.β - 1.0)) / SpecialFunctions.beta(F.α, F.β)\n", 197 | " w = C .* wj\n", 198 | " return x, w\n", 199 | "end\n", 200 | "f(x) = x^2\n", 201 | "F = Beta(2, 2)\n", 202 | "x, w = gauss_jacobi(F, 20)\n", 203 | "# compare to monte-carlo integration\n", 204 | "@show dot(w, f.(x)), mean(f.(rand(F, 1000)));" 205 | ] 206 | }, 207 | { 208 | "cell_type": "markdown", 209 | "id": "6ff099a0", 210 | "metadata": {}, 211 | "source": [ 212 | "\n", 213 | "" 214 | ] 215 | }, 216 | { 217 | "cell_type": "markdown", 218 | "id": "f1015686", 219 | "metadata": {}, 220 | "source": [ 221 | "### Back-of-the-Envelope Calculations\n", 222 | "\n", 223 | "Before we solve the model, let’s make some quick calculations that\n", 224 | "provide intuition on what the solution should look like.\n", 225 | "\n", 226 | "To begin, observe that the worker has two instruments to build\n", 227 | "capital and hence wages:\n", 228 | "\n", 229 | "1. invest in capital specific to the current job via $ \\phi $ \n", 230 | "1. search for a new job with better job-specific capital match via $ s $ \n", 231 | "\n", 232 | "\n", 233 | "Since wages are $ x (1 - s - \\phi) $, marginal cost of investment via either $ \\phi $ or $ s $ is identical.\n", 234 | "\n", 235 | "Our risk neutral worker should focus on whatever instrument has the highest expected return.\n", 236 | "\n", 237 | "The relative expected return will depend on $ x $.\n", 238 | "\n", 239 | "For example, suppose first that $ x = 0.05 $\n", 240 | "\n", 241 | "- If $ s=1 $ and $ \\phi = 0 $, then since $ G(x,\\phi) = 0 $,\n", 242 | " taking expectations of [(35.1)](#equation-jd) gives expected next period capital equal to $ \\pi(s) \\mathbb{E} U\n", 243 | " = \\mathbb{E} U = 0.5 $. \n", 244 | "- If $ s=0 $ and $ \\phi=1 $, then next period capital is $ G(x, \\phi) = G(0.05, 1) \\approx 0.23 $. \n", 245 | "\n", 246 | "\n", 247 | "Both rates of return are good, but the return from search is better.\n", 248 | "\n", 249 | "Next suppose that $ x = 0.4 $\n", 250 | "\n", 251 | "- If $ s=1 $ and $ \\phi = 0 $, then expected next period capital is again $ 0.5 $ \n", 252 | "- If $ s=0 $ and $ \\phi = 1 $, then $ G(x, \\phi) = G(0.4, 1) \\approx 0.8 $ \n", 253 | "\n", 254 | "\n", 255 | "Return from investment via $ \\phi $ dominates expected return from search.\n", 256 | "\n", 257 | "Combining these observations gives us two informal predictions:\n", 258 | "\n", 259 | "1. At any given state $ x $, the two controls $ \\phi $ and $ s $ will function primarily as substitutes — worker will focus on whichever instrument has the higher expected return. \n", 260 | "1. For sufficiently small $ x $, search will be preferable to investment in job-specific human capital. For larger $ x $, the reverse will be true. \n", 261 | "\n", 262 | "\n", 263 | "Now let’s turn to implementation, and see if we can match our predictions." 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "id": "171a606a", 269 | "metadata": {}, 270 | "source": [ 271 | "## Implementation\n", 272 | "\n", 273 | "\n", 274 | "\n", 275 | "The following code solves the DP problem described above" 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": null, 281 | "id": "858df168", 282 | "metadata": { 283 | "hide-output": false 284 | }, 285 | "outputs": [], 286 | "source": [ 287 | "function jv_worker(; A = 1.4,\n", 288 | " alpha = 0.6,\n", 289 | " beta = 0.96,\n", 290 | " grid_size = 50,\n", 291 | " quad_size = 30,\n", 292 | " search_grid_size = 15,\n", 293 | " epsilon = 1e-4)\n", 294 | " G(x, phi) = A * (x * phi)^alpha\n", 295 | " pi_func = sqrt\n", 296 | " F = Beta(2, 2)\n", 297 | "\n", 298 | " u, w = gauss_jacobi(F, quad_size)\n", 299 | "\n", 300 | " grid_max = max(A^(1.0 / (1.0 - alpha)), quantile(F, 1 - epsilon))\n", 301 | " x_grid = range(epsilon, grid_max, length = grid_size)\n", 302 | " search_grid = range(epsilon, 1.0, length = search_grid_size)\n", 303 | "\n", 304 | " # Pre-calculate the flat list of valid (s, phi) tuples which are feasible\n", 305 | " choices = vec([(s, phi) for s in search_grid, phi in search_grid if s + phi <= 1.0])\n", 306 | "\n", 307 | " return (; A, alpha, beta, x_grid, choices, G,\n", 308 | " pi_func, F, u, w, epsilon)\n", 309 | "end\n", 310 | "\n", 311 | "function T(jv, V)\n", 312 | " (; G, pi_func, beta, u, w, choices, x_grid) = jv\n", 313 | " Vf = LinearInterpolation(x_grid, V, extrapolation_bc = Line())\n", 314 | "\n", 315 | " # Objective takes a tuple 'c' which contains (s, phi)\n", 316 | " function objective(x, c)\n", 317 | " s, phi = c \n", 318 | " g_val = G(x, phi)\n", 319 | " integral = sum(w[j] * Vf(max(g_val, u[j])) for j in eachindex(u))\n", 320 | " continuation = (1.0 - pi_func(s)) * Vf(g_val) + pi_func(s) * integral\n", 321 | " return x * (1.0 - s - phi) + beta * continuation\n", 322 | " end\n", 323 | "\n", 324 | " # Pre-allocate output arrays\n", 325 | " new_V = similar(x_grid)\n", 326 | " s_policy = similar(x_grid)\n", 327 | " phi_policy = similar(x_grid)\n", 328 | "\n", 329 | " # Loop over states\n", 330 | " for (i, x) in enumerate(x_grid)\n", 331 | " # Broadcast: evaluate 'objective' for this 'x' across all 'choices'\n", 332 | " vals = objective.(x, choices)\n", 333 | " \n", 334 | " # Find the best value and its index\n", 335 | " v_max, idx = findmax(vals)\n", 336 | "\n", 337 | " # Store results\n", 338 | " new_V[i] = v_max\n", 339 | " s_policy[i], phi_policy[i] = choices[idx] # Unpack the tuple\n", 340 | " end\n", 341 | "\n", 342 | " return new_V, (s_policy, phi_policy)\n", 343 | "end" 344 | ] 345 | }, 346 | { 347 | "cell_type": "markdown", 348 | "id": "3ca6cab7", 349 | "metadata": {}, 350 | "source": [ 351 | "The code is written to be relatively generic—and hence reusable.\n", 352 | "\n", 353 | "- For example, we use generic $ G(x,\\phi) $ instead of specific $ A (x \\phi)^{\\alpha} $. \n", 354 | "\n", 355 | "\n", 356 | "Function `jv_worker` packages all parameters for the model. The Bellman\n", 357 | "operator $ T $ acts on a candidate value function via [(35.2)](#equation-jvbell). In\n", 358 | "code, `T` returns a fresh value array together with policies for $ s $ and\n", 359 | "$ \\phi $ on the state grid. It builds a linear interpolant `Vf` on\n", 360 | "`x_grid` and then evaluates\n", 361 | "\n", 362 | "$$\n", 363 | "w(s, \\phi) =\n", 364 | " x (1 - s - \\phi) + \\beta (1 - \\pi(s)) V[G(x, \\phi)] +\n", 365 | " \\beta \\pi(s) \\int V[G(x, \\phi) \\vee u] F(du)\n", 366 | "$$\n", 367 | "\n", 368 | "on a coarse feasible grid, taking the maximizer over $ s + \\phi \\leq 1 $.\n", 369 | "Expectations are computed with the quadrature nodes `u` and weights `w`.\n", 370 | "The second return value collects the maximizing $ s(x) $ and $ \\phi(x) $ at\n", 371 | "each state.\n", 372 | "\n", 373 | "\n", 374 | "" 375 | ] 376 | }, 377 | { 378 | "cell_type": "markdown", 379 | "id": "bd548bbe", 380 | "metadata": {}, 381 | "source": [ 382 | "## Solving for Policies\n", 383 | "\n", 384 | "\n", 385 | "\n", 386 | "Let’s plot the optimal policies and see what they look like.\n", 387 | "\n", 388 | "The code is as follows" 389 | ] 390 | }, 391 | { 392 | "cell_type": "code", 393 | "execution_count": null, 394 | "id": "26afab5c", 395 | "metadata": { 396 | "hide-output": false 397 | }, 398 | "outputs": [], 399 | "source": [ 400 | "wp = jv_worker(; grid_size = 25)\n", 401 | "v_init = collect(wp.x_grid) .* 0.5\n", 402 | "\n", 403 | "V = fixedpoint(v -> T(wp, v)[1], v_init)\n", 404 | "sol_V = V.zero\n", 405 | "\n", 406 | "_, (s_policy, phi_policy) = T(wp, sol_V)\n", 407 | "\n", 408 | "# plot solution\n", 409 | "p = plot(wp.x_grid, [phi_policy s_policy sol_V],\n", 410 | " title = [L\"$\\phi$ policy\" L\"$s$ policy\" \"value function\"],\n", 411 | " color = [:orange :blue :green],\n", 412 | " xaxis = (L\"x\", (0.0, maximum(wp.x_grid))),\n", 413 | " yaxis = ((-0.1, 1.1)), size = (800, 800),\n", 414 | " legend = false, layout = (3, 1),\n", 415 | " bottom_margin = Plots.PlotMeasures.Length(:mm, 20))" 416 | ] 417 | }, 418 | { 419 | "cell_type": "markdown", 420 | "id": "84fc02e3", 421 | "metadata": {}, 422 | "source": [ 423 | "The horizontal axis is the state $ x $, while the vertical axis gives $ s(x) $ and $ \\phi(x) $.\n", 424 | "\n", 425 | "Overall, the policies match well with our predictions from [section](#jvboecalc).\n", 426 | "\n", 427 | "- Worker switches from one investment strategy to the other depending on relative return. \n", 428 | "- For low values of $ x $, the best option is to search for a new job. \n", 429 | "- Once $ x $ is larger, worker does better by investing in human capital specific to the current position. " 430 | ] 431 | }, 432 | { 433 | "cell_type": "markdown", 434 | "id": "85f7e863", 435 | "metadata": {}, 436 | "source": [ 437 | "## Exercises\n", 438 | "\n", 439 | "\n", 440 | "" 441 | ] 442 | }, 443 | { 444 | "cell_type": "markdown", 445 | "id": "97f30647", 446 | "metadata": {}, 447 | "source": [ 448 | "### Exercise 1\n", 449 | "\n", 450 | "Let’s look at the dynamics for the state process $ \\{x_t\\} $ associated with these policies.\n", 451 | "\n", 452 | "The dynamics are given by [(35.1)](#equation-jd) when $ \\phi_t $ and $ s_t $ are\n", 453 | "chosen according to the optimal policies, and $ \\mathbb{P}\\{b_{t+1} = 1\\}\n", 454 | "= \\pi(s_t) $.\n", 455 | "\n", 456 | "Since the dynamics are random, analysis is a bit subtle.\n", 457 | "\n", 458 | "One way to do it is to plot, for each $ x $ in a relatively fine grid\n", 459 | "called `plot_grid`, a\n", 460 | "large number $ K $ of realizations of $ x_{t+1} $ given $ x_t =\n", 461 | "x $. Plot this with one dot for each realization, in the form of a 45 degree\n", 462 | "diagram. Set" 463 | ] 464 | }, 465 | { 466 | "cell_type": "code", 467 | "execution_count": null, 468 | "id": "cdf60107", 469 | "metadata": { 470 | "hide-output": false 471 | }, 472 | "outputs": [], 473 | "source": [ 474 | "K = 50\n", 475 | "plot_grid_max, plot_grid_size = 1.2, 100\n", 476 | "plot_grid = range(0, plot_grid_max, length = plot_grid_size)\n", 477 | "plot(plot_grid, plot_grid, color = :black, linestyle = :dash,\n", 478 | " lims = (0, plot_grid_max), legend = :none)" 479 | ] 480 | }, 481 | { 482 | "cell_type": "markdown", 483 | "id": "735fc40d", 484 | "metadata": {}, 485 | "source": [ 486 | "By examining the plot, argue that under the optimal policies, the state\n", 487 | "$ x_t $ will converge to a constant value $ \\bar x $ close to unity.\n", 488 | "\n", 489 | "Argue that at the steady state, $ s_t \\approx 0 $ and $ \\phi_t \\approx 0.6 $.\n", 490 | "\n", 491 | "\n", 492 | "" 493 | ] 494 | }, 495 | { 496 | "cell_type": "markdown", 497 | "id": "80c022d3", 498 | "metadata": {}, 499 | "source": [ 500 | "### Exercise 2\n", 501 | "\n", 502 | "In the preceding exercise we found that $ s_t $ converges to zero\n", 503 | "and $ \\phi_t $ converges to about 0.6.\n", 504 | "\n", 505 | "Since these results were calculated at a value of $ \\beta $ close to\n", 506 | "one, let’s compare them to the best choice for an *infinitely* patient worker.\n", 507 | "\n", 508 | "Intuitively, an infinitely patient worker would like to maximize steady state\n", 509 | "wages, which are a function of steady state capital.\n", 510 | "\n", 511 | "You can take it as given—it’s certainly true—that the infinitely patient worker does not\n", 512 | "search in the long run (i.e., $ s_t = 0 $ for large $ t $).\n", 513 | "\n", 514 | "Thus, given $ \\phi $, steady state capital is the positive fixed point\n", 515 | "$ x^*(\\phi) $ of the map $ x \\mapsto G(x, \\phi) $.\n", 516 | "\n", 517 | "Steady state wages can be written as $ w^*(\\phi) = x^*(\\phi) (1 - \\phi) $.\n", 518 | "\n", 519 | "Graph $ w^*(\\phi) $ with respect to $ \\phi $, and examine the best\n", 520 | "choice of $ \\phi $.\n", 521 | "\n", 522 | "Can you give a rough interpretation for the value that you see?" 523 | ] 524 | }, 525 | { 526 | "cell_type": "markdown", 527 | "id": "cf14e430", 528 | "metadata": {}, 529 | "source": [ 530 | "## Solutions" 531 | ] 532 | }, 533 | { 534 | "cell_type": "markdown", 535 | "id": "8dc1fffd", 536 | "metadata": {}, 537 | "source": [ 538 | "### Exercise 1\n", 539 | "\n", 540 | "Here’s code to produce the 45 degree diagram" 541 | ] 542 | }, 543 | { 544 | "cell_type": "code", 545 | "execution_count": null, 546 | "id": "9cdef015", 547 | "metadata": { 548 | "hide-output": false 549 | }, 550 | "outputs": [], 551 | "source": [ 552 | "wp = jv_worker(grid_size = 25)\n", 553 | "# simplify notation\n", 554 | "(; G, pi_func, F) = wp\n", 555 | "\n", 556 | "v_init = collect(wp.x_grid) * 0.5\n", 557 | "f2(v) = T(wp, v)[1]\n", 558 | "V2 = fixedpoint(f2, v_init)\n", 559 | "sol_V2 = V2.zero\n", 560 | "_, (s_policy, phi_policy) = T(wp, sol_V2)\n", 561 | "\n", 562 | "# Turn the policy function arrays into CoordInterpGrid objects for interpolation\n", 563 | "s = LinearInterpolation(wp.x_grid, s_policy, extrapolation_bc = Line())\n", 564 | "phi = LinearInterpolation(wp.x_grid, phi_policy, extrapolation_bc = Line())\n", 565 | "\n", 566 | "h_func(x, b, U) = (1 - b) * G(x, phi(x)) + b * max(G(x, phi(x)), U)" 567 | ] 568 | }, 569 | { 570 | "cell_type": "code", 571 | "execution_count": null, 572 | "id": "f9214d04", 573 | "metadata": { 574 | "hide-output": false 575 | }, 576 | "outputs": [], 577 | "source": [ 578 | "using Random\n", 579 | "Random.seed!(42)\n", 580 | "K = 50\n", 581 | "\n", 582 | "plot_grid_max, plot_grid_size = 1.2, 100\n", 583 | "plot_grid = range(0, plot_grid_max, length = plot_grid_size)\n", 584 | "ticks = [0.25, 0.5, 0.75, 1.0]\n", 585 | "\n", 586 | "xs = []\n", 587 | "ys = []\n", 588 | "for x in plot_grid\n", 589 | " for i in 1:K\n", 590 | " b = rand() < pi_func(s(x)) ? 1 : 0\n", 591 | " U = rand(wp.F)\n", 592 | " y = h_func(x, b, U)\n", 593 | " push!(xs, x)\n", 594 | " push!(ys, y)\n", 595 | " end\n", 596 | "end\n", 597 | "\n", 598 | "plot(plot_grid, plot_grid, color = :black, linestyle = :dash, legend = :none)\n", 599 | "scatter!(xs, ys, alpha = 0.25, color = :green, lims = (0, plot_grid_max),\n", 600 | " ticks = ticks)\n", 601 | "plot!(xlabel = L\"x_t\", ylabel = L\"x_{t+1}\", guidefont = font(16))" 602 | ] 603 | }, 604 | { 605 | "cell_type": "markdown", 606 | "id": "9e1fb587", 607 | "metadata": {}, 608 | "source": [ 609 | "Looking at the dynamics, we can see that\n", 610 | "\n", 611 | "- If $ x_t $ is below about 0.2 the dynamics are random, but\n", 612 | " $ x_{t+1} > x_t $ is very likely \n", 613 | "- As $ x_t $ increases the dynamics become deterministic, and\n", 614 | " $ x_t $ converges to a steady state value close to 1 \n", 615 | "\n", 616 | "\n", 617 | "Referring back to the figure [here](#jv-solve)\n", 618 | "\n", 619 | "we see that $ x_t \\approx 1 $ means that\n", 620 | "$ s_t = s(x_t) \\approx 0 $ and\n", 621 | "$ \\phi_t = \\phi(x_t) \\approx 0.6 $." 622 | ] 623 | }, 624 | { 625 | "cell_type": "markdown", 626 | "id": "45d4a4f9", 627 | "metadata": {}, 628 | "source": [ 629 | "### Exercise 2" 630 | ] 631 | }, 632 | { 633 | "cell_type": "code", 634 | "execution_count": null, 635 | "id": "47ec6137", 636 | "metadata": { 637 | "hide-output": false 638 | }, 639 | "outputs": [], 640 | "source": [ 641 | "wp = jv_worker(grid_size = 25)\n", 642 | "\n", 643 | "xbar(phi) = (wp.A * phi^wp.alpha)^(1.0 / (1.0 - wp.alpha))\n", 644 | "\n", 645 | "phi_grid = range(0, 1, length = 100)\n", 646 | "\n", 647 | "plot(phi_grid, [xbar(phi) * (1 - phi) for phi in phi_grid], color = :blue,\n", 648 | " label = L\"w^\\phi\", legendfont = font(12), xlabel = L\"\\phi\",\n", 649 | " guidefont = font(16), grid = false, legend = :topleft)" 650 | ] 651 | }, 652 | { 653 | "cell_type": "markdown", 654 | "id": "2bf4067c", 655 | "metadata": {}, 656 | "source": [ 657 | "Observe that the maximizer is around 0.6.\n", 658 | "\n", 659 | "This this is similar to the long run value for $ \\phi $ obtained in\n", 660 | "exercise 1.\n", 661 | "\n", 662 | "Hence the behaviour of the infinitely patent worker is similar to that\n", 663 | "of the worker with $ \\beta = 0.96 $.\n", 664 | "\n", 665 | "This seems reasonable, and helps us confirm that our dynamic programming\n", 666 | "solutions are probably correct." 667 | ] 668 | } 669 | ], 670 | "metadata": { 671 | "date": 1766028218.5624878, 672 | "filename": "jv.md", 673 | "kernelspec": { 674 | "display_name": "Julia", 675 | "language": "julia", 676 | "name": "julia-1.12" 677 | }, 678 | "title": "Job Search V: On-the-Job Search" 679 | }, 680 | "nbformat": 4, 681 | "nbformat_minor": 5 682 | } -------------------------------------------------------------------------------- /dynamic_programming/career.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "475c42a1", 6 | "metadata": {}, 7 | "source": [ 8 | "\n", 9 | "" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "dff1e47f", 15 | "metadata": {}, 16 | "source": [ 17 | "# Job Search IV: Modeling Career Choice\n", 18 | "\n", 19 | "\n", 20 | "" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "d5167b93", 26 | "metadata": {}, 27 | "source": [ 28 | "## Contents\n", 29 | "\n", 30 | "- [Job Search IV: Modeling Career Choice](#Job-Search-IV:-Modeling-Career-Choice) \n", 31 | " - [Overview](#Overview) \n", 32 | " - [Model](#Model) \n", 33 | " - [Exercises](#Exercises) \n", 34 | " - [Solutions](#Solutions) " 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "id": "c1055764", 40 | "metadata": {}, 41 | "source": [ 42 | "## Overview\n", 43 | "\n", 44 | "Next we study a computational problem concerning career and job choices.\n", 45 | "\n", 46 | "The model is originally due to Derek Neal [[Nea99](https://julia.quantecon.org/../zreferences.html#id115)].\n", 47 | "\n", 48 | "This exposition draws on the presentation in [[LS18](https://julia.quantecon.org/../zreferences.html#id101)], section 6.5." 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "id": "62c82dfa", 54 | "metadata": {}, 55 | "source": [ 56 | "### Model features\n", 57 | "\n", 58 | "- Career and job within career both chosen to maximize expected discounted wage flow. \n", 59 | "- Infinite horizon dynamic programming with two state variables. " 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": null, 65 | "id": "e3289f5b", 66 | "metadata": { 67 | "hide-output": false 68 | }, 69 | "outputs": [], 70 | "source": [ 71 | "using LinearAlgebra, Statistics, NLsolve" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "id": "21f9b8f7", 77 | "metadata": {}, 78 | "source": [ 79 | "## Model\n", 80 | "\n", 81 | "In what follows we distinguish between a career and a job, where\n", 82 | "\n", 83 | "- a *career* is understood to be a general field encompassing many possible jobs, and \n", 84 | "- a *job* is understood to be a position with a particular firm \n", 85 | "\n", 86 | "\n", 87 | "For workers, wages can be decomposed into the contribution of job and career\n", 88 | "\n", 89 | "- $ w_t = \\theta_t + \\epsilon_t $, where \n", 90 | " - $ \\theta_t $ is contribution of career at time $ t $ \n", 91 | " - $ \\epsilon_t $ is contribution of job at time $ t $ \n", 92 | "\n", 93 | "\n", 94 | "At the start of time $ t $, a worker has the following options\n", 95 | "\n", 96 | "- retain a current (career, job) pair $ (\\theta_t, \\epsilon_t) $\n", 97 | " — referred to hereafter as “stay put” \n", 98 | "- retain a current career $ \\theta_t $ but redraw a job $ \\epsilon_t $\n", 99 | " — referred to hereafter as “new job” \n", 100 | "- redraw both a career $ \\theta_t $ and a job $ \\epsilon_t $\n", 101 | " — referred to hereafter as “new life” \n", 102 | "\n", 103 | "\n", 104 | "Draws of $ \\theta $ and $ \\epsilon $ are independent of each other and\n", 105 | "past values, with\n", 106 | "\n", 107 | "- $ \\theta_t \\sim F $ \n", 108 | "- $ \\epsilon_t \\sim G $ \n", 109 | "\n", 110 | "\n", 111 | "Notice that the worker does not have the option to retain a job but redraw\n", 112 | "a career — starting a new career always requires starting a new job.\n", 113 | "\n", 114 | "A young worker aims to maximize the expected sum of discounted wages.\n", 115 | "\n", 116 | "\n", 117 | "\n", 118 | "$$\n", 119 | "\\mathbb{E} \\sum_{t=0}^{\\infty} \\beta^t w_t \\tag{34.1}\n", 120 | "$$\n", 121 | "\n", 122 | "subject to the choice restrictions specified above.\n", 123 | "\n", 124 | "Let $ V(\\theta, \\epsilon) $ denote the value function, which is the\n", 125 | "maximum of [(34.1)](#equation-exw) over all feasible (career, job) policies, given the\n", 126 | "initial state $ (\\theta, \\epsilon) $.\n", 127 | "\n", 128 | "The value function obeys\n", 129 | "\n", 130 | "$$\n", 131 | "V(\\theta, \\epsilon) = \\max\\{I, II, III\\},\n", 132 | "$$\n", 133 | "\n", 134 | "where\n", 135 | "\n", 136 | "\n", 137 | "\n", 138 | "$$\n", 139 | "\\begin{aligned}\n", 140 | "& I = \\theta + \\epsilon + \\beta V(\\theta, \\epsilon) \\\\\n", 141 | "& II = \\theta + \\int \\epsilon' G(d \\epsilon') + \\beta \\int V(\\theta, \\epsilon') G(d \\epsilon') \\nonumber \\\\\n", 142 | "& III = \\int \\theta' F(d \\theta') + \\int \\epsilon' G(d \\epsilon') + \\beta \\int \\int V(\\theta', \\epsilon') G(d \\epsilon') F(d \\theta') \\nonumber\n", 143 | "\\end{aligned} \\tag{34.2}\n", 144 | "$$\n", 145 | "\n", 146 | "Evidently $ I $, $ II $ and $ III $ correspond to “stay put”, “new job” and “new life”, respectively." 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "id": "6411cb9b", 152 | "metadata": {}, 153 | "source": [ 154 | "### Parameterization\n", 155 | "\n", 156 | "As in [[LS18](https://julia.quantecon.org/../zreferences.html#id101)], section 6.5, we will focus on a discrete version of the model, parameterized as follows:\n", 157 | "\n", 158 | "- both $ \\theta $ and $ \\epsilon $ take values in the set `linspace(0, B, N)` — an even grid of $ N $ points between $ 0 $ and $ B $ inclusive \n", 159 | "- $ N = 50 $ \n", 160 | "- $ B = 5 $ \n", 161 | "- $ \\beta = 0.95 $ \n", 162 | "\n", 163 | "\n", 164 | "The distributions $ F $ and $ G $ are discrete distributions\n", 165 | "generating draws from the grid points `linspace(0, B, N)`.\n", 166 | "\n", 167 | "A very useful family of discrete distributions is the Beta-binomial family,\n", 168 | "with probability mass function\n", 169 | "\n", 170 | "$$\n", 171 | "p(k \\,|\\, n, a, b)\n", 172 | "= {n \\choose k} \\frac{B(k + a, n - k + b)}{B(a, b)},\n", 173 | "\\qquad k = 0, \\ldots, n\n", 174 | "$$\n", 175 | "\n", 176 | "Interpretation:\n", 177 | "\n", 178 | "- draw $ q $ from a $ \\beta $ distribution with shape parameters $ (a, b) $ \n", 179 | "- run $ n $ independent binary trials, each with success probability $ q $ \n", 180 | "- $ p(k \\,|\\, n, a, b) $ is the probability of $ k $ successes in these $ n $ trials \n", 181 | "\n", 182 | "\n", 183 | "Nice properties:\n", 184 | "\n", 185 | "- very flexible class of distributions, including uniform, symmetric unimodal, etc. \n", 186 | "- only three parameters \n", 187 | "\n", 188 | "\n", 189 | "Here’s a figure showing the effect of different shape parameters when $ n=50 $.\n", 190 | "\n", 191 | "\n", 192 | "" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": null, 198 | "id": "4a2b7a0a", 199 | "metadata": { 200 | "hide-output": false 201 | }, 202 | "outputs": [], 203 | "source": [ 204 | "using LaTeXStrings, Plots, Distributions\n", 205 | "\n", 206 | "n = 50\n", 207 | "a_vals = [0.5, 1, 100]\n", 208 | "b_vals = [0.5, 1, 100]\n", 209 | "\n", 210 | "plt = plot()\n", 211 | "for (a, b) in zip(a_vals, b_vals)\n", 212 | " ab_label = L\"$a = %$a, b = %$b$\"\n", 213 | " dist = BetaBinomial(n, a, b)\n", 214 | " plot!(plt, 0:n, pdf.(dist, support(dist)), label = ab_label)\n", 215 | "end\n", 216 | "plt" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "id": "96d17c5e", 222 | "metadata": {}, 223 | "source": [ 224 | "Implementation:\n", 225 | "\n", 226 | "The code for solving the DP problem described above is found below:" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": null, 232 | "id": "e93bd209", 233 | "metadata": { 234 | "hide-output": false 235 | }, 236 | "outputs": [], 237 | "source": [ 238 | "function CareerWorkerProblem(; beta = 0.95,\n", 239 | " B = 5.0,\n", 240 | " N = 50,\n", 241 | " F_a = 1.0,\n", 242 | " F_b = 1.0,\n", 243 | " G_a = 1.0,\n", 244 | " G_b = 1.0)\n", 245 | " theta = range(0, B, length = N)\n", 246 | " epsilon = copy(theta)\n", 247 | " dist_F = BetaBinomial(N - 1, F_a, F_b)\n", 248 | " dist_G = BetaBinomial(N - 1, G_a, G_b)\n", 249 | " F_probs = pdf.(dist_F, support(dist_F))\n", 250 | " G_probs = pdf.(dist_G, support(dist_G))\n", 251 | " F_mean = sum(theta .* F_probs)\n", 252 | " G_mean = sum(epsilon .* G_probs)\n", 253 | " return (; beta, N, B, theta, epsilon, F_probs, G_probs, F_mean, G_mean)\n", 254 | "end\n", 255 | "\n", 256 | "function update_bellman!(cp, v, out; ret_policy = false)\n", 257 | "\n", 258 | " # new life. This is a function of the distribution parameters and is\n", 259 | " # always constant. No need to recompute it in the loop\n", 260 | " v3 = (cp.G_mean + cp.F_mean .+ cp.beta .* cp.F_probs' * v * cp.G_probs)[1] # do not need 1 element array\n", 261 | "\n", 262 | " for j in 1:(cp.N)\n", 263 | " for i in 1:(cp.N)\n", 264 | " # stay put\n", 265 | " v1 = cp.theta[i] + cp.epsilon[j] + cp.beta * v[i, j]\n", 266 | "\n", 267 | " # new job\n", 268 | " v2 = (cp.theta[i] .+ cp.G_mean .+ cp.beta .* v[i, :]' * cp.G_probs)[1] # do not need a single element array\n", 269 | "\n", 270 | " if ret_policy\n", 271 | " if v1 > max(v2, v3)\n", 272 | " action = 1\n", 273 | " elseif v2 > max(v1, v3)\n", 274 | " action = 2\n", 275 | " else\n", 276 | " action = 3\n", 277 | " end\n", 278 | " out[i, j] = action\n", 279 | " else\n", 280 | " out[i, j] = max(v1, v2, v3)\n", 281 | " end\n", 282 | " end\n", 283 | " end\n", 284 | "end\n", 285 | "\n", 286 | "function update_bellman(cp, v; ret_policy = false)\n", 287 | " out = similar(v)\n", 288 | " update_bellman!(cp, v, out, ret_policy = ret_policy)\n", 289 | " return out\n", 290 | "end\n", 291 | "\n", 292 | "function get_greedy!(cp, v, out)\n", 293 | " update_bellman!(cp, v, out, ret_policy = true)\n", 294 | "end\n", 295 | "\n", 296 | "function get_greedy(cp, v)\n", 297 | " update_bellman(cp, v, ret_policy = true)\n", 298 | "end" 299 | ] 300 | }, 301 | { 302 | "cell_type": "markdown", 303 | "id": "b5579c19", 304 | "metadata": {}, 305 | "source": [ 306 | "The code defines\n", 307 | "\n", 308 | "- a named tuple `CareerWorkerProblem` that \n", 309 | " - encapsulates all the details of a particular parameterization \n", 310 | " - implements the Bellman operator $ T $ \n", 311 | "\n", 312 | "\n", 313 | "In this model, $ T $ is defined by $ Tv(\\theta, \\epsilon) = \\max\\{I, II, III\\} $, where\n", 314 | "$ I $, $ II $ and $ III $ are as given in [(34.2)](#equation-eyes), replacing $ V $ with $ v $.\n", 315 | "\n", 316 | "The default probability distributions in `CareerWorkerProblem` correspond to discrete uniform distributions (see [the Beta-binomial figure](#beta-binom)).\n", 317 | "\n", 318 | "In fact all our default settings correspond to the version studied in [[LS18](https://julia.quantecon.org/../zreferences.html#id101)], section 6.5.\n", 319 | "\n", 320 | "Hence we can reproduce figures 6.5.1 and 6.5.2 shown there, which exhibit the\n", 321 | "value function and optimal policy respectively.\n", 322 | "\n", 323 | "Here’s the value function" 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": null, 329 | "id": "4a1cfb79", 330 | "metadata": { 331 | "hide-output": false 332 | }, 333 | "outputs": [], 334 | "source": [ 335 | "wp = CareerWorkerProblem()\n", 336 | "v_init = fill(100.0, wp.N, wp.N)\n", 337 | "func(x) = update_bellman(wp, x)\n", 338 | "sol = fixedpoint(func, v_init)\n", 339 | "v = sol.zero\n", 340 | "\n", 341 | "plot(linetype = :surface, wp.theta, wp.epsilon, transpose(v),\n", 342 | " xlabel = L\"\\theta\",\n", 343 | " ylabel = L\"\\epsilon\",\n", 344 | " seriescolor = :plasma, gridalpha = 1)" 345 | ] 346 | }, 347 | { 348 | "cell_type": "markdown", 349 | "id": "95ac8050", 350 | "metadata": {}, 351 | "source": [ 352 | "The optimal policy can be represented as follows (see [Exercise 3](#career-ex3) for code).\n", 353 | "\n", 354 | "\n", 355 | "\n", 356 | "![https://julia.quantecon.org/_static/figures/career_solutions_ex3_jl.png](https://julia.quantecon.org/_static/figures/career_solutions_ex3_jl.png)\n", 357 | "\n", 358 | " \n", 359 | "Interpretation:\n", 360 | "\n", 361 | "- If both job and career are poor or mediocre, the worker will experiment with new job and new career. \n", 362 | "- If career is sufficiently good, the worker will hold it and experiment with new jobs until a sufficiently good one is found. \n", 363 | "- If both job and career are good, the worker will stay put. \n", 364 | "\n", 365 | "\n", 366 | "Notice that the worker will always hold on to a sufficiently good career, but not necessarily hold on to even the best paying job.\n", 367 | "\n", 368 | "The reason is that high lifetime wages require both variables to be large, and\n", 369 | "the worker cannot change careers without changing jobs.\n", 370 | "\n", 371 | "- Sometimes a good job must be sacrificed in order to change to a better career. " 372 | ] 373 | }, 374 | { 375 | "cell_type": "markdown", 376 | "id": "74e9e3a4", 377 | "metadata": {}, 378 | "source": [ 379 | "## Exercises\n", 380 | "\n", 381 | "\n", 382 | "" 383 | ] 384 | }, 385 | { 386 | "cell_type": "markdown", 387 | "id": "d8042e30", 388 | "metadata": {}, 389 | "source": [ 390 | "### Exercise 1\n", 391 | "\n", 392 | "Using the default parameterization in the `CareerWorkerProblem`,\n", 393 | "generate and plot typical sample paths for $ \\theta $ and $ \\epsilon $\n", 394 | "when the worker follows the optimal policy.\n", 395 | "\n", 396 | "In particular, modulo randomness, reproduce the following figure (where the horizontal axis represents time)\n", 397 | "\n", 398 | "![https://julia.quantecon.org/_static/figures/career_solutions_ex1_jl.png](https://julia.quantecon.org/_static/figures/career_solutions_ex1_jl.png)\n", 399 | "\n", 400 | " \n", 401 | "Hint: To generate the draws from the distributions $ F $ and $ G $, you can use the `Categorical` distribution from the `Distributions` package.\n", 402 | "\n", 403 | "\n", 404 | "" 405 | ] 406 | }, 407 | { 408 | "cell_type": "markdown", 409 | "id": "21049c82", 410 | "metadata": {}, 411 | "source": [ 412 | "### Exercise 2\n", 413 | "\n", 414 | "Let’s now consider how long it takes for the worker to settle down to a\n", 415 | "permanent job, given a starting point of $ (\\theta, \\epsilon) = (0, 0) $.\n", 416 | "\n", 417 | "In other words, we want to study the distribution of the random variable\n", 418 | "\n", 419 | "$$\n", 420 | "T^* := \\text{the first point in time from which the worker's job no longer changes}\n", 421 | "$$\n", 422 | "\n", 423 | "Evidently, the worker’s job becomes permanent if and only if $ (\\theta_t, \\epsilon_t) $ enters the\n", 424 | "“stay put” region of $ (\\theta, \\epsilon) $ space.\n", 425 | "\n", 426 | "Letting $ S $ denote this region, $ T^* $ can be expressed as the\n", 427 | "first passage time to $ S $ under the optimal policy:\n", 428 | "\n", 429 | "$$\n", 430 | "T^* := \\inf\\{t \\geq 0 \\,|\\, (\\theta_t, \\epsilon_t) \\in S\\}\n", 431 | "$$\n", 432 | "\n", 433 | "Collect 25,000 draws of this random variable and compute the median (which should be about 7).\n", 434 | "\n", 435 | "Repeat the exercise with $ \\beta=0.99 $ and interpret the change.\n", 436 | "\n", 437 | "\n", 438 | "" 439 | ] 440 | }, 441 | { 442 | "cell_type": "markdown", 443 | "id": "587141dd", 444 | "metadata": {}, 445 | "source": [ 446 | "### Exercise 3\n", 447 | "\n", 448 | "As best you can, reproduce [the figure showing the optimal policy](#career-opt-pol).\n", 449 | "\n", 450 | "Hint: The `get_greedy()` method returns a representation of the optimal\n", 451 | "policy where values 1, 2 and 3 correspond to “stay put”, “new job” and “new life” respectively. Use this and the plots functions (e.g., `contour, contour!`) to produce the different shadings.\n", 452 | "\n", 453 | "Now set `G_a = G_b = 100` and generate a new figure with these parameters. Interpret." 454 | ] 455 | }, 456 | { 457 | "cell_type": "markdown", 458 | "id": "e4e76f51", 459 | "metadata": {}, 460 | "source": [ 461 | "## Solutions" 462 | ] 463 | }, 464 | { 465 | "cell_type": "markdown", 466 | "id": "04d80810", 467 | "metadata": {}, 468 | "source": [ 469 | "### Exercise 1" 470 | ] 471 | }, 472 | { 473 | "cell_type": "code", 474 | "execution_count": null, 475 | "id": "64d3cfd6", 476 | "metadata": { 477 | "hide-output": false 478 | }, 479 | "outputs": [], 480 | "source": [ 481 | "wp = CareerWorkerProblem()\n", 482 | "\n", 483 | "function solve_wp(wp)\n", 484 | " v_init = fill(100.0, wp.N, wp.N)\n", 485 | " func(x) = update_bellman(wp, x)\n", 486 | " sol = fixedpoint(func, v_init)\n", 487 | " v = sol.zero\n", 488 | " optimal_policy = get_greedy(wp, v)\n", 489 | " return v, optimal_policy\n", 490 | "end\n", 491 | "\n", 492 | "v, optimal_policy = solve_wp(wp)\n", 493 | "\n", 494 | "F = Categorical(wp.F_probs)\n", 495 | "G = Categorical(wp.G_probs)\n", 496 | "\n", 497 | "function gen_path(T = 20)\n", 498 | " i = j = 1\n", 499 | " theta_ind = Int[]\n", 500 | " epsilon_ind = Int[]\n", 501 | "\n", 502 | " for t in 1:T\n", 503 | " # do nothing if stay put\n", 504 | " if optimal_policy[i, j] == 2 # new job\n", 505 | " j = rand(G)\n", 506 | " elseif optimal_policy[i, j] == 3 # new life\n", 507 | " i, j = rand(F), rand(G)\n", 508 | " end\n", 509 | " push!(theta_ind, i)\n", 510 | " push!(epsilon_ind, j)\n", 511 | " end\n", 512 | " return wp.theta[theta_ind], wp.epsilon[epsilon_ind]\n", 513 | "end\n", 514 | "\n", 515 | "plot_array = Any[]\n", 516 | "for i in 1:2\n", 517 | " theta_path, epsilon_path = gen_path()\n", 518 | " plt = plot(epsilon_path, label = L\"\\epsilon\")\n", 519 | " plot!(plt, theta_path, label = L\"\\theta\")\n", 520 | " plot!(plt, legend = :bottomright)\n", 521 | " push!(plot_array, plt)\n", 522 | "end\n", 523 | "plot(plot_array..., layout = (2, 1))" 524 | ] 525 | }, 526 | { 527 | "cell_type": "markdown", 528 | "id": "9752ee75", 529 | "metadata": {}, 530 | "source": [ 531 | "### Exercise 2\n", 532 | "\n", 533 | "The median for the original parameterization can be computed as follows" 534 | ] 535 | }, 536 | { 537 | "cell_type": "code", 538 | "execution_count": null, 539 | "id": "0a43856f", 540 | "metadata": { 541 | "hide-output": false 542 | }, 543 | "outputs": [], 544 | "source": [ 545 | "function gen_first_passage_time(optimal_policy)\n", 546 | " t = 0\n", 547 | " i = j = 1\n", 548 | " while true\n", 549 | " if optimal_policy[i, j] == 1 # Stay put\n", 550 | " return t\n", 551 | " elseif optimal_policy[i, j] == 2 # New job\n", 552 | " j = rand(G)[1]\n", 553 | " else # New life\n", 554 | " i, j = rand(F)[1], rand(G)[1]\n", 555 | " end\n", 556 | " t += 1\n", 557 | " end\n", 558 | "end\n", 559 | "\n", 560 | "M = 25000\n", 561 | "samples = zeros(M)\n", 562 | "for i in 1:M\n", 563 | " samples[i] = gen_first_passage_time(optimal_policy)\n", 564 | "end\n", 565 | "print(median(samples))" 566 | ] 567 | }, 568 | { 569 | "cell_type": "markdown", 570 | "id": "d2fb0a7f", 571 | "metadata": {}, 572 | "source": [ 573 | "To compute the median with $ \\beta=0.99 $ instead of the default value $ \\beta=0.95 $, replace `wp=CareerWorkerProblem()` with `wp=CareerWorkerProblem(beta=0.99)`.\n", 574 | "\n", 575 | "The medians are subject to randomness, but should be about 7 and 14 respectively. Not surprisingly, more patient workers will wait longer to settle down to their final job." 576 | ] 577 | }, 578 | { 579 | "cell_type": "code", 580 | "execution_count": null, 581 | "id": "899590b8", 582 | "metadata": { 583 | "hide-output": false 584 | }, 585 | "outputs": [], 586 | "source": [ 587 | "wp2 = CareerWorkerProblem(beta = 0.99)\n", 588 | "\n", 589 | "v2, optimal_policy2 = solve_wp(wp2)\n", 590 | "\n", 591 | "samples2 = zeros(M)\n", 592 | "for i in 1:M\n", 593 | " samples2[i] = gen_first_passage_time(optimal_policy2)\n", 594 | "end\n", 595 | "print(median(samples2))" 596 | ] 597 | }, 598 | { 599 | "cell_type": "markdown", 600 | "id": "4fef7ceb", 601 | "metadata": {}, 602 | "source": [ 603 | "### Exercise 3\n", 604 | "\n", 605 | "Here’s the code to reproduce the original figure" 606 | ] 607 | }, 608 | { 609 | "cell_type": "code", 610 | "execution_count": null, 611 | "id": "82d53983", 612 | "metadata": { 613 | "hide-output": false 614 | }, 615 | "outputs": [], 616 | "source": [ 617 | "wp = CareerWorkerProblem();\n", 618 | "v, optimal_policy = solve_wp(wp)\n", 619 | "\n", 620 | "lvls = [0.5, 1.5, 2.5, 3.5]\n", 621 | "x_grid = range(0, 5, length = 50)\n", 622 | "y_grid = range(0, 5, length = 50)\n", 623 | "\n", 624 | "contour(x_grid, y_grid, optimal_policy', fill = true, levels = lvls,\n", 625 | " color = :Blues,\n", 626 | " fillalpha = 1, cbar = false)\n", 627 | "contour!(xlabel = L\"\\theta\", ylabel = L\"\\epsilon\")\n", 628 | "annotate!([(1.8, 2.5, text(\"new life\", 14, :white, :center))])\n", 629 | "annotate!([(4.5, 2.5, text(\"new job\", 14, :center))])\n", 630 | "annotate!([(4.0, 4.5, text(\"stay put\", 14, :center))])" 631 | ] 632 | }, 633 | { 634 | "cell_type": "markdown", 635 | "id": "5e84438a", 636 | "metadata": {}, 637 | "source": [ 638 | "Now, we need only swap out for the new parameters" 639 | ] 640 | }, 641 | { 642 | "cell_type": "code", 643 | "execution_count": null, 644 | "id": "f495100b", 645 | "metadata": { 646 | "hide-output": false 647 | }, 648 | "outputs": [], 649 | "source": [ 650 | "wp = CareerWorkerProblem(G_a = 100.0, G_b = 100.0); # use new params\n", 651 | "v, optimal_policy = solve_wp(wp)\n", 652 | "\n", 653 | "lvls = [0.5, 1.5, 2.5, 3.5]\n", 654 | "x_grid = range(0, 5, length = 50)\n", 655 | "y_grid = range(0, 5, length = 50)\n", 656 | "\n", 657 | "contour(x_grid, y_grid, optimal_policy', fill = true, levels = lvls,\n", 658 | " color = :Blues,\n", 659 | " fillalpha = 1, cbar = false)\n", 660 | "contour!(xlabel = L\"\\theta\", ylabel = L\"\\epsilon\")\n", 661 | "annotate!([(1.8, 2.5, text(\"new life\", 14, :white, :center))])\n", 662 | "annotate!([(4.5, 2.5, text(\"new job\", 14, :center))])\n", 663 | "annotate!([(4.0, 4.5, text(\"stay put\", 14, :center))])" 664 | ] 665 | }, 666 | { 667 | "cell_type": "markdown", 668 | "id": "add98db7", 669 | "metadata": {}, 670 | "source": [ 671 | "You will see that the region for which the worker\n", 672 | "will stay put has grown because the distribution for $ \\epsilon $\n", 673 | "has become more concentrated around the mean, making high-paying jobs\n", 674 | "less realistic." 675 | ] 676 | } 677 | ], 678 | "metadata": { 679 | "date": 1766028218.1285794, 680 | "filename": "career.md", 681 | "kernelspec": { 682 | "display_name": "Julia", 683 | "language": "julia", 684 | "name": "julia-1.12" 685 | }, 686 | "title": "Job Search IV: Modeling Career Choice" 687 | }, 688 | "nbformat": 4, 689 | "nbformat_minor": 5 690 | } --------------------------------------------------------------------------------