diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..7809c2a97 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + commit-message: + prefix: ⬆️ + schedule: + interval: weekly diff --git a/.github/workflows/cache.yml b/.github/workflows/cache.yml index 5205b0173..e2f45418c 100644 --- a/.github/workflows/cache.yml +++ b/.github/workflows/cache.yml @@ -8,14 +8,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Anaconda - uses: conda-incubator/setup-miniconda@v2 + uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true auto-activate-base: true miniconda-version: 'latest' - python-version: "3.11" + python-version: "3.12" environment-file: environment.yml activate-environment: quantecon - name: graphviz Support # TODO: required? @@ -39,13 +39,14 @@ jobs: run: | jb build lectures --path-output ./ -W --keep-going - name: Upload Execution Reports (HTML) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: failure() with: name: execution-reports path: _build/html/reports - name: Upload "_build" folder (cache) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: build-cache - path: _build \ No newline at end of file + path: _build + include-hidden-files: true \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ffaf30d20..02ad4edf5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: auto-update-conda: true auto-activate-base: true miniconda-version: 'latest' - python-version: "3.11" + python-version: "3.12" environment-file: environment.yml activate-environment: quantecon - name: Graphics Support #TODO: Review if graphviz is needed @@ -38,7 +38,7 @@ jobs: shell: bash -l {0} run: pip list - name: Download "build" folder (cache) - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v11 with: workflow: cache.yml branch: main @@ -78,7 +78,7 @@ jobs: name: execution-reports path: _build/html/reports - name: Preview Deploy to Netlify - uses: nwtgck/actions-netlify@v2 + uses: nwtgck/actions-netlify@v3.0 with: publish-dir: '_build/html/' production-branch: main diff --git a/.github/workflows/collab.yml b/.github/workflows/collab.yml new file mode 100644 index 000000000..069deda1d --- /dev/null +++ b/.github/workflows/collab.yml @@ -0,0 +1,54 @@ +name: Build Project on Google Collab (Execution) +on: [pull_request] + +jobs: + test: + runs-on: quantecon-large + container: + image: us-docker.pkg.dev/colab-images/public/runtime:latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Check for dockerenv file + run: (ls /.dockerenv && echo Found dockerenv) || (echo No dockerenv) + - name: Check python version + shell: bash -l {0} + run: | + python --version + - name: Display Pip Versions + shell: bash -l {0} + run: pip list + - name: Download "build" folder (cache) + uses: dawidd6/action-download-artifact@v11 + with: + workflow: cache.yml + branch: main + name: build-cache + path: _build + # Install build software + - name: Install Build Software + shell: bash -l {0} + run: | + pip install jupyter-book==0.15.1 docutils==0.17.1 quantecon-book-theme==0.7.2 sphinx-tojupyter==0.3.0 sphinxext-rediraffe==0.2.7 sphinx-exercise==0.4.1 sphinxcontrib-youtube==1.1.0 sphinx-togglebutton==0.3.1 arviz==0.13.0 sphinx_proof==0.2.0 sphinx_reredirects==0.1.3 + # Build of HTML (Execution Testing) + - name: Build HTML + shell: bash -l {0} + run: | + jb build lectures --path-output ./ -n -W --keep-going + - name: Upload Execution Reports + uses: actions/upload-artifact@v4 + if: failure() + with: + name: execution-reports + path: _build/html/reports + - name: Preview Deploy to Netlify + uses: nwtgck/actions-netlify@v3.0 + with: + publish-dir: '_build/html/' + production-branch: main + github-token: ${{ secrets.GITHUB_TOKEN }} + deploy-message: "Preview Deploy from GitHub Actions" + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml index 79f0578b9..cada059f3 100644 --- a/.github/workflows/linkcheck.yml +++ b/.github/workflows/linkcheck.yml @@ -1,44 +1,31 @@ name: Link Checker [Anaconda, Linux] on: - pull_request: - types: [opened, reopened] schedule: - # UTC 12:00 is early morning in Australia - - cron: '0 12 * * *' + # UTC 23:00 is early morning in Australia (9am) + - cron: '0 23 * * *' + workflow_dispatch: jobs: - link-check-linux: - name: Link Checking (${{ matrix.python-version }}, ${{ matrix.os }}) - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: ["ubuntu-latest"] - python-version: ["3.11"] + link-checking: + name: Link Checking + runs-on: "ubuntu-latest" + permissions: + issues: write # required for peter-evans/create-issue-from-file steps: + # Checkout the live site (html) - name: Checkout - uses: actions/checkout@v2 - - name: Setup Anaconda - uses: conda-incubator/setup-miniconda@v2 + uses: actions/checkout@v4 with: - auto-update-conda: true - auto-activate-base: true - miniconda-version: 'latest' - python-version: "3.11" - environment-file: environment.yml - activate-environment: quantecon - - name: Download "build" folder (cache) - uses: dawidd6/action-download-artifact@v2 - with: - workflow: cache.yml - branch: main - name: build-cache - path: _build + ref: gh-pages - name: Link Checker - shell: bash -l {0} - run: jb build lectures --path-output=./ --builder=custom --custom-builder=linkcheck - - name: Upload Link Checker Reports - uses: actions/upload-artifact@v2 - if: failure() + id: lychee + uses: lycheeverse/lychee-action@v2 + with: + fail: false + args: --accept 403,503 *.html + - name: Create Issue From File + if: steps.lychee.outputs.exit_code != 0 + uses: peter-evans/create-issue-from-file@v5 with: - name: linkcheck-reports - path: _build/linkcheck \ No newline at end of file + title: Link Checker Report + content-filepath: ./lychee/out.md + labels: report, automated issue, linkchecker \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c2531730f..6d195b53d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,14 +9,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Anaconda - uses: conda-incubator/setup-miniconda@v2 + uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true auto-activate-base: true miniconda-version: 'latest' - python-version: "3.11" + python-version: "3.12" environment-file: environment.yml activate-environment: quantecon - name: Install latex dependencies @@ -39,7 +39,7 @@ jobs: shell: bash -l {0} run: pip list - name: Download "build" folder (cache) - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v11 with: workflow: cache.yml branch: main @@ -73,7 +73,7 @@ jobs: rm -r _build/.doctrees jb build lectures --path-output ./ - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v1.1 + uses: nwtgck/actions-netlify@v3.0 with: publish-dir: '_build/html/' production-branch: main @@ -83,13 +83,13 @@ jobs: NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - name: Deploy website to gh-pages - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: _build/html/ cname: intro.quantecon.org - name: Upload "_build" folder (cache) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: build-publish path: _build diff --git a/environment.yml b/environment.yml index 52036b809..2602bab0b 100644 --- a/environment.yml +++ b/environment.yml @@ -3,24 +3,17 @@ channels: - default - conda-forge dependencies: - - python=3.11 - - anaconda=2024.02 + - python=3.12 + - anaconda=2024.10 - pip - pip: - - jupyter-book==0.15.1 - - docutils==0.17.1 - - quantecon-book-theme==0.7.1 + - jupyter-book==1.0.3 + - quantecon-book-theme==0.8.2 - sphinx-tojupyter==0.3.0 - sphinxext-rediraffe==0.2.7 - - sphinx-exercise==0.4.1 - - sphinx-proof==0.1.3 - - ghp-import==1.1.0 - - sphinxcontrib-youtube==1.1.0 - - sphinx-togglebutton==0.3.1 - # Sandpit Requirements - # - PuLP - # - cvxpy - # - cvxopt - # - cylp - # - array-to-latex - # - prettytable + - sphinx-exercise==1.0.1 + - ghp-import==2.1.0 + - sphinxcontrib-youtube==1.3.0 #Version 1.3.0 is required as quantecon-book-theme is only compatible with sphinx<=5 + - sphinx-proof==0.2.0 + - sphinx-togglebutton==0.3.2 + - sphinx-reredirects==0.1.4 #Version 0.1.5 requires sphinx>=7.1 diff --git a/lectures/_config.yml b/lectures/_config.yml index 1d5a36e67..069af81d3 100644 --- a/lectures/_config.yml +++ b/lectures/_config.yml @@ -35,7 +35,7 @@ latex: targetname: quantecon-python-intro.tex sphinx: - extra_extensions: [sphinx_multitoc_numbering, sphinxext.rediraffe, sphinx_exercise, sphinx_togglebutton, sphinx.ext.intersphinx, sphinx_proof, sphinx_tojupyter] + extra_extensions: [sphinx_multitoc_numbering, sphinxext.rediraffe, sphinx_exercise, sphinx_togglebutton, sphinx.ext.intersphinx, sphinx_proof, sphinx_tojupyter, sphinx_reredirects] config: bibtex_reference_style: author_year # false-positive links @@ -45,6 +45,7 @@ sphinx: width: 80% nb_code_prompt_show: "Show {type}" suppress_warnings: [mystnb.unknown_mime_type, myst.domains] + proof_minimal_theme: true # ------------- html_js_files: - https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js @@ -70,11 +71,12 @@ sphinx: analytics: google_analytics_id: G-QDS1YRJNGM launch_buttons: - notebook_interface : classic # The interface interactive links will activate ["classic", "jupyterlab"] - binderhub_url : https://mybinder.org # The URL of the BinderHub (e.g., https://mybinder.org) colab_url : https://colab.research.google.com thebe : false # Add a thebe button to pages (requires the repository to run on Binder) intersphinx_mapping: + intermediate: + - https://python.quantecon.org/ + - null pyprog: - https://python-programming.quantecon.org/ - null @@ -82,22 +84,22 @@ sphinx: - https://intro.quantecon.org/ - null dle: - - https://quantecon.github.io/lecture-dle/ + - https://dle.quantecon.org/ - null dps: - - https://quantecon.github.io/lecture-dps/ + - https://dps.quantecon.org/ - null eqm: - - https://quantecon.github.io/lecture-eqm/ + - https://eqm.quantecon.org/ - null stats: - - https://quantecon.github.io/lecture-stats/ + - https://stats.quantecon.org/ - null tools: - - https://quantecon.github.io/lecture-tools-techniques/ + - https://tools-techniques.quantecon.org/ - null dynam: - - https://quantecon.github.io/lecture-dynamics/ + - https://dynamics.quantecon.org/ - null mathjax3_config: tex: @@ -107,6 +109,9 @@ sphinx: mathjax_path: https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js rediraffe_redirects: index_toc.md: intro.md + # Remote Redirects + redirects: + ak2: https://python.quantecon.org/ak2.html tojupyter_static_file_path: ["_static"] tojupyter_target_html: true tojupyter_urlpath: "https://intro.quantecon.org/" diff --git a/lectures/_static/lecture_specific/inequality/data.ipynb b/lectures/_static/lecture_specific/inequality/data.ipynb new file mode 100644 index 000000000..97aea6522 --- /dev/null +++ b/lectures/_static/lecture_specific/inequality/data.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "258b4bc9-2964-470a-8010-05c2162f5e05", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: wbgapi in /Users/longye/anaconda3/lib/python3.10/site-packages (1.0.12)\n", + "Requirement already satisfied: plotly in /Users/longye/anaconda3/lib/python3.10/site-packages (5.22.0)\n", + "Requirement already satisfied: requests in /Users/longye/anaconda3/lib/python3.10/site-packages (from wbgapi) (2.31.0)\n", + "Requirement already satisfied: tabulate in /Users/longye/anaconda3/lib/python3.10/site-packages (from wbgapi) (0.9.0)\n", + "Requirement already satisfied: PyYAML in /Users/longye/anaconda3/lib/python3.10/site-packages (from wbgapi) (6.0)\n", + "Requirement already satisfied: tenacity>=6.2.0 in /Users/longye/anaconda3/lib/python3.10/site-packages (from plotly) (8.4.1)\n", + "Requirement already satisfied: packaging in /Users/longye/anaconda3/lib/python3.10/site-packages (from plotly) (23.1)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/longye/anaconda3/lib/python3.10/site-packages (from requests->wbgapi) (1.26.16)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/longye/anaconda3/lib/python3.10/site-packages (from requests->wbgapi) (2.0.4)\n", + "Requirement already satisfied: idna<4,>=2.5 in /Users/longye/anaconda3/lib/python3.10/site-packages (from requests->wbgapi) (3.4)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /Users/longye/anaconda3/lib/python3.10/site-packages (from requests->wbgapi) (2024.6.2)\n" + ] + } + ], + "source": [ + "!pip install wbgapi plotly\n", + "\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import random as rd\n", + "import wbgapi as wb\n", + "import plotly.express as px\n", + "\n", + "url = 'https://media.githubusercontent.com/media/QuantEcon/high_dim_data/main/SCF_plus/SCF_plus_mini.csv'\n", + "df = pd.read_csv(url)\n", + "df_income_wealth = df.dropna()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "9630a07a-fce5-474e-92af-104e67e82be5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: quantecon in /Users/longye/anaconda3/lib/python3.10/site-packages (0.7.1)\n", + "Requirement already satisfied: requests in /Users/longye/anaconda3/lib/python3.10/site-packages (from quantecon) (2.31.0)\n", + "Requirement already satisfied: numpy>=1.17.0 in /Users/longye/anaconda3/lib/python3.10/site-packages (from quantecon) (1.26.3)\n", + "Requirement already satisfied: numba>=0.49.0 in /Users/longye/anaconda3/lib/python3.10/site-packages (from quantecon) (0.59.1)\n", + "Requirement already satisfied: sympy in /Users/longye/anaconda3/lib/python3.10/site-packages (from quantecon) (1.12)\n", + "Requirement already satisfied: scipy>=1.5.0 in /Users/longye/anaconda3/lib/python3.10/site-packages (from quantecon) (1.12.0)\n", + "Requirement already satisfied: llvmlite<0.43,>=0.42.0dev0 in /Users/longye/anaconda3/lib/python3.10/site-packages (from numba>=0.49.0->quantecon) (0.42.0)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /Users/longye/anaconda3/lib/python3.10/site-packages (from requests->quantecon) (2024.6.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /Users/longye/anaconda3/lib/python3.10/site-packages (from requests->quantecon) (3.4)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/longye/anaconda3/lib/python3.10/site-packages (from requests->quantecon) (2.0.4)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/longye/anaconda3/lib/python3.10/site-packages (from requests->quantecon) (1.26.16)\n", + "Requirement already satisfied: mpmath>=0.19 in /Users/longye/anaconda3/lib/python3.10/site-packages (from sympy->quantecon) (1.3.0)\n" + ] + } + ], + "source": [ + "!pip install quantecon\n", + "import quantecon as qe\n", + "\n", + "varlist = ['n_wealth', # net wealth \n", + " 't_income', # total income\n", + " 'l_income'] # labor income\n", + "\n", + "df = df_income_wealth\n", + "years = df.year.unique()\n", + "\n", + "# create lists to store Gini for each inequality measure\n", + "results = {}\n", + "\n", + "for var in varlist:\n", + " # create lists to store Gini\n", + " gini_yr = []\n", + " for year in years:\n", + " # repeat the observations according to their weights\n", + " counts = list(round(df[df['year'] == year]['weights'] ))\n", + " y = df[df['year'] == year][var].repeat(counts)\n", + " y = np.asarray(y)\n", + " \n", + " rd.shuffle(y) # shuffle the sequence\n", + " \n", + " # calculate and store Gini\n", + " gini = qe.gini_coefficient(y)\n", + " gini_yr.append(gini)\n", + " \n", + " results[var] = gini_yr\n", + "\n", + "# Convert to DataFrame\n", + "results = pd.DataFrame(results, index=years)\n", + "results.to_csv(\"usa-gini-nwealth-tincome-lincome.csv\", index_label='year')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d59e876b-2f77-4fa7-b79a-8e455ad82d43", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lectures/_static/lecture_specific/inequality/usa-gini-nwealth-tincome-lincome.csv b/lectures/_static/lecture_specific/inequality/usa-gini-nwealth-tincome-lincome.csv index bf8203640..3ec95a662 100644 --- a/lectures/_static/lecture_specific/inequality/usa-gini-nwealth-tincome-lincome.csv +++ b/lectures/_static/lecture_specific/inequality/usa-gini-nwealth-tincome-lincome.csv @@ -1,21 +1,21 @@ year,n_wealth,t_income,l_income -1950,0.8257332034366338,0.44248654139458626,0.5342948198773412 -1953,0.8059487586599329,0.4264544060935945,0.5158978980963702 -1956,0.8121790488050616,0.44426942873399283,0.5349293526208142 -1959,0.795206874163792,0.43749348077061573,0.5213985948309416 -1962,0.8086945076579359,0.4435843103853645,0.5345127915054341 -1965,0.7904149225687935,0.43763715466663444,0.7487860020887753 -1968,0.7982885066993497,0.4208620794438902,0.5242396427381545 -1971,0.7911574835420259,0.4233344246090255,0.5576454812313466 -1977,0.7571418922185215,0.46187678800902543,0.5704448110072049 -1983,0.7494335400643013,0.439345618464469,0.5662220844385915 -1989,0.7715705301674302,0.5115249581654197,0.601399568747142 -1992,0.7508126614055308,0.4740650672076798,0.5983592657979563 -1995,0.7569492388110265,0.48965523558400603,0.5969779516716903 -1998,0.7603291991801185,0.49117441585168614,0.5774462841723305 -2001,0.7816118750507056,0.5239092994681135,0.6042739644967272 -2004,0.7700355469522361,0.4884350383903255,0.5981432201792727 -2007,0.7821413776486978,0.5197156312086187,0.626345219575322 -2010,0.8250825295193438,0.5195972120145615,0.6453653328291903 -2013,0.8227698931835303,0.531400174984336,0.6498682917772644 -2016,0.8342975903562234,0.5541400068900825,0.6706846793375284 +1950,0.8257332034366366,0.44248654139458743,0.534294819877344 +1953,0.805948758659935,0.4264544060935942,0.5158978980963682 +1956,0.8121790488050612,0.44426942873399367,0.5349293526208106 +1959,0.7952068741637912,0.43749348077061534,0.5213985948309414 +1962,0.8086945076579386,0.44358431038536356,0.5345127915054446 +1965,0.7904149225687949,0.4376371546666344,0.7487860020887701 +1968,0.7982885066993503,0.4208620794438885,0.5242396427381534 +1971,0.7911574835420282,0.4233344246090255,0.5576454812313462 +1977,0.7571418922185215,0.46187678800902554,0.57044481100722 +1983,0.749433540064301,0.4393456184644682,0.5662220844385925 +1989,0.7715705301674285,0.5115249581654115,0.6013995687471289 +1992,0.7508126614055305,0.4740650672076754,0.5983592657979544 +1995,0.7569492388110274,0.4896552355840001,0.5969779516717039 +1998,0.7603291991801172,0.49117441585168525,0.5774462841723346 +2001,0.781611875050703,0.523909299468113,0.6042739644967232 +2004,0.7700355469522372,0.48843503839032354,0.5981432201792916 +2007,0.782141377648698,0.5197156312086207,0.6263452195753227 +2010,0.825082529519342,0.5195972120145641,0.6453653328291843 +2013,0.8227698931835299,0.5314001749843426,0.6498682917772886 +2016,0.8342975903562537,0.55414000689009,0.6706846793375292 diff --git a/lectures/_static/lecture_specific/long_run_growth/tooze_ch1_graph.png b/lectures/_static/lecture_specific/long_run_growth/tooze_ch1_graph.png index a3833f103..3ae6891e3 100644 Binary files a/lectures/_static/lecture_specific/long_run_growth/tooze_ch1_graph.png and b/lectures/_static/lecture_specific/long_run_growth/tooze_ch1_graph.png differ diff --git a/lectures/_static/lecture_specific/short_path/Graph-networkx2.ipynb b/lectures/_static/lecture_specific/short_path/Graph-networkx2.ipynb deleted file mode 100644 index f9fd7aa1e..000000000 --- a/lectures/_static/lecture_specific/short_path/Graph-networkx2.ipynb +++ /dev/null @@ -1,279 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import networkx as nx\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "G = nx.DiGraph()\n", - "G.add_node('A',pos=(0,100))\n", - "G.add_node('B',pos=(2,50))\n", - "G.add_node('C',pos=(-2,50))\n", - "G.add_node('D',pos=(0,40))\n", - "G.add_node('E',pos=(1,10))\n", - "G.add_node('F',pos=(-1,10))\n", - "G.add_node('G',pos=(0,-50))\n", - "G.add_edges_from([('A', 'B')], weight=1)\n", - "G.add_edges_from([('F','G')], weight=1)\n", - "G.add_edges_from([('C','F')], weight=2)\n", - "G.add_edges_from([('A','D')], weight=3)\n", - "G.add_edges_from([('D','F'),('E','G')], weight=4)\n", - "G.add_edges_from([('A','C')], weight=5)\n", - "G.add_edges_from([('B','E')], weight=6)\n", - "G.add_edges_from([('D','G')], weight=8)\n", - "G.add_edges_from([('B','D')], weight=9)\n", - "edge_labels=dict([((u,v,),d['weight'])\n", - " for u,v,d in G.edges(data=True)])\n", - "pos=nx.get_node_attributes(G,'pos')\n", - "\n", - "\n", - "\n", - "nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, rotate=False)\n", - "nx.draw(G,pos, node_color='lightgrey',with_labels=True, node_size=1000)\n", - "plt.savefig('graph.png')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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lLN6UNtAD8uWLePZZ59l3bp1tG/fXu/miFpCQreh8vaGCRMgOrr0UFN/f76fNImirl0p7tVLK4YjhVKc4ijKs3r1arp27ap3c0QtIvN0G7qiIliwAFJSSg+ZR4/Gv1cvHRv1+1q2bElSUlKtrjBWWFgoK83EVaSn29D5+WklHiMiSg/5l629K5wmgSsqIqErtGLmkyZBeHilb5k6dSrh4eHyUfkKNpuNnj17EhcXp3dTRB0hoSs0/v7abhJNm1b48pQpU1i7dq2HG1X7mUymOllwR+hHQldc1rgxTJ5cYVHzgQMHylbdV0hJSeG7775j2rRpejdF1CESuqK8oKBy47uics888wxvvPGGy3bpFQ2D3C3ias4U07ZaXd+OWmzVqlWEh4fTu3dvvZsi6hgJXeEa589DdrberfCYbdu2sWLFCqKjo5kwYQIbN25k4sSJejdL1AESusI1bDaYPx/y8vRuiUf8+9//JiUlhVOnTvHFF19wyy231Om92oTnSOiKKrnvvvvo168fR44cITIykk8++eTqN2Vnw7x5cPGi5xsoRB0hK9KEa5w+DZ99pv1/eDhMmaJNQ3OTurAiTYiKSE9XuERBTs7lL9LTtaXFhYX6NcjFioqKKC67macQTpLQFTVmLSzktU8/JaXseG5qKixcqNV2qOMsFgt//OMfkQ+FwhUkdEX1qar2q6QEiovx2b2bkF9/Zej8+ZwvO56bkgKLF9fp6WRFRUXcfffd5Obm4uPMVDohriChK6pPUbQpYhs3wtKl8P33/OXmm7m/a1eGLVjABbP58ntPn4YvvtACuo6xWq1MmDABf39/5s2bJ4sghEvIXSSc06KFVqfh+PHSQy8PGsSodu0YsXAhOWXHc48fh//+V5tWVkfYbDYefPBBiouLWbJkCd7e3no3SdQTErrCeb17w223lX6pKAr/HjqUm6OiuG3RIvLLjuceOQLLlkHZXYdrKbvdzrRp00hPT+err77C19dX7yaJekRCV9RMbCwMG1b6paIovDdyJF3Dwhj9xReYy47n/vILfPutNh5cS6mqytNPP82xY8dYsWIFRqNR7yaJekZCV9TcgAEwaFDplwZF4YO4OCKDghizdClFZcdz9++HVatqZfCqqsqf//xnkpKS+O677wgICNC7SaIektAVrjF4MNx8c+mXXgYDn915J4G+voz/6iusZcdzd++GdetqXfC+/PLLbNiwgbVr1xIUFKR3c0Q9JaErXENRtGGGmJjSQ94GA4vHjsVmtzNx+XJsZcdzd+yADRsuTz+rovnz5/P3v/+d/Px83n77bd58801sLnhA969//Yuvv/6a9evXS91g4VayDFi4lqrCypWwZ0/pocKSEu5YsoSWgYF8duedGBRFWzRx/Lg2A6JVK21X4hEjKt25wmHIkCFs3ry59OvQ0FDS09PxqsGuxe+99x6zZs1i69atsqxYuJ30dIVrKQrExUG3bqWHGnl7882993IyO5snv/sONTcXdu3SlgsfOgTHjmmzGz76SDt2Da+//jr+l2o6+Pv7889//rNGgfvBBx/w3nvvsWHDBglc4RHS0xXuYbdrc3MPHSo9lFdUxPDPPqO/ry/vtG6NoiiX39+uHVx3HbRtq+1OfA0DBw7kxx9/JDg4mLS0NPz8/Jxq4rx583jxxRfZsmULN9xwg1PnEKK6pKcr3MNggHHjtDC9JMhsZm27dmzOzualU6dKj6t2O/z2m1av4dix363J++abbwLwl7/8pVqBW7Z/sXTpUl544QW+//57CVzhUV5///vf/653I0Q9ZTBA585aDYa0NNi3DyMwtlkznj95kpySEgrz8uj/yy88FBGBf3Y2GI3aGO9111V62sjISAoKCnjhhReqXA9BVVU6depEUVERGRkZPPnkk6xfv162lBceJ8MLwv2Ki+G552Dv3tJDqYWF9EpK4oLNhkFReL9dOx6KiNDGhEeNgj//udwpbDYbZrMZi8VCQUEBVqsVVVVRFAUfHx8CAgIwGo34+/tXOMZ74MAB+vbti91ux8vLiy1bttCnTx+3/9aFuJIMLwj38/WFTp0gMLD00P/S0six2bACRarKwvPntRdUVZtKdqlamcVi4cyZMxw+fJjk5GTS09MpKCiguLgYq9VKcXExBQUFpKenk5yczOHDhzlz5gwWi6VcE7766iusVitFRUXYbDa+/vprT/3uhShHQld4RnAwdO8OjRsDsL6oCLui0OjSw7QtubmYHfNtLRas+/dz4sQJTpw4QV5eHqqqYv+dug12ux1VVcnLyyv9XuulZciffvopJSUleHt7oygKP/zww++eTwh3kNAVntGxo7a1e/fu4O/P3A4dONO3L6+3aUObRo2wAZ+npaECWX37cjQwELPZ7HThcFVVMZvNHD16lKNHj3L27FlCQ0N5/vnnOXDgALt27ZJSjUIXMqYrPENV4ZtvtNoLRUWwbx+UGQLYl59PG6ORi/feS3b//qhOTgOriKIoFBYW0rNnTwlaoTsJXeE5qqotgti+Xfvvvn2l+6ipQOrYsS4PXAdFUQgNDSUiIsLl5xaiOiR0hT5ycyExEb78Eo4dI6tvX1LvucctgeugKAoRERFSW0HoSkJX6M6akcHRtDTUsivU3MRgMNCuXTvZ70zoRga4hO6S8/M9ErigzXBITk72yLWEqIiErtCVY8GDJ1ksFo9fUwgHCV2hq8zMTKenhTlLVVUyMzM9ek0hHGSLU6Ebm81Gfn5+tb9vzZo1LFiwgGPHjmE0GrnuuusYPXo09957b/nKZdeQl5eHzWarUVlIIZwhPV2hG7PZXOWQdJg3bx6vv/46U6ZMYdOmTWzevJm//e1v7N27t3T1WVUoioLZbK5uk4WoMZm9IHSTnp5O+u8ULS8rPz+foUOH8tprrzF8+PAaXz88PJzw8PAan0eI6pCertBNQUFBtd6/f/9+iouLGTJkiC7XF8IVJHSFbqozHACQnZ1NcHAw3t6XH0VMnDiR/v3706dPH5KSktx6fSFcQR6kCd1Ud2QrODiYnJyc0mphAAsXLgRg6NCh1T6fjKwJPUhPV+imug/RevToga+vL5s2bdLl+kK4gvR0hW58fHwoLi6u8vuDgoJ4/PHHefXVV1FVlQEDBtCoUSOOHj3q1GIHWQos9CCzF4Ruqjt7wWHVqlUsWrSodJ5uZGQkY8aM4a677qpWkMrsBaEHCV2hm/z8fJKTk3XZwcFgMBAVFUVgmS2EhPAEGdMVuvH399ftYZaqqvj7++tybdGwSegK3Xh5eenW0wwKCpIlwEIXErpCV2FhYR6fRaAoCs2aNfPoNYVwkNAVujIajRiNxnp/TSEcJHSF7qKiojzW23U8QBNCLxK6Qnc+Pj5ERES4PXgVRaFFixYyP1foSkJX1AohISGEhIS4LXgduwHLppRCbxK6olZw7NTrjuB1BG6LFi1cel4hnCGLI0Stoqoq2dnZpKWluWTRhMFgoEWLFtLDFbWGhK6olaxWK8nJyVgsFqcWUCiKgtFoJCoqSsZwRa0ioStqNYvFQmZmJnl5eSiKcs3er8FgQFVVgoKCaNasmUwLE7WShK6oE2w2W+l27QUFBVitVlRVRVEUfHx8CAgIwGg04u/vLyvNRK0moSuEEB4ksxeEEMKDJHSFEMKDJHSFEMKDJHSFEMKDJHSFEMKDJHSFEMKDJHSFEMKDJHSFEMKD/j8vkws1IVjJjQAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import networkx as nx\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "G = nx.DiGraph()\n", - "G.add_node('A',pos=(0,100))\n", - "G.add_node('B',pos=(2,50))\n", - "G.add_node('C',pos=(-2,50))\n", - "G.add_node('D',pos=(0,40))\n", - "G.add_node('E',pos=(1,10))\n", - "G.add_node('F',pos=(-1,10))\n", - "G.add_node('G',pos=(0,-50))\n", - "G.add_edges_from([('A', 'B')], weight=1)\n", - "G.add_edges_from([('F','G')], weight=1)\n", - "G.add_edges_from([('C','F')], weight=2)\n", - "G.add_edges_from([('A','D')], weight=3)\n", - "G.add_edges_from([('D','F'),('E','G')], weight=4)\n", - "G.add_edges_from([('A','C')], weight=5)\n", - "G.add_edges_from([('B','E')], weight=6)\n", - "G.add_edges_from([('D','G')], weight=8)\n", - "G.add_edges_from([('B','D')], weight=9)\n", - "edge_labels=dict([((u,v,),d['weight'])\n", - " for u,v,d in G.edges(data=True)])\n", - "\n", - "\n", - "pos=nx.get_node_attributes(G,'pos')\n", - "nx.draw_networkx_edges(G,pos,\n", - " edgelist=[('A','C'), ('C','F'), ('F','G')],\n", - " width=8,alpha=0.5,edge_color='r')\n", - "\n", - "nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, rotate=False)\n", - "nx.draw(G,pos, node_color='lightgrey',with_labels=True, node_size=1000)\n", - "plt.savefig('graph2.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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vawbLJxKpgELh1JVWL8ejhwpPJaXl83KlY/i71+LgQO/QFF05OTYRjXUqAF16th2Je7V6893rsj38MMPs2vXroLHQUFBpKSk4FGGbYs/+eQTZs+ezZ49e2RasXA6aekKh1IU6N8fWrYsPObpWYUnn/yWjIzzbNz4PNevqxw6ZJsufOoUnD1rG90wb57t2J188MEH+P5vUQdfX1/efvvtMgXunDlz+OSTT9i+fbsErnAJaekKp7BabWNzT50qPJaTk8kXX/TE2zuaunVnoChKwXMNG8K990KDBrbdie+kS5cu7N27l+rVq5OcnIyPj49ddVy8eDFTpkxh9+7d1K9f365zCFFa0tIVTqHTwdChtjDNZzQG0LDhZjIydnHhwusFx61WlV9/ta3XcPbs3dfknT59OgB/+9vfShW4N7cvVq1axauvvsrWrVslcIVLebz55ptval0JUTHpdNCsmW0NhuRkOHYMQE/NmkM4f/4V8vKukZmZzS+/RBMWNoaMDF/0elsf7733/vl5a9euTVZWFq+++mqJ10NQVZWmTZuSk5NDamoqzz//PN9//71sKS9cTroXhNPl5sLf/w5HjxYey85OIj6+LRbLVRRFR8OGnxMWNgZFgX794OWXi57DYrFgNBoxmUxkZWVhNptRVRVFUfDy8sLPzw+9Xo+vr2+xfbwnTpzggQcewGq14uHhwe7du2nXrp2Tv3MhbifdC8LpvL2haVPw9y88lpz8AxbLNcCMquZw5YptqxtVtQ0ly999wmQycenSJU6fPk1iYiIpKSlkZWWRm5uL2WwmNzeXrKwsUlJSSExM5PTp01y6dAmTyVSkDl9//TVms5mcnBwsFgvffPONi757IYqS0BUuUb06tGoFVavaHufkfI+iWFGUKgBcv74bi8U2ZdhkguPHzZw7d45z586RmZmJqqpY77Jwg9VqRVVVMjMzC77W/L91JRctWkReXh6enp4oisK2bdvuej4hnEFCV7hEkya2rd1btbJt49O48XweeOAS9ep9QJUq9QALyclfAioPPJCOv38CRqPR7oXDVVXFaDSSkJBAQkICv//+O0FBQbzyyiucOHGCQ4cOyVKNQhPSpytcQlXh229tay/k5Nhuqt3cA2AwHEOvr8eTT94gOjoDHx/HXZaKopCdnU2bNm0kaIXmJHSFy6iqbRLEjz/a/nvs2M37qKkMGZLk8MDNpygKQUFBhIWFOfzcQpSGhK7QxPXr8NNP8O9/28bmPvBAOo8/nuSUwM2nKAphYWGytoLQlISu0Fxqqpnk5AQUxfmXok6no2HDhrLfmdCMdHAJzRkMiS4JXLCNcEhMTHRJWUIUR0JXaCp/woMrmUwml5cpRD4JXaGptLQ0u4eF2UtVVdLS0lxaphD5ZItToRmLxYLBYLj7C2/x3XffsXTpUs6ePYter+fee+9lwIABPPnkk0VWLruTzMxMLBZLmZaFFMIe0tIVmjEajSUOyXyLFy/mgw8+YPTo0ezcuZNdu3bxj3/8g6NHjxbMPisJRVEwGo13f6EQDiajF4RmUlJSSLnbquU3MRgMdO/enffee4+ePXuWufyQkBBCQkLKfB4hSkNaukIzWVlZpXr98ePHyc3N5eGHH9akfCEcQUJXaKY03QEAGRkZVK9eHU/PwlsRI0aMIDo6mnbt2hEfH+/U8oVwBLmRJjRT2p6t6tWrc+3atYLVwgCWLbMtCdm9e/dSn0961oQWpKUrNFPam2iRkZF4e3uzc+dOTcoXwhGkpSs04+XlRW5ubolfHxAQwLPPPsu7776Lqqp06tSJKlWqkJCQYNdkB5kKLLQgoxeEZko7eiHfhg0bWL58ecE43dq1azNo0CAee+yxUgWpjF4QWpDQFZoxGAwkJiZqsoODTqcjPDwc/5v3EBLCBaRPV2jG19dXs5tZqqri6+urSdmicpPQFZrx8PDQrKUZEBAgU4CFJiR0haaCg4NdPopAURRq1qzp0jKFyCehKzSl1+vR6/UVvkwh8knoCs2Fh4e7rLWbfwNNCK1I6ArNeXl5ERYW5vTgVRSF0NBQGZ8rNCWhK9xCYGAggYGBTgve/N2AZVNKoTUJXeEW8nfqdUbw5gduaGioQ88rhD1kcoRwK6qqkpGRQXJyskMmTeh0OkJDQ6WFK9yGhK5wS2azmcTEREwmk10TKBRFQa/XEx4eLn24wq1I6Aq3ZjKZSEtLIzMzE0VR7tj61el0qKpKQEAANWvWlGFhwi1J6IpywWKxFGzXnpWVhdlsRlVVFEXBy8sLPz8/9Ho9vr6+MtNMuDUJXSGEcCEZvSCEEC4koSuEEC4koSuEEC4koSuEEC4koSuEEC4koSuEEC4koSuEEC4koSuEEC70/wEfdsiKgHK/hgAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "nx.draw_networkx_edges(G,pos,\n", - " edgelist=[('A','D'), ('D','F'), ('F','G')],\n", - " width=8,alpha=0.5,edge_color='b')\n", - "\n", - "\n", - "\n", - "nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, rotate=False)\n", - "nx.draw(G,pos, node_color='lightgrey',with_labels=True, node_size=1000)\n", - "plt.savefig('graph3.png')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "colormap:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import networkx as nx\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "G = nx.DiGraph()\n", - "G.add_node('A',pos=(0,100))\n", - "G.add_node('B',pos=(2,50))\n", - "G.add_node('C',pos=(-2,50))\n", - "G.add_node('D',pos=(0,40))\n", - "G.add_node('E',pos=(1,10))\n", - "G.add_node('F',pos=(-1,10))\n", - "G.add_node('G',pos=(0,-50))\n", - "G.add_edges_from([('A', 'B')], weight=1)\n", - "G.add_edges_from([('F','G')], weight=1)\n", - "G.add_edges_from([('C','F')], weight=2)\n", - "G.add_edges_from([('A','D')], weight=3)\n", - "G.add_edges_from([('D','F'),('E','G')], weight=4)\n", - "G.add_edges_from([('A','C')], weight=5)\n", - "G.add_edges_from([('B','E')], weight=6)\n", - "G.add_edges_from([('D','G')], weight=8)\n", - "G.add_edges_from([('B','D')], weight=9)\n", - "edge_labels=dict([((u,v,),d['weight'])\n", - " for u,v,d in G.edges(data=True)])\n", - "\n", - "edges,weights = zip(*nx.get_edge_attributes(G,'weight').items())\n", - "\n", - "\n", - "pos=nx.get_node_attributes(G,'pos')\n", - "\n", - "nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, rotate=False)\n", - "nx.draw(G,pos, node_color='lightgrey',with_labels=True, node_size=1000,edge_color=weights, width=4.0, edge_cmap=plt.cm.Blues)\n", - "\n", - "plt.savefig('graph4.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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49///nfxj84jRozA19dX6/JEKZnNZmJjYzl8+DDvv/8+W7dupU6dOrz00kv8+uuvWpcnvEACuhypW7cuTZs2pUWLFrRp0+a651RV5eeff6Zfv3506tSJoKAgfvjhBz766CPat2+vUcXCHRRFoVu3bnz22Wd8//332O12WrVqxdChQzl79uxNrx87dixhYWE0adJEg2qFO8lKwnKkbt26HDhwgOrVq9/0nN1u5/333ycwMJAnnnjC43tP6MmqVauoUqUKgwYN0roUr7l27RorVqwgKCiI0aNHX/fczp07qVKlCqNHj5Z51uWcBHQ5cqeALvpv9PZNV/UgNzcXRVEq5Q5yqqre8v/89OnT9O/fXwK6nJMhjnJEURRiYmJo3bo1ixYtuum5yhjOAP7+/pUynKFyfkOuTGTiazmye/duatWqxYULF+jduzfR0dF06dJF67KEEB4iPehypFatWkDhKrTBgwezf/9+jSsSQniSBLQO7d+//6b5rjk5OWRnZxf/edu2bXKVnsLx57Zt29K8eXPuv/9+XnnlFa1L0r1Lly5x5MgRrcsQpSABrRM2m401a9bQoUMHHn/88Zs2mv/999/p3LkzzZs3p23btvTr14+HHnpIo2r1w8/Pjx07dnD48GEOHTrEl19+yb59+7QuS1NPPPEEHTp0ICUlhdq1a7N06dLrnvfx8aFv3750796dzz//XDZp0jGZxaGxixcvsmjRIj744AMaNGhAXFwcAwYM0OROIOWdxWKhc+fOfPDBB7Rr107rcnTNZrPx6aefEh8fT3p6OpMmTSI2NpaqVatqXZr4A+lBa+TIkSPExsZy3333kZqayqZNm0hKSmLQoEESzk6y2+20aNGCsLAwevfuLeFcCiaTieHDh7N3717Wrl1LcnIyUVFRPPvss6SkpGhdnvg/EtBeZLfb+eyzz+jWrRt9+/alfv36nDhxgqVLl9K8eXOtyyu3jEYjhw4d4uzZs+zfv1/m/jqpbdu2rF69mqNHj1KtWjW6dOnCww8/zJYtW+54Y17heTLE4QVXrlwpvjddeHg4cXFxDB06FJPJpHVpFc5rr71GYGAgL774otallFu5ubmsWbOG+Ph4rFYrkydPZsyYMVSpUkXr0iod6UF70PHjx3n22WeJiooiOTmZtWvXsnfvXoYPHy7h7CYXL17kypUrAFitVr7++muio6M1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rw7dul3/2OnThb8/+KAsWvGAin9m61xRryUkJMQjF4O+/PJLli9f7vbjCu9RVZXp06fzzjvveOQ8KQrn8PBwtx5XlJ0MceiEqqpkZmaSnp7ulj2ADQYD4eHh5Obm0qVLFyZPnuzSajKhvVdffZX169eTlJREaGioR86TivwTVnkmQxw6UdSLCQoKIi0tDavV6tKQh6IomM1mIiMji38U3r59O127dsVsNjN+/Hh3l66pv//97yxZsgRFUWjatCnLli3D399f67Lc5q233mLt2rV88803VKtWDcBj54nQH+lB65TVaiUjI4OsrCwURbljb8lgMKCqKsHBwVSvXv2WU6ROnjxJt27deOONNxg9erQnS/eac+fO0blzZ44dO4bZbOaxxx6jb9++PPXUU1qX5hYJCQnEx8ezc+dO7r777lu+xt3nidAX6UHrVFHvxm63Y7FYsFqt5OTkYLPZUFUVRVEwmUwEBgZiNpsJCAi44wrBe++9l6+++ooePXpgNpt59NFHvfjVeE5BQQFWqxWTyYTFYqFWrVpal+QWixcv5p133uHbb7+9bTiD+88ToS8S0DpXtNzXHUt+GzVqxJdffklMTAx+fn4MHDjQDRVq5+677+bFF1/knnvuwWw2ExMTQ0xMjNZlldmqVat47bXXSEpKou5tpmfeyJ3nidAPmcVRyTRv3pwvvviCcePGsW3bNq3LKZPMzEw2bNjAqVOn+O2338jJyWHVqlVal1UmH3/8MdOmTWPbtm00aNBA63KExiSgK6EHHniA9evXM3LkSL799luty3HZ119/Tb169ahRowYmk4khQ4awZ88ercty2caNG5k0aRJbtmyhcePGWpcjdEACupLq3Lkza9asYdiwYezdu1frclxyzz33sG/fPiwWC6qqsn37dho1aqR1WS756quviI2NZePGjbRo0ULrcoROSEBXYj179mTFihU88sgjJCcna12O09q1a8ewYcNo1aoVTZs2xeFwlMtphDt37mTEiBGsX7+etm3bal2O0BGZZidYv349//M//8PXX39NkyZNtC6nUtm3bx8DBgzgo48+olevXlqXI3RGZnEIhgwZQm5uLjExMSQlJdFQNrzxiuTkZAYOHMjy5cslnMUtSUALAEaMGEFubi69e/fm22+/pd7tduYTbvHjjz/St29fPvjgA/r166d1OUKnJKBFsbFj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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import networkx as nx\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import pylab\n", - "\n", - "G = nx.DiGraph()\n", - "G.add_node('A',pos=(0,100))\n", - "G.add_node('B',pos=(2,50))\n", - "G.add_node('C',pos=(-2,50))\n", - "G.add_node('D',pos=(0,40))\n", - "G.add_node('E',pos=(1,10))\n", - "G.add_node('F',pos=(-1,10))\n", - "G.add_node('G',pos=(0,-50))\n", - "G.add_edges_from([('A', 'B')], weight=1)\n", - "G.add_edges_from([('F','G')], weight=1)\n", - "G.add_edges_from([('C','F')], weight=2)\n", - "G.add_edges_from([('A','D')], weight=3)\n", - "G.add_edges_from([('D','F'),('E','G')], weight=4)\n", - "G.add_edges_from([('A','C')], weight=5)\n", - "G.add_edges_from([('B','E')], weight=6)\n", - "G.add_edges_from([('D','G')], weight=8)\n", - "G.add_edges_from([('B','D')], weight=9)\n", - "edge_labels=dict([((u,v,),d['weight'])\n", - " for u,v,d in G.edges(data=True)])\n", - "pos=nx.get_node_attributes(G,'pos')\n", - "\n", - "import matplotlib.pyplot as plt\n", - "\n", - "plt.text(0,120,s='8', color='red', size=15, horizontalalignment='center')\n", - "plt.text(2.4,50,s='10', color='red', size=15, horizontalalignment='center')\n", - "plt.text(-2.4,50,s='3', color='red', size=15, horizontalalignment='center')\n", - "plt.text(-0.35,35,s='5', color='red', size=15, horizontalalignment='center')\n", - "plt.text(1.35,0,s='4', color='red', size=15, horizontalalignment='center')\n", - "plt.text(-1.35,2,s='1', color='red', size=15, horizontalalignment='center')\n", - "plt.text(0.45,-55,s='0', color='red', size=15, horizontalalignment='center')\n", - "\n", - "\n", - "nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, rotate=False)\n", - "nx.draw(G,pos, node_color='lightgrey',with_labels=True, node_size=1000)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/lectures/_static/lecture_specific/short_path/figures.ipynb b/lectures/_static/lecture_specific/short_path/figures.ipynb new file mode 100644 index 000000000..aeb553fcf --- /dev/null +++ b/lectures/_static/lecture_specific/short_path/figures.ipynb @@ -0,0 +1,229 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAApQAAAHzCAYAAACe1o1DAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABH80lEQVR4nO3de3hU1b3/8c/MBJJJIAMkYQgxIISbRRQQpAjqsWpbW+WiVWqxVY+iPUJVOPRqtVilHi9QrVpFsBULCNVK0LZWa+sFvHAR8YYiCBgacsdfBsIkYWb27w+alECAJLNn9mXer+fhecpk2Pvr02TPJ2ut71oewzAMAQAAAB3ktboAAAAAOBuBEgAAAHEhUAIAACAuBEoAAADEhUAJAACAuBAoAQAAEBcCJQAAAOJCoAQAAEBcCJQAAACIC4ESAAAAcSFQAgAAIC4ESgAAAMSFQAkAAIC4ECgBAAAQFwIlAAAA4kKgBAAAQFwIlAAAAIgLgRIAAABxIVACAAAgLgRKAAAAxIVACQAAgLgQKAEAABAXAiUAAADiQqAEAABAXAiUAAAAiAuBEgAAAHEhUAIAACAuaVYXAAB2ZBiGotGoYrGYDMOQx+OR1+uVz+eTx+OxujwAsBUCJQBIikQiqqurUzgc1v79+1VfX69YLHbE+7xerzIyMpSZmSm/36+srCylpfEoBZDaPIZhGFYXAQBWMAxD4XBYNTU1qq2t7fB1AoGAcnJy5Pf7Gb0EkJIIlABSUigUUkVFhRoaGky7Znp6uoLBoLKzs027JgA4AYESQEqJRCIqKyuLa0TyeAKBgPLz85kKB5AyCJQAUkYoFFJpaami0WjC7+Xz+VRQUMBoJYCUQKAE4HqGYaiqqkqVlZVJv3cwGFRubi5rKwG4GoESgKsZhqGKigpVV1dbVkNubq6CwSChEoBrsbE5AFerqqqyNExKUnV1teU1AEAiESgBuFYoFLJkmrs1FRUVCoVCVpcBAAlBoATgSpFIRKWlpVaX0UJpaakikYjVZQCA6QiUAFyprKwsKd3c7RGNRlVWVmZ1GQBgOgIlANcJhUIJ3WcyHrW1tUx9A3AdAiUAV2nq6raziooKscEGADchUAJwlXA4bOpxionQ0NCgcDhsdRkAYBoCJQBXqampsbqENnFKnQDQFgRKAK4RiURMXTu5dOlSDRs2TJMnTzbtmk1qa2vp+AbgGgRKAK5RV1dn6vVWrlwpSdq2bZvef/99U68tmV8vAFiFQAnANcxcl/jRRx9py5YtOuussyRJzz77rGnXbsI6SgBuQaAE4Br79+837VpNAfLmm2/W8OHD9be//c30AEigBOAWBEoArmAYhurr6025Vn19vV544QWdfPLJGjhwoCZPnqy6ujq99NJLply/STgcZvsgAK5AoATgCtFoVLFYzJRr/f3vf9fevXubm3G+/vWvKzMz0/Rp71gsZrvTfACgIwiUAFzBrDApHZzuzsjI0AUXXCBJyszM1Fe/+lVt3LhRn3/+uWn3kcytGwCsQqAE4ApmTR2XlJTonXfe0ZlnninDMBQKhRQKhXT++edL+k/nt1mY8gbgBh6DpxkAF2hsbNSnn34a93UeeOABLVq06Khfz8vL09///nf5fL647yVJgwYNUufOnU25FgBYJc3qAgDADF5v/BMu0WhUzz33nAoLC3X77bcf8fXXXntNixcv1po1a3T22WfHfT/JnLoBwGoESgCu4PP55PV641qTuGbNGlVWVmrmzJkaPXr0EV8fMGCAnnrqKT377LOmBEqv12vaSCcAWIlfjQG4gsfjUUZGRlzXePbZZ9WpUydNmjSp1a93795d5557rl5//XVVV1fHdS9J8vv98ng8cV8HAKzGGkoArlFeXm5K0EuW3Nxc9erVy+oyACBujFACcA2/3291Ce3itHoB4GgIlABcIysry+oS2sVp9QLA0RAoAbhGWlqaunTp4ojNwgOBgNLS6IsE4A4ESgCuUF9fr2uvvVaXXHKJI7biWbBggWlnjwOA1ez/1AWAY2gKkl27dtXjjz+u8vJyWwc1wzD02Wefae7cueratauuvfZaW9cLAG1BoATgSIcHyZ49e2r58uUqLS3VoEGDrC7vqDwej8455xwtX75ceXl5evzxxwmWAByPQAnAUY4VJKdMmSJJys7OViAQsLjS1gUCAWVnZ2vKlCnavXs3wRKAKxAoAThCW4LkofLz8213Co3P51N+fn6L1wiWANyAQAnA1tobJJukpaWpoKAgiZUeX0FBwVE7uwmWAJyMQAnAljoaJA+VnZ2tnj17JrjStgkGg8rOzj7u+wiWAJyIQAnAVswIkofKy8tTbm5uAiptu9zc3HbXQLAE4CSc5Q3AFurr6zVjxgwtXrxYkUhEvXv31vz58zsUIg9n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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import networkx as nx\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import pylab\n", + "\n", + "def create_base_graph():\n", + " G = nx.DiGraph()\n", + " nodes_with_positions = {\n", + " 'A': (0, 100),\n", + " 'B': (2, 50),\n", + " 'C': (-2, 50),\n", + " 'D': (0, 40),\n", + " 'E': (1, 10),\n", + " 'F': (-1, 10),\n", + " 'G': (0, -50)\n", + " }\n", + " for node, pos in nodes_with_positions.items():\n", + " G.add_node(node, pos=pos)\n", + " edges_with_weights = [\n", + " ('A', 'B', 1),\n", + " ('F', 'G', 1),\n", + " ('C', 'F', 2),\n", + " ('A', 'D', 3),\n", + " ('D', 'F', 4),\n", + " ('E', 'G', 4),\n", + " ('A', 'C', 5),\n", + " ('B', 'E', 6),\n", + " ('D', 'G', 8),\n", + " ('B', 'D', 9)\n", + " ]\n", + " for u, v, w in edges_with_weights:\n", + " G.add_edge(u, v, weight=w)\n", + " return G\n", + "\n", + "def draw_base_graph(G, file_name):\n", + " pos = nx.get_node_attributes(G, 'pos')\n", + "\n", + " nx.draw(G, pos, node_color='lightgrey', with_labels=True, node_size=1000)\n", + " nx.draw_networkx_edges(G, pos, edgelist=G.edges(), arrows=True)\n", + " \n", + " edge_labels = {(u, v): d['weight'] for u, v, d in G.edges(data=True)}\n", + " nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, rotate=False)\n", + " \n", + " plt.savefig(file_name)\n", + "\n", + "G = create_base_graph()\n", + "draw_base_graph(G, file_name='graph.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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3O79Vpjk50sLF0qDByf5J0MyESjtraWlRaWlpQoGg1qxYoVmzZrVq/cl7foAZAgCJfAlwzAUjUYVi8VkGIZcLpfcbrc8Hk/PowyGIT3/vLR2baen/vnPf+qf//qXDh4xQpdccknn9wYC0sUXS9nZSfxJkEwESnubNm2aVq1apZtuukn/7//9v34fp9/XByBD0JQDfMnlcikrK0vZ2dnKyclRdna2srKyDvzHwuWSZsyQDj2001MnnXSSDhszRp/v2EHnN5BmCxcu1KpVqzRr1qyEwqSUwPUByBAESiAZPB7pnHOkIUM6PXXuuefS+Q2k2f3336+HHnqovaMbQGoRKIFkycuTvv1tKSenw8Mul0uXXXaZcrKz9cILL6iioqLze19/XXr//TQVCjjbypUrtWjRIvl8Pr3zzjud1y8DSDp+y4BkKiqS5s2LT4PvIzs7W5dccolcLpcee+wx7d27t/N72fPbkq677jpdd911ZpeBXtq5c6dOPfVUeTwevf32251uDwQgNWjKAVKBzm/HaPlyu8xsGqcsr78d3QASxwglkArHHCNNntzp4bFjx+qkE09UfUODHnnkkc7vY89vy8nOziZM2sT06dMVDAZ10003ESaBNCNQAqlA5zeQVsns6AbQdwRKIFXo/AbSgo5uwHwESiCV6PwGUoqObsAa+M0DUo3ObyAl6OgGrINACaRDebl02mmdHi4qKtI555yjSDSqBx54oPNewdGotHSp9MUX6akT7SKRiH72s59p5MiR8nq9GjVqlP77v/+7y/2ckX4tLS2aPHmympqa9PTTT+uwww4zuyQgoxEogXSh89tW7rjjDv32t7/Vfffdpw0bNuiXv/yl7rzzTt17771mlwbR0Q1YDYESSBc6v23lrbfe0qxZszRjxgwdeuihmjdvnk477bSum6iQVnR0A9ZDoATSic5v2/j617+uV199VR9//LEk6f3339fKlSv1zW9+0+TKMhsd3YA1sVMOYIbqaumhh6Tm5g4Pt7S0aPHixWppadGCBQtUWlra+b1z5khHHpmmQjOXYRj66U9/qjvuuEMej0fRaFS33nor2zCaaOXKlTrhhBNUUFCgzz//nCYcwEIYoQTMQOe35S1btkxLlizRE088obVr1+rRRx/Vr371Kz366KNml5aR6OgGrI0RSsBM7PltWSUlJfrJT36iRYsWtT92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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def draw_graph_with_highlights(G, highlighted_edges, edge_color, file_name):\n", + " pos = nx.get_node_attributes(G, 'pos')\n", + "\n", + " nx.draw(G, pos, node_color='lightgrey', with_labels=True, node_size=1000)\n", + " nx.draw_networkx_edges(G, pos, edgelist=G.edges(), arrows=True)\n", + "\n", + " nx.draw_networkx_edges(G, pos, edgelist=highlighted_edges,\n", + " width=8, alpha=0.5, edge_color=edge_color, arrows=True)\n", + "\n", + " edge_labels = {(u, v): d['weight'] for u, v, d in G.edges(data=True)}\n", + " nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, rotate=False)\n", + "\n", + " plt.savefig(file_name)\n", + "\n", + "highlighted_edges_red = [('A', 'C'), ('C', 'F'), ('F', 'G')]\n", + "draw_graph_with_highlights(G, highlighted_edges_red, 'r', 'graph2.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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vfPOO+rTp4+2bt2qnj17Wl0aLMYIJZopLy9Xnz599OGHH2ry5MlWlwOH6sr09rnnnqszzjijzdfHO73dVY3hds+ePcn7UMCmfvWrX+mjjz7S0qVLrS4FNsMIJZppXEfGCTvoCqdMbwPomjfeeEPnn3++rrzySn344Yfq37+/brnlFt18881WlwaLMUKJJoZh6NJLL9X+/fv51yc6xWnT253BCCVwWOPWP3feeaeuvPJKrVixQrfffrueeeYZ/fjHP7a4OliJQIkmM2fO1Ntvv61ly5bpuOOOs7ocOISbprdbQ6AEDktPT9fYsWO1fPnypmv//M//rJUrV+rjjz+2sDJYjSlvSJJ+/vOf64033tCSJUsIk+iQAwekd99lehtIJYWFhfrOd77T7NoJJ5ygv/zlLxZVBLsgUKY4wzD085//XIsWLdIHH3ygQYMGWV0SbK5xTqO+vmF0si1OnN4G0L4zzzxTmzZtanbtq6++0sCBAy2qCHZBoExxM2fO1Msvv6zXX39d2dnZTdN6gUBAfr/f4upgR41hr2dP6fzzpYULm3//6Ont88//vmOmtwG074477tCECRP0u9/9TldddZVWrFihZ599Vs8++6zVpcFirKFMcW3tp/df//Vfuv7665NbDBzn0CHpoYekSMS909usoQSae+utt/TrX/9amzdv1qBBg3TnnXfS5Q0CJTonGo3K5/NZXQZs5IknpP/9X/dObxMokYp41qOzOGQTnVJfX6/HHnvM6jJgIwsXLtCiRQsVi8V0/vnf1+23395mmExLk846S5o5Uxoxwv5hEkhFs2fPVn17+38BrWCEEp2yb98+5ebmaurUqXrttdfk9fJvklR38slPqa6ulyumt1vDCCVSRSwW0+WXX67XX39dlZWVHHCBTiENoFMCgYDGjBmjRYsWaejQodq3b5/VJSGBHnzwQXk8Ht1+++1tvmbatCs1Y8aMNsNkz57SjBnSNdc4L0wCqaKyslLFxcV6/fXXNXbs2KYz7YGOIlCiU3w+n1atWqVbbrlF27Zt03HHHcdmti61cuVKPfvsszrppJPafV1eXl6r15neBpzho48+UlFRkXbs2KFbb71VK1euZP0kOo1AiS75wx/+oPnz56u+vl5nnnkm6ypd5uDBg7r22mv13HPPqVevXp1+/9Ch0i23SGefzVZAgJ3Nnj1bkyZN0qFDhzR//nw98cQTVpcEhyJQosumT5+uL7/8Uj179tQdd9yhyy+/XLFYzOqy0AGx2OENylszc+ZMXXTRRTr33HM7dV+mtwFniMViuuyyyzRr1iz17NlT69ev1/Tp060uCw7GxuaIy/Dhw7V7925NnDixaV3lypUrWcxtY9u3SyUl0uTJrX9//vz5WrNmjVauXNnhe7I5OeAclZWVGjt2rHbs2KGxY8dq6dKlyszMtLosOBwjlIhbZmYm6yodIBSSXntNmjdPOniw9dfs3LlTt912m1566aUO/4AZMIDpbcApWlsvSZiEGdg2CKZasGCBrr32WsViMT366KPtdgcjOaJR6ZNPpA8+aDh/W5LGjZMuvLBlo8zixYs1derUZgvyo9GoPB6PvF6v6urqWizWNwx3N9ywbRDcYvbs2frFL34hn8+nl156iSlumIpACdNt2rRJ48eP1/79+9mv0mLbt0t//atUXt78eluB8sCBA/r666+bXbvhhhs0YsQI/fKXv9SJJ56Y4Irth0AJpztyf8levXrpk08+0dChQ60uCy7DGkqYjnWV1guFpPfek9ata/s1hmG0OMs9Ozu7RWjMyspSbm5uSoZJwOlYL4lkYdgICcG6SmtEo9Ly5dKcOe2HydLS0uQVBcASrJdEMjHljYRjXWVytDW9faT9+/frlVde0bRpAzVnzoXyel28+NEkTHnDiVgviWRjyhsJN336dJ1yyikaP3687rjjDi1ZsoR1lSbqyPR2LBbTG2+8obVr10oyVFBwWtLqA5A8rJeEVQiUSArWVZqvte7t1nz++ed66623dOhQvQKBnpoxY4ZOOaWvyPOAu7BeElYiUCJpGtdVzpw5U08++aSOO+44/f3vf9f48eOtLs1xOjO9XV6+Vz5fms4///s644wzJEl79yapUABJ8dFHH2nKlCkKh8O69dZbOUIRSccaSliCdZVd05Xp7eHDR+iKK65Qt6N2Hb/zTqlHDzFSeQysoYTdsV4SdkCghGXYr7Lj4pnebgxERzvuOOnHPz58uo2bNyePB4ESdsV6SdgJU96wDOsqOybe6e3W+HxScXFDiCRIAs7DeknYDSOUsIXGdZV+v591ld8yc3r7SEOHShdcIJHbO4YRStgN6yVhRwRK2AbrKhskYnpbknr2lL7/fWn4cEYlO4NACTthvSTsikAJW0n1dZVdmd6eMmWK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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "highlighted_edges_blue = [('A', 'D'), ('D', 'F'), ('F', 'G')]\n", + "draw_graph_with_highlights(G, highlighted_edges_blue, 'b', 'graph3.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "colormap:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAApQAAAHzCAYAAACe1o1DAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABIe0lEQVR4nO3deXhkZZ3//c85p5JKJZ2q7mzV6ZimV7YGBBEVEATB0WZRGdwQFVFnfuPggl54MS74MLIN4zOO2+9hBhwERMGNRR0R1BGYVpBdUBabtZuQrizdXdVJKkudc54/QkLS2SqpU3WWer+uK9dMqirn3NjJqU/d9/d7bsN1XVcAAADAEpl+DwAAAADhRqAEAABASQiUAAAAKAmBEgAAACUhUAIAAKAkBEoAAACUhEAJAACAkhAoAQAAUBICJQAAAEpCoAQAAEBJCJQAAAAoCYESAAAAJSFQAgAAoCQESgAAAJSEQAkAAICSECgBAABQEgIlAAAASkKgBAAAQEkIlAAAACgJgRIAAAAlIVACAACgJARKAAAAlIRACQAAgJIQKAEAAFASAiUAAABKQqAEAABASQiUAAAAKEnM7wEAQBC5rivbtuU4jlzXlWEYMk1TlmXJMAy/hwcAgUKgBABJhUJBg4ODyufzGhoa0vDwsBzHmfE60zRVV1en+vp6JRIJNTQ0KBbjUgqguhmu67p+DwIA/OC6rvL5vPr7+5XNZpd8nFQqpebmZiUSCWYvAVQlAiWAqpTL5ZTJZDQyMuLZMePxuNLptJLJpGfHBIAwIFACqCqFQkHd3d0lzUguJJVKqb29naVwAFWDQAmgauRyOXV1dcm27bKfy7IsdXR0MFsJoCoQKAFEnuu66u3tVU9PT8XPnU6n1dLSQm0lgEgjUAKINNd1lclk1NfX59sYWlpalE6nCZUAIosbmwOItN7eXl/DpCT19fX5PgYAKCcCJYDIyuVyvixzzyaTySiXy/k9DAAoCwIlgEgqFArq6uryexjTdHV1qVAo+D0MAPAcgRJAJHV3d1ekm3sxbNtWd3e338MAAM8RKAFETi6XK+t9JkuRzWZZ+gYQOQRKAJEy0dUdZJlMRtxgA0CUECgBREo+n/d0O8VyGBkZUT6f93sYAOAZAiWASOnv7/d7CEUJyzgBoBgESgCRUSgUPK2d/P73v6+DDz5Yp512mmfHnJDNZun4BhAZBEoAkTE4OOjp8W6++WZJ0tNPP61HH33U02NL3o8XAPxCoAQQGV7WJf7lL3/RU089pWOPPVaSdNNNN3l27AnUUQKICgIlgMgYGhry7FgTAfLcc8/VoYceql/96leeB0ACJYCoIFACiATXdTU8POzJsYaHh3XbbbfpoIMO0saNG3XaaadpcHBQd9xxhyfHn5DP57l9EIBIIFACiATbtuU4jifH+vWvf609e/ZMNuO87W1vU319vefL3o7jBG43HwBYCgIlgEjwKkxK48vddXV12rx5sySpvr5ef/M3f6OHHnpIL7zwgmfnkbwdNwD4hUAJIBK8Wjretm2bHnzwQR1zzDFyXVe5XE65XE5vectbJL3S+e0VlrwBRIHhcjUDEAGjo6P661//WvJxvvGNb+g73/nOnM+3trbq17/+tSzLKvlckrTvvvuqtrbWk2MBgF9ifg8AALxgmqUvuNi2rZ/97Gfq7OzUP//zP894/q677tK1116rLVu26E1velPJ55O8GTcA+I1ACSASLMuSaZol1SRu2bJFPT09+sxnPqMjjjhixvMbNmzQDTfcoJtuusmTQGmapmcznQDgJz4aA4gEwzBUV1dX0jFuuukm1dTU6J3vfOesz69YsUInnHCC7r77bvX19ZV0LklKJBIyDKPk4wCA36ihBBAZO3bs8CToVUpLS4tWrlzp9zAAoGTMUAKIjEQi4fcQFiVs4wWAuRAoAUTCC7vy+tHju2WHaM0lUd/g9xAAwBM05QAItRd25fXLJ/r058yAJKkpLW1slMyAlyYuS6bkGDGN2lLMDP54AWA+BEoAobR3kJzwl6yp/ZLB331m+YpmSZLjSqP2eKAkWAIIKwIlgFCZK0hOyAxL/SPSitrghrPaeFzxuun1kwRLAGFGoAQQCgsFyVcYuq/f1OZVwZ2lbG5Jz3m7IIIlgDAiUAIItOKD5Li6mKkDXtWkhoa8Bvfkyjy6xWtMptTQmFzwdQRLAGFCoAQQSEsJksevb9LxG5rUUGupUCho69ZB2bZd5pEWz7Isdaxql2VJBUdFdaQTLAGEATc2BxAopQbJqXK5nLZt21aOYS7J6tWrlUy+MjvpusUHywkESwBBRKAEEAheBsmpenp61NPT49UwlyydTqu1tXXW5wiWAMKOQAnAV+UKkhNc11Umk/F1S8aWlhal03M34kwgWAIIKwIlAF+UO0hO5bqu+vr6lMlkljLUksw3MzkXgiWAsCFQAqioSgbJveVyOXV1dVWkUceyLHV0dEyrmVwsgiWAsCBQAqgIP4PkVIVCQd3d3cpms54dc2+pVErt7e2Kxby5kQbBEkDQESgBlFVQguTecrmcMpmMRkZGPDtmPB5XOp0uaVZyPgRLAEFFoARQFkENklO5rqt8Pq/+/v6SZixTqZSam5uVSCQWbLzxAsESQNAQKAF4KgxBcjaFQkGDg4PK5/PK5/MaGBySoZmXR9M0lUgkJr8aGho8W9peLIIlgKAgUALwRFiD5Fwe25bT4MiYJHc8uRmGGmpjOmh1qiKzkItBsATgN7ZeBFCSqAXJSYYh13h5fBOhy7QCFyYlyTCkGkuKLSJYsqUjAC8RKAEsSWSDZIgRLAH4hUAJYFEIksFHsARQaQRKAEUhSIYPwRJApRAoAcyLIBl+BEsA5UagBDArgmT0ECwBlAuBEsA0BMnoI1gC8BqBEoAkgmQ1IlgC8AqBEqhyBEkQLAGUikAJVCmCJPZGsASwVARKoMoQJLEQgiWAxSJQAlWCIInFIlgCKBaBEog4giRKRbAEsBACJRBRBEl4jWAJYC4ESiBiCJIoN4IlgL0RKIGIIEii0giWACYQKIGQI0jCbwRLAARKIKQIkggagiVQvQiUQMgQJBF0BEug+hAogZAgSCJsCJZA9SBQAgFHkETYESyB6CNQAgFFkETUECyB6CJQAgFDkETUESyB6CFQAgFBkES1IVgC0UGgBHxGkES1I1gC4UegBHxCkASmI1gC4UWgBCqMIAnMj2AJhA+BEqgQgiSwOARLIDwIlECZESSB0hAsgeAjUAJlQpAEvEWwBIKLQAl4jCAJlBfBEggeAiXgEYIkUFkESyA4CJRAiQiSgL8IloD/CJTAEhEkgWAhWAL+IVACS/SNLds0UnAWfB1BEqisUoJlHe+KwJLwpwMs0UIzGQRJwF9LCZYAloZACXiMIAkEC8ESKD/T7wEAQXDhhRfKMIxpXytXrlzUMepipjbv16KvvHWDTjmwlTAJBMxEsIxbkrXIWsm7775bp556qlatWiXDMHTLLbeUZYxAWDFDCbxs06ZN+s1vfjP5vWUVFwiZkQTCZSkzloODg3r1q1+ts88+W6effnr5BwmEDIESeFksFlvUrGRdzNRx6wiSQFgtJlhu3rxZmzdvrtzggJBhyRt42datW7Vq1SqtXbtW73vf+/Tss8/O+/rPv3kdS9tABExdCgewNARKQNLrX/96XXfddbr99tt11VVXaceOHTrqqKPU398/588QJIFoMbgHJbBkLHmj6riuK2Ovd46pS1kHH3ywjjzySK1fv17XXnutPvvZz1Z6iABCzHUJp6g+BEpUjed35rVzaFSHrEoqtsDFvqGhQQcffLC2bt1amcEhcPZvb9Det61nSQfFsp3xUMnOO6gWBEpE3vM78/rlk736S2ZQ79jUWtTPjIyM6IknntAxxxxT5tEhqGpixEcsnStpjC0dUUUIlIisqUFyIeedd55OPfVUrV69Wj09Pbr44ouVy+V01llnVWCkAIJuYGBATz/99OT3zz33nB555BE1NTVp9erVc/4ce4WjWhAoETmLCZITXnzxRZ1xxhnq6+tTa2ur3vCGN+jee+/VPvvsU8aRAgiLBx54QMcff/zk9xO11WeddZauueaaBX+eYImoM1zXZRMqREIxQfIdm1r15g3NinE1B1Amrjt+T8vC3kW4UxAsETXMUCL0ljIjCQB+YsYSUUOgRGgtNkjWxUytXp5Y9B6+ALBYxV5mCJaICtoYETrP78zr//vDNn31rueLCpN1MVOb92vRV966Qfu3Ncy4ByUwmyuuuEKHHHKIksmkksmkjjzySN12221+DwshYBiSZY7vvFPsB9iJYDlqj///QNhQQ4nQWMqM5PHr2WsbS/Pzn/9clmVpw4YNkqRrr71WX/3qV/Xwww9r06ZNPo8OYeIWsVf43pixRNgQKBF4BEkERVNTk7761a/qox/9qN9DQQgRLBFl1FAisAiSCArbtvXjH/9Yg4ODOvLII/0eDkLKMKQaS4otIlhSY4mwIFAicAiSCIrHHntMRx55pIaHh7Vs2TLdfPPNOvDAA/0eFkKOYIkoYskbgUGQRNCMjo5q27Zt2r17t37605/qO9/5ju666y5CJTzFUjiigEAJ3xEkERYnnnii1q9fr//8z//0eyiIIIIlwowlb/iGIImwcV1XIyMjfg8DEcVSOMKMQImKI0giDL7whS9o8+bN6uzs1J49e3TjjTfqzjvv1K9+9Su/h4aII1gijAiUqBiCJMIkk8nogx/8oLq7u5VKpXTIIYfoV7/6ld7ylrf4PTRUCYIlwoQaSpQdQRIASkeNJYKMQImyIUgCgPcIlggiAiU8R5AEgPIjWCJICJTwDEESACqPYIkgIFCiZARJAPAfwRJ+IlBiyQiSABA8BEv4gUCJRSNIohqMFhw5e10eTcNQbcz0aUTA4hAsUUkEShSNIIlq8tj2PRoYsac9tixu6eDORp9GBCwNwRKVwI3NsSCCJACEFzdIRyUQKDEngiQARAfBEuVEoMQMBEkAiC6CJcqBQIlJBEkAqB4ES3iJQAmCJABUMYIlvECgrGIESQDABIIlSkGgrEIESQDAXAiWWAoCZRUhSAIAikWwxGIQKKsAQRIAsFQESxSDQBlhBEkAgFcIlpgPgTKCCJIAgHIhWGI2BMoIIUgCACqFYImpCJQRQJAEAPiFYAmJQBlqBEkAQFAQLKsbgTKECJIAgKAiWFYnAmWIECQBAGFBsKwuBMoQIEgCAMKKYFkdqjpQuq4r27blOI5c15VhGDJNU5ZlyTD8/+0lSAIAoiJKwTLo+cEPVRUoC4WCBgcHlc/nNTQ0pOHhYTmOM+N1pmmqrq5O9fX1SiQSamhoUCxWuf+pCJIAgKgKY7AMS37wU+T/K13XVT6fV39/v7LZbFE/4ziOhoaGNDQ0NPlYKpVSc3OzEolEyZ8+ntuZ10vZYa1trteqZHzycYIkAKBaeB0sHXf8yzS8CZxBzA9BFulAmcvllMlkNDIyUvKxstmsstms4vG40um0ksnkoo/huq5u/nOPfvv0zsnHTj+4Teua6gmSAICq5EWwdF7+2QnWy48vNb8FLT+EgeG6bhH/dOFSKBTU3d1d9CeKpUilUmpvb1/UVPb/PrdLNz6yY8nnJEgClfPY9j0aGLGnPbYsbungzkafRgRUB3cRwXI+MXP8azGCmh/CIFr/NRr/VNHV1SXbthd+cQmy2awGBgbU0dFR1KeN7buH9ZNHM0s6F0ESAFAtljJjOZuCs7jl76Dmh7CITKB0XVe9vb3q6emp2Dlt29a2bduUTqfV0tIyZ21EfszW1fd1qeAs7q+CIAkAqFZeBMsxW6q15l/6DnJ+CJNIBErXdZXJZNTX1+fL+TOZjGzbVjqdnvFL4bqu/uu+LvUMjhZ9PIIkAADjSgmWrqQxR6qZo54yyPkhbCIRKHt7e337ZZjQ19cny7LU2to67fEfP5rREz3FNdvUWoZO2NBMkAQAYC9LDZYTDTs1s7ytBjk/hM0iy1WDJ5fLVXSaej6ZTEa5XG7ye8dx9Pvndxf980evWaFTDmwlTAIAMIeJYGktYkLPdsebfaYKcn4Io1AHykKhoK6uLr+HMU1XV5cKhYIkyZEWVTe5Z6RQplEBABAtiy2pnBoog54fwijUgbK7u7vs3ViLZdu2uru7JUkx01QyXvxs46b0snINCwCASFnMDKUkmVMST9DzQxiFNlDmcrmy3ieqFNlsdnLq+rw3rVkwVC6rtXTKAS06ojM6tw8AwsxxXdmzrC7YjisnerfuBUJp4qbmxaid8rqw5IewCeWNzV3X1dNPP+3JHezLJR6Pa8OGDZNdW8NjtuZa/a6rMWWGvLsLiIquXcN6cefwnH+vpiG9qqlOHSvqKjswALOaL8W47vSZyTDmh7AIZZd3Pp8P9C+DJI2MjCifz6u+vl6SVDdbexmAQMnmC9rWPzzvaxxX2tY/rMa6mJKJUF5CgUiZL3ft/VwY80NYhHLJu7+/3+8hFCUs4wQwLpcvviA+u4jXAgiGsLwvh2WcU4Xu43WhUPC09uGpp57S9773PT3wwAPq7e2VZVlas2aN3va2t+n0009XKpVa8rGz2Wwk9+sEoipRU/xn7PraUH4eB6qWV/nhlltu0QUXXDDtsRUrVmj9+vX68Ic/rDe96U0lnyOM+SE8I33Z4GBxNwkvxk9+8hNdcsklWrNmjT784Q9r/fr1Ghsb0+OPP64f/ehH+tOf/qRvfOMbJZ1jcHCwpFAKoHJWNNSoxjI0tsAdk2ssQ8vrayo0KgBe8DI/SNJFF12ktWvXynVd9ff364YbbtAnPvEJfetb39Jxxx1X8vHDlh9CFyjz+bwnx3nkkUd08cUX6w1veIO++c1vqra2dvK5o446SmeddZa2bNlS8nny+XyofiGAamaZhjpWxPV83/x1lB0r6mSZ4SqYB6qdV/lhwsaNG7Vp06bJ748++mgdffTR+uUvf+lJoAxbfgjdms3Q0JAnx/nOd74jwzB04YUXTguTE2pqanT88ceXfB6vf4EBlFdbMq6aeW5wV2MZakvOvGYACDav8sNc4vG4ampqVFPjzepF2PJDqGYoXdfV8PD8MwfFsG1b9913nw488ECtXLnSg5HNLZ/Py3Xd0LX/A9VqoVlKZieB8PEqP0xl27YKhcLkkvc111yjfD6vk046yZPjhy0/hCpQ2rYtx3FKPs6uXbuUz+fV0dHhwajm5ziObNsOVWEtUO3aknG90D884/52hiFmJ4EQ8io/THXmmWdO+762tlZf+MIXdPTRR3ty/LDlh3CM8mVe/zJUSljHDVQryzTU1lirTG502uNtjbXMTgIBNjZma0d/Tt29WXX3ZrWjb/z/Dg7mddZJB3p6rksvvVTr1q2TND5R9dvf/laXXHKJbNvW+9//fk/OEab8EKpA6dWmPitWrFAikajYxvAh3IwIqHrr2uplO652Do5JkpoaarSuLVw3GgaiYq6guKN3+mO9uwZm/fnVK1OeB8p169ZNa8p54xvfqO7ubv37v/+7TjnlFCWTpW+nHKb8EKpA6VUdgWVZev3rX68tW7Zox44dZa+jDEv9A4DpNq5s8HsIQKSVGhSLPk+hMjN9++67r37/+9/rhRde0MEHH1zy8cKUH0IVKE3Tu6b0j370o/rf//1fXXjhhfrWt741oytrbGxMv//97z1p/fdy3AAABF2lgmKxhkfHKnKeJ598UtL4SqgXwpQfQhUoLcuSaZqe1BQceuih+tKXvqRLLrlE73nPe/Te975X69evV6FQ0JNPPqmf/OQn2rBhQ8mB0jRNWRb7eANh47ruZCH/RKflxN9zmGYNAC8FLSgWa1duWIP5UTUkvGuq27p1qwqF8S1Ys9msfvOb3+iee+7RCSecoFe96lUlHz9s+SFUgdIwDNXV1Xl2L6l3vetdOvjgg3Xdddfp6quvVl9fn2KxmNasWaOTTjpJZ5xxRsnnSCQSvPkAIVAoFDQ4OKh8Pq+hoSENDw/P+uHVNE3V1dWpvr5eiURCDQ0NoenCBOYS1qBYrHhtTM+9tFub1rV69p48dfvFxsZGdXR06HOf+5ze9773eXL8sOUHww1TxaekHTt2qK+vz+9hFK2lpaXsNZoAlsZ1XeXzefX395e0x28qlVJzc3Po3gAQfdUQFFe2pNTeOv61siU5/v+3JNXellJ763KtbElqRbJemUyG/FBGoftYnUgk/B7CooRtvEC1yOVyymQyGhkZKflY2WxW2WxW8Xhc6XTak+5OYD4ExVeCYrEf4sL2fhy28YYuUDY0hKvrMmzjBaKuUCiou7u7pBnJuYyMjGjbtm1KpVJqb29nKRyLVk1BcTIkTgmKE88tJigWK2zvx2Ebb+iudrFYTKlUqixvBl5LpVK8oQABksvl1NXVJdu2y3qebDargYEBdXR0MFsZIXv27NEFF1ygm2++WT09PTrssMP0jW98Q0ccccSCP0tQLF9QLBb5obzCNdqXNTc3h+IXorm52e8hANB4rWRvb696enoqdk7btrVt2zal02m1tLRQWxkBH/vYx/TnP/9Z3/ve97Rq1Spdf/31OvHEE/X4449P28rXth39+p4ndMUNd4U+KNbWxGZfdm5NBSYoLgb5oXxC15Qjjb85PP30057UPpVLPB7Xhg0bQvEHBkSZ67q+F+O3tLQonU5zPQixfD6vxsZG3XrrrTr55JMnHz/00EN1yimn6OKLL558bHSsoG9e/z+64Js/82OoRYlaUCwW+aF8QjlDaRiG0um0tm3b5vdQ5sSbBxAMvb29vnd29vX1ybIstba2+joOzL/0nBsY1g/+34/O+nOFQkG2bauurm7a44lEQlu2bKnE0IsyERRnLDu3prSy9ZUml6gFxWIZhqG2tjZt377d76HMKaz5IZSBUpKSyWRgayFq6xu1bFmj38MAql4ul6voMvd8MpmM4vE4NZVl4kWN4vLGubtqGxsbdeSRR+qiiy7SAQccoHQ6rRtuuEF//OMftXHjxnL8J01DUPTGwEhBl9/1kvatH9Nh6ZisgP1vlUqlQnuNCG2glKT29nYNDAyUvcB+UQxTsWUteik7qrbGGtXGwrNtEhAlhUJBXV1dfg9jmq6uLtXX14eu2N5PQWpm+d73vqePfOQj6ujokGVZes1rXqP3v//9euihh5Z8TIJi5TzfP6Qv//dTenH3sB6NSfs3Nai+RjID8r+rZVlqb2/3exhLFuqrWiwWU0dHR6CWvuOpNhmmpTHb1UvZUbUuq1FDPDxbJwFR0d3dHawPmxpv1Onu7lZnZ6ffQ/FdkIJisdavX6+77rpLg4ODyuVyam9v13vf+16tXbt2xmst09Q+q5ong+LKlqRWTdQsTqldbEo1EBQrYMszO3XZHVuVHxvf/WqoIN3w5Ij+7pDg3Ouxo6Mj1B82Q9mUs7eenp5ALGvVLGtS7bKmGY8vT1haXh/jogFUSC6XC9QHzb2tXr06tMtaCwljUJywvDGh7ru/WvTrd+3apbVr1+pf//Vf9fd///eTj0+8rXLN95/jurr2j9v1vftmX614yz61OnV9vMKjmimdToe+xjq8UXiK1tZWOY7ja+F9bcMKxRpWzPrc7rytkYKrtsYamSYXGKCcJrq6gyyTyaixsTFUgSPMQbEYtTUxdbbPnBCY6vbbb5frutpvv/309NNP63Of+5z2228/nX322dNeF6Z/1ygbGCno0tu36t7nd8/5mgd6XZ2yKSljOFe5ge2lpaVFLS0tvp3fK5EIlBNd35Zl+fJGkk6ntaKpRZk9oxotzD7hmx9zqKsEKiCfzwf6liDS+I46+Xxe9fX1C752z+Cwfv67R/XCS/168xv21+sPmbm8WopqCIpTaxRLWXrOZrP6/Oc/rxdffFFNTU06/fTTdckll6impqZC/zUo1tR6ybnsn16mfz5pX7Usq1VfX59v+SHsM5MTIrHkPVWldsKQxgtop+6E4biu+gcKGhiZ+9yGIeoqgTLavn17IO/+sLdUKrVgLeWt//MnfeZffqTu3vH/HtM09B//z5n64NvfsODxCYrUKFarveslZ7P5wFZ9+rh10yZ4/MwPURC5QCmVd6/eCXPt1eu6rvYM2+ofLMz789RVAt4rFAp68skn/R5G0fbff/9Zi/BfzOzSZ/7lx/rFnY/OeO5V6eX6zdWfUaZ/D0GR6yemWKheUpIs09Anjl2jtx88+70e/cwPYRfJQDkhl8spk8l4uvwVj8eVTqcX/FQxPOYokxuVM8//uokak7pKwEPZbLbkGxbfcsstuuCCCya/r62tVWNjo9atW6ejjjpKp512mmfbonV2diqVSk1+b9uOLr3yl/r3a3+r/MiYJ+cICoIiyqmYeskV9TW68KR9dfCqhWcF/cwPYRWteLyXZDKpxsZG5fN59ff3l/SJI5VKqbm5WYlEoqiLXV2NqY7lceoqgQrK5/OeHeuiiy7S2rVrVSgUtHPnTj300EO6+uqrdc011+irX/2qjjzyyJLPkc/nJwPlwNCwDjzlwtDNLBIU4bfF1Eu2NhbX0e1nfgirSAdKabxhp76+XvX19Wpvb9fg4KDy+fzkl+PMrLEwTVOJRGLyq6GhYUlT0zHLUHuqdt66Su5XCXhnaGjIs2Nt3LhRmzZtmvz+LW95iz70oQ/pQx/6kD7zmc/oF7/4RcmdmVMD8BnnfSdQYZKgiDBYar1kMfzMD2FUHf+VL4vFYkqlUpMzAq7ryrZtOY4j13VlGIZM05RlWZ5dIE3DUMuymOIxY866SteVevaMaXnBoa4SWCLXdTU8PPcMhRfa29t13nnn6bzzztOPf/xjffzjHy/pePl8fvLa8/gz3R6Ncn4ERUSBF/WSi+FHfgibqgqUezMMoyKfHAzDUDIRU23MnLeukvtVAks3cXEvt2OOOUaWZenBBx8s+ViO48i2bcViMR20YZVe6ln6shpBEdXC63rJpahUfggT/teoIOoqgfKpRJiUpPr6ei1fvly9vb2eHG9i3N/+0hk68ozL1Z8dXPBnXn/IWn3s9KMJiqg65aiXhDcIlBVGXSVQHpW8YYWX55o4Vmd7k5779SX67s1/0A9ve0B/fOx52fbsIfldb32NPlDEvSiBKClnvSRKR6D0AXWVgPcq9TcyNDSkbDarjRs3enK8qeOuqYnp799zrP7+PceqZ+ce3fjL+3XdrffoL0+/Ul954Pp2ffidR3lybiAMKl0viaUhUPqEukrAW6ZZmRmJu+++W7Zt64gjjvDkeHONu62pUZ/6wJv1yTOP10OPb9NDj29TQyKu0048VIm6Wk/ODQRdEOolURwCpc+oqwS8YVmWTNMsay1ld3e3/u3f/k2NjY1697vfXfLxJrpC52MYhg7ftI8O37RPyecDwoR6yXAhUAYAdZVA6QzDUF1dnWf3oty6dasKhYJs29bOnTv14IMP6tZbb5Vpmvr617+upqamks8R9RsdA0tFvWT4ECgDgrpKoHT19fWeBcqJ7Rdramomt178yEc+or/927/1JExK44ESwCuolwyvSO/lHVbsAw4sjRd7eVfS3nt5A9WMeslwY4YygKirBJamoaHB7yEsStjGC5QL9ZLhRxIJqIm6ymXz1EtO1FUOzlF3CVSbie3RwiCVSrHTBqDxeslzfvTYvGFy84Gt+vrpmwiTAcbVLMCoqwQWJz9mq2u0Rsv8HkgRmpub/R4C4CvqJaOFQBlw3K8SWJjjunqqd0APvrhbo7ajg+KmEoajoL7/xONxGnJQ1aiXjB6ackKkYLvz1lVKUo1lUFeJqtIzMKJ7Xtip/qGxyceWm2PaN573cVTzW716tZJJ3iRRnaiXjCYCZcg4rjvv/SolyTDE/SoRefkxWw+8uFtb+wZnfX5dzZCarULgZilTqZQ6Ozv9HgbgC+4vGV0EyhByXVd7hu056yonLE9Y1FUicqYvb899+YrJ0SF1g4oZwbnEWZaljRs30oyDqkO9ZPRxVQsh6ipRrWZb3p7Lq1Y0qH1FSr3dc7+BVVpHRwdhElWHesnqwAxlyFFXiWqw0PL2VMm6mI5cvUIdqfGml56eHvX09JR7iAtKp9NqbW31exhARVEvWT0IlBFQbF1lx/Ja1ViESoRHscvbkhQzDb16VVIHpZOypszIu66rTCajvr6+cg93Ti0tLUqnWcZDddmRG9ZHv/8n6iWrBGsvEVDM/SprTIMwiVBZzPL2mhUJva5zhZbFZ17SDMNQOp2WZVnKZDLlGOq8mJlEtVqZrFN7qk7P9g3NeI56yeghUEbEQnWV9XFLruvyh4vAK2V5ey6GYai1tVXxeFxdXV2y7fLvLmVZljo6Org9EKpWwXF1zPqmGYGSesloIlBGzFz7gMdoykHAebG8vZBkMqn6+np1d3crm82WOuQ5pVIptbe304CDqrcyOb0uknrJ6OJqF0ET+4BPraskTiLIvFreLkYsFlNnZ6dSqZQymYxGRkaWdJzZxONxpdNpZiUBjb/vWFNWxaiXjDYCZUQVU1cJ+K0cy9vFSiaTamxsVD6fV39/f0kzlqlUSs3NzUokEpSVAHuhXrI60OVdBYbHHNmOq/pac8Yf82WXXaabbrpJTz75pBKJhI466ihdfvnl2m+//XwaLapBJZa3F6tQKGhwcFD5fH48ZO7eo7qamTMppmkqkUhMfjU0NLC0jarS1dWl888/X7fddpvy+bz23Xdf/dd//ZcOP/zwaa+zHVe/f3anVtTXUC9ZBQiUVcJxXBmGZgTKt73tbXrf+96nI444QoVCQV/84hf12GOP6fHHH1dDQ4NPo0WUVXJ5uxRvOv9n2tq1U/GYqdqYqdGCowP3adIvLjyZWRZUrV27dumwww7T8ccfr49//ONqa2vTM888ozVr1mj9+vXTXms7rsZsR3U1bANcDfhYXSVM09Bsnx1+9atfTfv+u9/9rtra2vTggw/q2GOPrdTwUAX8XN5eql17lYusHnYIk6hql19+uTo7O/Xd73538rE1a9bM+lrTEGGyilAZW0WKeSOcqCNramoq93BQJRzX1RM9e/TTx15aMEzGTEOHvyql0za1+x4mAcz0s5/9TK997Wv17ne/W21tbTrssMN01VVXzfpaPnxVFwIlJrmuq89+9rN64xvfqIMOOsjv4SACegZG9PPHd+ieF3YtWCu5ZkVCf3tQu17dniprrSSApXv22Wd1xRVXaOPGjbr99tv1D//wD/rUpz6l6667zu+hwWcseWPSJz7xCT366KPasmWL30NByIVxeRvAwhzH0Wtf+1pdeumlkqTDDjtMf/nLX3TFFVfoQx/6kM+jg58IlJAkffKTn9TPfvYz3X333XrVq17l93AQUkHs3gbgnfb2dh144IHTHjvggAP005/+1KcRISgIlFXOdV198pOf1M0336w777xTa9euXfD11MVgNmHp3gawsLmu9UcffbSeeuqpaY/99a9/1T777FOpoSGguJpXuXPOOUc/+MEPdOutt6qxsVE7duyQNH6j5kRi9iVIx3FlMqOEl7G8DUTLwEhB8ZipGmvmdf4zn/mMjjrqKF166aV6z3veo/vuu09XXnmlrrzySh9GiiChKafKXXHFFcpmszruuOPU3t4++fXDH/5w1te7kl7Kjmq04FR2oAgkx3V185/p3gai4vn+If3jDx+TM8ctqo844gjdfPPNuuGGG3TQQQfpoosu0te//nWdeeaZFR4pgoYZyiq3lPvaj9muXsqOqnVZjRri3GOsmpmGodqYpeHC3Nt7srwNhMOWZ3bqsju2Kj82/4TBKaecolNOOaVCo0JYcIXHkriu1LNnTMsLjpbXx6irrGKxOf7tWd4GwsFxXV37x+363n1dfg8FIUagxKLsPaG5O29r1HbVuqyGukpIonsbCJOBkYIuvf1p3fv8rmmPD485isdYgULxqKFE0VzX1fAsSyFDow51lRF12WWXyTAMnXvuuUW9npuTA+Hxws7xesm9w6QkPdqVU8Hhmo7iMUOJohmGoYERe9bnqKuMnvvvv19XXnmlDjnkkAVfy/I2EC5bntmpf7njaQ2NzX5Nv+PJXh2zobnCo0KYMUOJormuq0TN3L8yE3WVuwbHltTsg+AYGBjQmWeeqauuukorVqyY97UHpJfRvQ2EhOO6+u692/Tl/35qzjBpmYZeu3o513EsCoESRTMMQ8lETO2pWs23mrk7b6tnz5gch4tRWJ1zzjk6+eSTdeKJJy742v1aG1neBkJgYKSgL/38qXmbb1bU1+hrf3ug3nHISpotsSgseWPR6mpMdSyPK7NnVKOF2UPjRF1lW2ONamN8bgmTG2+8UQ899JDuv/9+v4cCwCMv7BzSBb94Si/uHp7zNfunl+mfT9pXrY3xCo4MUUGgxJLELEPtqVr1DxSoq4yQ7du369Of/rTuuOMO1dXV+T0cAB5YqF5SkjYf2KpPH7eOCQAsGYESS2YahlqWxRSPGeofnP3G1tyvMrhm26v3wQcfVE9Pjw4//PDJx2zb1t13361vf/vbGhkZkWXx4QAIg2LuL2mZhj5x7Bq9/eA012eUhECJkkzUVdbGTGVyo5qrbJL7VQZHfsxWVzav9c0NM5474YQT9Nhjj0177Oyzz9b++++v888/nzAJhMRc95ecakV9jS48aV8dvCpZwZEhqgiU8MREXWXPnlGNUFcZSI7r6qneAT344m6ta2qYNVA2NjbqoIMOmvZYQ0ODmpubZzwOIJiKqZc8IL1MF568r1qXUS8JbxAo4ZmYZWgldZWB1DMwonte2Kn+oTG/hwKgjIqplzzpwDZ96ri1fLCHpwiU8BR1lcGSH7P1wIu7tbVvcMnHuPPOO70bEICyoF4SfiNQwnNT6yp7cqOyqausuKnL26Nz/QMAiATqJREEBEqUTV2NqVXUVVZcMcvb9iwd3gDCh3pJBAWBEmVFXWXlLGZ5e9R2KjAiAOVEvSSChECJsqOusrwWs7wdMw29elVSB6VZ9gLCinpJBBGBEhVBXWV5LKZ7e82KhF7XuULL4vzZA2FFvSSCincWVBR1ld5YzPJ2si6mI1evUEcqUYGRASgX6iURZARKVBx1lUu31OVti9leINSol0TQESjhi6XUVUrSqO3KcVzV1ZhVVxfE8jYQfWO2o0e7ckrW1WhDa71ciXpJhALvNvDNYuoqRwqOJEP5sfHuZMuU2lO1qrGi/0mc5W2gOnTtHta5P/2z+gfHPzS+Yc1y2Y50/7bdc/4M9ZIICgIlfFdMXWV+zJX0ynO2I/XuGVN7qjayn8hZ3gaqh+u6uuT2rZNhUpLufX73vD9DvSSChECJQCimrnJvIwVXw2OOErXRq7FkeRuoLg+/mNOTmYGiX0+9JIKGdyAERjF1lXvL5m3PAqXrurJtW47jyH15JxnTNGVZVllmQXcNjepP3TkNjNrqXF6nQ1YmNVxwWN4GAqjc14cbH5y7RnIq6iURVARKBMrUuspMdlQL7eeSH3M0UnAUX8Kn9EKhoMHBQeXzeQ0NDWl4eFiOM/OMpmmqrq5O9fX1SiQSamhoUCxW2p9ONj+m/36yZ3LHmp6BEb24e1i78qMsbwMBUMnrw9O9g3pgW3bB1yXrYrrolP2ol0QgESgRSHU1puI15mQTznx2DRa0MlVb1HFd11U+n1d/f7+y2YUv4JLkOI6GhoY0NDQ0+VgqlVJzc7MSicSiZwlc19WW53fO2P4wMzCy4M+yvA2Uj1/Xh6vv2V7UufZrayBMIrB4V0Igua5bVJiUXp6lHHMUr5l/ljKXyymTyWhkZOHgtpBsNqtsNqt4PK50Oq1ksviL/FO9g0WFx6lY3gbKy6/rw9begXl3vZnqwe1Z2Y7LygQCiUCJQDIMQ6YhOfOv/k7K5gtqq5l9lrJQKKi7u7voGYfFGBkZ0bZt25RKpdTe3r7gUtfQqK37XyzuzUNieRsoN7+vDz9+qLvo4yXrYlwHEFgESgRWU0ON+gYW7nKWpt5QaLpcLqeuri7ZdnGd40uVzWY1MDCgjo6OeWcj7nq2T2ML1EhOYHkbKK8gXB+GRos/9/954z5eDw3wDO9UCKzGOku1MUMDw+M3Np/rHpWSJnfSmeC6rnp7e9XT01PuYU6ybVvbtm1TOp1WS0vLjNqpx7pz6t5T3HLaPssTevOG1nIME6h6Qbo+fPgNnfrDc7OvWtSYhja0NuiAlcu0+cA2rW9tqNh4gcUiUCLQ4jFT8WXjtZGu62q0MF5bOThia8x2ZRpS87KaaV3erusqk8mor6/PlzFnMhnZtq10evptPf6S2VP0MXIjxd02CcDiBO36sKG1QRedsp++8btnNTTq6FUr6nTifi3a1N6o9S0N3GcSoUGgRGgYhqF4jaF4jTljRnKq3t5e394sJvT19cmyLLW2vjLLOGYX12QkiWVuoEyCeH04el2Tjl7X5OuYgFLx0QeRksvlKrqMNZ9MJqNcLjf5/apkXVE/V2sZOrwjVa5hAVUryNcHIOyYBkFkFAoFdXUVt9tEpXR1dam+vl6xWEzHr2/Wr5/uU3duWK47vpyfrIupLmapLmYqHrPUGI9pnxUJJWqit50k4KegXx+AsOO3GJHR3d1d9m7NxbJtW93d3ers7JRpmnrrvm1+DwmoSkG/PgBhx5I3IiGXy5XlPnJeyGazLG0BPuL6AJQfgRKhN9G1GWSZTEauW+Rd2gF4husDUBkESoRePp/3ZLu0choZGVE+n/d7GEDV4foAVAaBEqHX39/v9xCKEpZxAlESlr+7sIwTmAtNOQi1QqHgWW3ULbfcogsuuGDW58466yydd955JR0/m80Wtd83AG9U6vogSVdffbWOOOKIJR+f6wPCjt9chNrg4KDnx7zooou0du3aaY+1tXnTnT04OKhUintMApVQqeuDJK1fv77kY3N9QJgRKBFq5ag72rhxozZt2uT5caXx8fKGAVQG1wegcqihRKgNDQ35PYRFofAeqByuD0DlMEOJ0HJdV8PDw54f17ZtFQqFaY95VdeUz+fluq4Mw/DkeABmV8nrg2EYsqzSd7fi+oAwI1AitGzbluM4nh/3zDPPnPHYww8/7EmodBxHtm1TeA+UWSWvD5Zl6ZFHHin52FwfEGb81iK0yvFmIUmXXnqp1q1bN+0xLy/w5Ro3gFdU8vrgJa4PCCsCJUKrXDtLrFu3rmxF91L5xg3gFVwfgMqiKQehFdY6o7COGwiTsP6dhXXcAIESoWWa4fz1Deu4gTAJ699ZWMcNsOSN0LIsS6ZphqrmyDRNT7pBAcyvXNeHrVu3zujylqTOzk41NTWVdGyuDwgzAiVCyzAM1dXVhepec4lEgiUtoALKdX2Ya/vFCy+8UKeffnpJx+b6gDAjUCLU6uvrPXvDeOc736l3vvOdnhxrLolEoqzHB/AKrg9A5VCsgVAL2wU4bOMFwixsf29hGy8wFYESodbQ0OD3EBYlbOMFwixsf29hGy8wFYESoRaLxZRKpfweRlFSqRQ7YAAVxPUBqBwCJUKvubnZ7yEUJSzjBKIkLH93YRknMBcCJUIvkUgoHo/7PYx5xeNx6qMAH3B9ACqDQInQMwxD6XTa72HMK51OczsQwAdcH4DKIFAiEpLJZGBrpVKplJLJpN/DAKoW1weg/AiUiIz29vbA7TJhWZba29v9HgZQ9bg+AOVFoERkxGIxdXR0+D2MaTo6OujcBAKA6wNQXgRKREoymVRbW5vfw5A0XhfFUhYQHMlkUiO1jX4PQxLXB0QPgRKR09raqpaWFl/HsKK5Rcub/B0DgOme6NmjP2Wll8ZqfR1HS0uL79cowGvMtSNyJro6LctSJpOp+PmbW9Na0dwq25VMR7L42Ab4ris7rHtf2CXJ0IuFuGwZ6qwZketKlWywTqfTam1trdwJgQohUCKSDMNQa2ur4vG4urq6ZNt22c9pWpbaVnZoWeMry1hjzviblckdQQDfZIfH9LtneuVOPmKouxBX3jG1tnZYNVOeKRfLstTR0cEyNyKLQIlISyaTqq+vV3d3t7LZbBnPk1Jzul2WNfNPasyWaq3KzoIAGDdScPTrrb0atWeGxt1OjVLtbarJ7y7r9SGVSqm9vZ0GHEQav92IvFgsps7OTqVSKWUyGY2MjHh27Hg8PllcX3CkgjPzNa7GZyprTEIlUEmO4+p3z/QpN1yY9fnXdKS0rqVRUmPZrw9A1BEoUTWSyaQaGxuVz+fV399f0oxEKpVSc3OzEonE5A4XliE5huTMsnrmuONhsyZYt8EDIu2P23fppdzwrM+tbarXq9tfCXrlvj4AUUegRFUxDEP19fWqr69Xe3u7BgcHlc/nJ78cZ+YUo2maSiQSk18NDQ2zLl0Zxvgs5KitWSuybFcyHClGkw5Qdk/07NETPQOzPtfSUKtj1jbNCHvlvD4AUcdvPapWLBZTKpWa3JLNdV3Zti3HceS6rgzDkGmasiyr6FkGwxivlxyZoweo4EiG6PwGyumVju6Z6mssnbihVTFz/j/CclwfgCgjUAIvMwzDk5mFiVA5OkeopPMbKJ+ZHd2vsExDJ25sVX3t4mtPvLo+AFHFPAlQBubLy99zGbMlt/x3KgGqynwd3ZJ07NpmtTT4e1NzIKoIlECZWObc9ZITnd+ESsAbxXR0r22qr/CogOrB/D1QRnR+h9ffvXV/nXzE6mmPrSKQBNZiOroBeM9wXeZIgHJy3bk7v6XxWUw6v4NnrODI3etfzZChGv6xAueJnj26Z44mnJaGWp20f9uCTTgASsMMJVBmdH6HE8ExHLzo6AZQOv7KgAqYCJVzGXNmXxYHMLdydXQDWDwCJVAhdH4D3qGjGwgWAiVQQXR+A6WjoxsIHgIlUGHWPDc1n+j8BjA3OrqB4CFQAhU2sef3XBvl2ITKQCgUCvrSl76ktWvXKpFIaN26dfrKV74y637OqJyl7NENoPzo8gZ8QOd38F1++eX6j//4D1177bXatGmTHnjgAZ199tlKpVL69Kc/7ffwqhId3UBwESgBn7Dnd7Ddc889esc73qGTTz5ZkrRmzRrdcMMNeuCBB3weWXWioxsINj7KAT6i8zu43vjGN+q3v/2t/vrXv0qS/vSnP2nLli066aSTfB5Z9aGjGwg+ZigBn1nmeIf3bHWTE53fNeb4bCUq5/zzz1c2m9X+++8vy7Jk27YuueQSnXHGGX4PrarQ0Q2EA4ESCAD2/A6eH/7wh7r++uv1gx/8QJs2bdIjjzyic889V6tWrdJZZ53l9/CqBh3dQDiwlzcQEOz5HSydnZ36p3/6J51zzjmTj1188cW6/vrr9eSTT/o4surBHt1AePCXCATEQtszFhzJ5o41FTM0NCRzr7BiWRa3DaqQhTu6WwiTQICw5A0ECJ3fwXHqqafqkksu0erVq7Vp0yY9/PDD+trXvqaPfOQjfg8t8orr6ObtCwgSlryBALKd8fA4G0PjoZMmnfLas2ePLrjgAt18883q6enRqlWrdMYZZ+jLX/6yamvpKC6XkYKjnz+xY84mnOPXt9CEAwQQgRIIqIIz9445E7cbIlQiShzH1R1be+dswnlNR0qHrkpVeFQAikEBChBQ7PmNakNHNxBeBEogoNjzG9WEPbqBcCNQAgFG5zeqAR3dQPjxFwoE3EKhcsyZ/YboQBjQ0Q1EA4ESCAH2/EYUsUc3EB0ESiAkrHl2ypnY85tQibBwHFf/80wve3QDEcE6AhAi7PldOX/3zbv0lxd2Tnts0z5NuupTb/JpRNFy7/Zd6s6NzPocHd1A+BAogRCZ6Pyea89v25UMhz2/vfDXrqwefrZ/2mM1MdK6F57o2aMn6egGIoW3HSBk6PxGmNHRDUQTf7VACNH5jTCioxuILgIlEFJ0fiNM6OgGoo1ACYQYnd8IAzq6gegjUAIhx57fCDo6uoHoI1ACIcee3wgyOrqB6kCgBCKAzm8EER3dQPXgLxmICDq/ESR0dAPVhUAJRAid3wgCOrqB6kOgBCKGzm/4iY5uoDoRKIEIovMbfqGjG6hOBEogguj8hh/o6AaqF4ESiCg6v1FJdHQD1Y2/biDC6PxGJdDRDYBACUTcfJ3fhsYDJU06WCrHddWVHVY8NvsnFzq6gepAoASqwGyd34bGZy8tStpQAkPS/m3L9M5NK2cERzq6gepBoASqxN6d3xNL4YYx/gUshWEYMg1DlmnozetbJh+noxuoLhS1AFViovN71H7le8ArpmFoWTw2OUtJRzdQXQiUQBWZaNLhlkEol/SyuA5e2UhHN1Bl+IsHqoxhjNdU0ogDr7muq03pRjq6gSpEoASq0Fy76AClWhYnTALViEAJVKm5ytvuvvtunXrqqVq1apUMw9Att9xS0XEhuC677DIZhqFzzz131uepmQSqF4ESwDSDg4N69atfrW9/+9t+DwUBcv/99+vKK6/UIYcc4vdQAAQQaxMAptm8ebM2b97s9zAQIAMDAzrzzDN11VVX6eKLL/Z7OAACiBlKAMC8zjnnHJ188sk68cQT/R4KgIBihhIAMKcbb7xRDz30kO6//36/hwIgwAiUAIBZbd++XZ/+9Kd1xx13qK6uzu/hAAgwAiUAYFYPPvigenp6dPjhh08+Ztu27r77bn3729/WyMiILMvycYQAgoJACQCY1QknnKDHHnts2mNnn3229t9/f51//vmESQCTCJQAphkYGNDTTz89+f1zzz2nRx55RE1NTVq9erWPI0OlNTY26qCDDpr2WENDg5qbm2c8DqC6ESgBTPPAAw/o+OOPn/z+s5/9rCTprLPO0jXXXOPTqAAAQUagBDDNcccdJ5eNvjGHO++80+8hAAgg7kMJoCRkz/AbLTh+DwFAyBEoAZRkzCFUhpnjuLp3+06/hwEg5AiUAJbMdSXHlZjgCq97t+/Sc/15FRz+EQEsHYESwJJMhElJsgmVofREzx492TMg23X1wq68HKaaASwRgRLAorjuy18aX+6eUHAkm1AZGl3ZYd37wq7J7+/btkt7RgpyXZemLACLRqAEsGgFRxq1Zz4+5rwya4ngyg6P6XfP9GrqP1W+4OgXj2f0wIu7VeAfEcAiESgBLIphSKYx9/NjNk06QTZScPTrrb0atWf+I43Yjloa4qqxeGsAsDhcNQAsmmVKsTmuHhNL4YTK4HEcV//zTK9yw4VZn39NR0prm+orPCoAUUCgBLAk1jwzlXR+B9O923epOzcy63Nrm+r16vZkhUcEICoIlACWxDCkGlOaa/Wbzu9gmejonk1LQ62OWdskw5inlgEA5kGgBLBkhiHVWnM/T+d3MOzd0T1VfY2lEze0KmbydgBg6biCACjJQqGSzm9/zdbRPcEyDZ24sVX18/0DAkARCJQASma+vPw9Fzq//TFfR7ckHbu2WS0NtRUeFYAoIlAC8ASd38FCRzeASiJQAvAMnd/BQUc3gEoiUALwDJ3fwUBHN4BKI1AC8BSd3/6ioxuAH7iqAPAcnd/+oKMbgF8IlADKgs7vyqKjG4CfCJQAyobO78qgoxuA3wiUAMqKzu/yo6MbgN8IlADKis7v8qKjG0AQECgBlB2d3+VBRzeAoOBKA6Ai6Pz2Fh3dAIKEQAmgYuj89sZCHd1voqMbQIURKAFUFJ3fpXEcV797pm/eju41dHQDqDACJYCKo/N76f64fZdeyg3P+hwd3QD8QqAEUHF0fi/NEz179AQd3QACiEAJwBd0fi8OHd0AgoyrDwDf0PldHDq6AQQdgRKAr+j8nh8d3QDCgEAJwHd0fs+Ojm4AYUGgBBAIdH7PREc3gLAgUAIIBDq/p6OjG0CYECgBBAad3+Po6AYQNlyRAARKtXd+09ENIIwIlAACx+/O77GCo/zozEaY/GhBY2Vcd6ejG0BYESgBBJJfnd9fv/VRtX/wOj32/M4Zzz32/E61f/A6ff3WRz0/Lx3dAMKMQAkgsCrd+b3l8R36/DX3aXCOUCdJg8MFff6a+7Tl8R2ennu+ju51dHQDCDgCJYDAqnTn992PvVSW1y5koY7uN9LRDSDgCJQAAq2Snd8bO1Jlee186OgGEAVcpQAEXqU6v08+Yh+1peoWfF16eUInH7FPyeejoxtAVBAoAYRCsZ3fU78Wqz4e02dPe/WCr/vsaYeoPh5b9PFd19WY7ch1XTq6AUSK4brVuEMugLAqOHPXTU5UGU5c1GrM8W7xxRgaKeiA/3OjerKzN8iklyf0+H+8d9GB8qXcsLY816+BUVsrEjUyDal/aGzW176mI6VDV3mzpA4AlcAMJYBQma/z25WmLR8v5dZCC81SLmV2ctR29Ltn+jQwakuSduXH5gyTdHQDCCMCJYBQWajze29Lqa38u7cdoNpZboIZrzH1sbcesOjjbduV10gR7eh0dAMIKwIlgNBZqElnqqUEyvp4TB84fuOMx888buOSaiczAyMLviYRM+noBhBai78yAkBAGNKsHdJTLbX7+//+4zHKDo3qv+/bJkk65XX76P/+4zFLOlZmz8KBMh6zVDfX1kAAEHA05QAIJdsZr5EsRtwan9X0w3DB1g8e7irqtceta9a65oYyjwgAvMfHYQChtJhPwnPcmaciipmdnDDs9V6SAFAhLHkDCCXLkObecXs6x9GiPz67rivbtuU44/eNNAxDpmnKsqxFNc081Tv7lop7MyStXp5Y3CABICAIlABCaaLbu5hl72Lm/QqFggYHB5XP5zU0NKTh4WE5zsyfNE1TdXV1qq+vVyKRUENDg2KxuS+lu+a4PdBUDTWWjl3XrGVLaPgBgCDg6gUgtCxz/J6Ujjt+s/O5Vrbnmk90XVf5fF79/f3KZrNFndNxHA0NDWloaGjysVQqpebmZiUSiRmzl3U1pgbH7FmP1dpQq03pRq1ZUS9zrptrAkAI0JQDIDImguXend21prT33XhyuZwymYxGRoqvcVxIPB5XOp1WMvnKjcl350d18593TAu7Hck6HdaRUtuyuGfnBgA/ESgBRI7jvNKIYxnTw2ShUFB3d3fRM5JLkUql1N7ePrkUPjxm68GurExD2q+1QU31BEkA0UKgBFA1crmcurq6ZNuzL0F7ybIsdXR0TJutBICoIlACiDzXddXb26uenp6KnzudTqulpYXtFAFEGoESQKS5rqtMJqO+vj7fxtDS0qJ0Ok2oBBBZ3NgcQKT19vb6GiYlqa+vz/cxAEA5ESgBRFYul/NlmXs2mUxGuVzO72EAQFkQKAFEUqFQUFdXcXtoV0pXV5cKhWL39wGA8CBQAoik7u7uinRzL4Zt2+ru7vZ7GADgOQIlgMjJ5XJlvc9kKbLZLEvfACKHQAkgUia6uoMsk8mIG2wAiBICJYBIyefznm6nWA4jIyPK5/N+DwMAPEOgBBAp/f39fg+hKGEZJwAUg0AJIDIKhUJgayf3ls1m6fgGEBkxvwcAAF4ZHBz07FhPPfWUvv/97+v+++9Xb2+vpPFtFF/3utfpXe96lzZt2lTyOQYHB5VKpUo+DgD4jUAJIDK8qkv80Y9+pMsuu0xr1qzRBz7wAa1fv16GYejZZ5/Vbbfdpve973365S9/qc7OzpLHS6AEEAXs5Q0gMp599lkNDQ2VdIyHH35YH/7wh3Xsscfqa1/7mmpqama85vbbb9dhhx2mtra2ks7V0NCgtWvXlnQMAAgCZigBRILruhoeHi75OFdddZVM09SXv/zlWcOkJL31rW8t+TzS+Ayl67oyDMOT4wGAX2jKARAJtm3LcZySj3H//fdr06ZNam1t9Whkc3McJ3C7+QDAUjBDCSASSg2TkrRr1y4NDw9r1apVM56zbXvazcgty/JkZtGLcQOA35ihBBAJ5S4Hf+9736vDDjts8uvaa6/15LiUsQOIAmYoAUSCF7OFK1asUF1dnV566aUZz11++eUaHh5Wb2+vPvnJT5Z8rgnUTwKIAgIlgEgwzdIXXCzL0ute9zr94Q9/UG9v77Q6yvXr10uSurq6Sj7PVF6MGwD8xpUMQCRYluVJOPvYxz4mx3H0la98RWNjYx6MbG6macqyrLKeAwAqgRlKAJFgGIbq6upKvg/lYYcdpi9+8Yu67LLL9J73vEfvete7tGHDBpmmqd7eXv3mN7+RNH4PyVIlEgmWvAFEAjc2BxAZO3bsUF9fnyfHeuqpp3T99ddPbr1oGIbS6bQOPfRQvf3tb9frX//6ks/R0tKilStXejBaAPAXgRJAZGSzWW3fvt3vYRSts7OTrRcBRAI1lAAiw4tl6EoK23gBYC4ESgCREYvFQjPjl0qlFItRxg4gGgiUACKlubnZ7yEUJSzjBIBiECgBREoikVA8Hvd7GPOKx+NKJBJ+DwMAPEOgBBApE93YQZZOp7ldEIBIIVACiJxkMhnYWspUKqVkMun3MADAUwRKAJHU3t4euF1oLMtSe3u738MAAM8RKAFEUiwWU0dHh9/DmKajo4PObgCRRKAEEFnJZFJtbW1+D0PSeN0kS90AoopACSDSWltb1dLS4usYWlpafB8DAJQTWy8CiDzXddXX16dMJlPxc6fTabW2tlb8vABQSQRKAFUjl8upq6tLtm2X/VyWZamjo4NlbgBVgUAJoKoUCgV1d3crm82W7RypVErt7e004ACoGgRKAFUpl8spk8loZGTEs2PG43GabwBUJQIlgKrluq7y+bz6+/tLmrFMpVJqbm5WIpFgBxwAVYlACQAaXwofHBxUPp+f/HIcZ8brTNNUIpGY/GpoaGBpG0DVI1ACwCxc15Vt23IcR67ryjAMmaYpy7KYhQSAvRAoAQAAUBJubA4AAICSECgBAABQEgIlAAAASkKgBAAAQEkIlAAAACgJgRIAAAAlIVACAACgJARKAAAAlIRACQAAgJIQKAEAAFASAiUAAABKQqAEAABASQiUAAAAKAmBEgAAACUhUAIAAKAkBEoAAACUhEAJAACAkhAoAQAAUBICJQAAAEpCoAQAAEBJCJQAAAAoCYESAAAAJSFQAgAAoCQESgAAAJSEQAkAAICSECgBAABQEgIlAAAASvL/A6zzCeWd0jKkAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def draw_graph_with_colormap(G, file_name):\n", + " pos = nx.get_node_attributes(G, 'pos')\n", + " edges, weights = zip(*nx.get_edge_attributes(G, 'weight').items())\n", + "\n", + " nx.draw(G, pos, node_color='lightgrey', with_labels=True, node_size=1000, edge_color=weights, width=4.0, edge_cmap=plt.cm.Blues)\n", + " edge_labels = {(u, v): d['weight'] for u, v, d in G.edges(data=True)}\n", + " nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, rotate=False)\n", + "\n", + " plt.savefig(file_name)\n", + " plt.show()\n", + "\n", + "draw_graph_with_colormap(G, 'graph4.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def draw_graph_with_custom_labels(G, file_name):\n", + " pos = nx.get_node_attributes(G, 'pos')\n", + "\n", + " nx.draw(G, pos, node_color='lightgrey', with_labels=True, node_size=1000)\n", + " nx.draw_networkx_edges(G, pos, edgelist=G.edges(), arrows=True)\n", + "\n", + " custom_labels = [\n", + " (0, 120, '8'),\n", + " (2.4, 50, '10'),\n", + " (-2.4, 50, '3'),\n", + " (-0.35, 35, '5'),\n", + " (1.35, 0, '4'),\n", + " (-1.35, 2, '1'),\n", + " (0.45, -55, '0')\n", + " ]\n", + " \n", + " for x, y, label in custom_labels:\n", + " plt.text(x, y, s=label, color='red', size=15, horizontalalignment='center')\n", + "\n", + " edge_labels = {(u, v): d['weight'] for u, v, d in G.edges(data=True)}\n", + " nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, rotate=False)\n", + "\n", + "G = create_base_graph()\n", + "\n", + "draw_graph_with_custom_labels(G, 'graph5.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/lectures/_static/lecture_specific/short_path/graph.png b/lectures/_static/lecture_specific/short_path/graph.png index d5c31af9e..2b451a462 100644 Binary files a/lectures/_static/lecture_specific/short_path/graph.png and b/lectures/_static/lecture_specific/short_path/graph.png differ diff --git a/lectures/_static/lecture_specific/short_path/graph2.png b/lectures/_static/lecture_specific/short_path/graph2.png index c287eac5d..7bc5a5d90 100644 Binary files a/lectures/_static/lecture_specific/short_path/graph2.png and b/lectures/_static/lecture_specific/short_path/graph2.png differ diff --git a/lectures/_static/lecture_specific/short_path/graph3.png b/lectures/_static/lecture_specific/short_path/graph3.png index 35af75ef5..13b2463bc 100644 Binary files a/lectures/_static/lecture_specific/short_path/graph3.png and b/lectures/_static/lecture_specific/short_path/graph3.png differ diff --git a/lectures/_static/lecture_specific/short_path/graph4.png b/lectures/_static/lecture_specific/short_path/graph4.png index abc9e84e5..b817225ac 100644 Binary files a/lectures/_static/lecture_specific/short_path/graph4.png and b/lectures/_static/lecture_specific/short_path/graph4.png differ diff --git a/lectures/_static/quant-econ.bib b/lectures/_static/quant-econ.bib index 409748aae..61f867e24 100644 --- a/lectures/_static/quant-econ.bib +++ b/lectures/_static/quant-econ.bib @@ -3,6 +3,56 @@ Note: Extended Information (like abstracts, doi, url's etc.) can be found in quant-econ-extendedinfo.bib file in _static/ ### + +@book{russell2004history, + title={History of western philosophy}, + author={Russell, Bertrand}, + year={2004}, + publisher={Routledge} +} + +@article{north1989, + title={Constitutions and commitment: the evolution of institutions governing public choice in seventeenth-century England}, + author={North, Douglass C and Weingast, Barry R}, + journal={The journal of economic history}, + volume={49}, + number={4}, + pages={803--832}, + year={1989}, + publisher={Cambridge University Press} +} + +@incollection{keynes1940pay, + title={How to Pay for the War}, + author={Keynes, John Maynard}, + booktitle={Essays in persuasion}, + pages={367--439}, + year={1940}, + publisher={Springer} +} + +@article{bryant1984price, + title={A price discrimination analysis of monetary policy}, + author={Bryant, John and Wallace, Neil}, + journal={The Review of Economic Studies}, + volume={51}, + number={2}, + pages={279--288}, + year={1984}, + publisher={Wiley-Blackwell} +} + + +@article{levitt2019did, + title={Why did ancient states collapse?: the dysfunctional state}, + author={Levitt, Malcolm}, + journal={Why Did Ancient States Collapse?}, + pages={1--56}, + year={2019}, + publisher={Archaeopress} +} + + @book{Burns_2023, title={Milton Friedman: The Last Conservative by Jennifer Burns}, author={Burns, Jennifer}, diff --git a/lectures/_toc.yml b/lectures/_toc.yml index 91ae341f6..cc420c3e1 100644 --- a/lectures/_toc.yml +++ b/lectures/_toc.yml @@ -11,6 +11,7 @@ parts: - file: long_run_growth - file: business_cycle - file: inflation_history + - file: french_rev - file: inequality - caption: Foundations numbered: true @@ -24,6 +25,7 @@ parts: chapters: - file: pv - file: cons_smooth + - file: tax_smooth - file: equalizing_difference - file: cagan_ree - file: cagan_adaptive @@ -31,6 +33,7 @@ parts: numbered: true chapters: - file: eigen_I + - file: greek_square - caption: Probability and Distributions numbered: true chapters: @@ -42,8 +45,8 @@ parts: - caption: Nonlinear Dynamics numbered: true chapters: - - file: solow - file: scalar_dynam + - file: solow - file: cobweb - file: olg - file: commod_price @@ -54,8 +57,6 @@ parts: - file: unpleasant - file: money_inflation_nonlinear - file: laffer_adaptive - #- file: french_rev - #- file: ak2 - caption: Stochastic Dynamics numbered: true chapters: diff --git a/lectures/about.md b/lectures/about.md index 0b419cc51..ac8c6f391 100644 --- a/lectures/about.md +++ b/lectures/about.md @@ -61,10 +61,15 @@ In particular, we sincerely thank and give credit to - [Aakash Gupta](https://github.com/AakashGfude) - [Shu Hu](https://github.com/shlff) - Jiacheng Li +- [Jiarui Zhang](https://github.com/Jiarui-ZH) - [Smit Lunagariya](https://github.com/Smit-create) -- [Matthew McKay](https://github.com/mmcky) - [Maanasee Sharma](https://github.com/maanasee) +- [Matthew McKay](https://github.com/mmcky) +- [Margaret Beisenbek](https://github.com/mbek0605) +- [Phoebe Grosser](https://github.com/pgrosser1) +- [Longye Tian](https://github.com/longye-tian) - [Humphrey Yang](https://github.com/HumphreyYang) +- [Sylvia Zhao](https://github.com/SylviaZhaooo) We also thank Noritaka Kudoh for encouraging us to start this project and providing thoughtful suggestions. diff --git a/lectures/ak2.md b/lectures/ak2.md deleted file mode 100644 index 6f530a5cf..000000000 --- a/lectures/ak2.md +++ /dev/null @@ -1,1172 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst - format_version: 0.13 - jupytext_version: 1.14.1 -kernelspec: - display_name: Python 3 (ipykernel) - language: python - name: python3 ---- - -# Transitions in an Overlapping Generations Model - - - -## Overview - - -This lecture presents a life-cycle model consisting of overlapping generations of two-period lived people proposed by -{cite}`diamond1965national`. - -We'll present the version that was analyzed in chapter 2 of {cite}`auerbach1987dynamic`. - -Auerbach and Kotlikoff (1987) used their two period model as a warm-up for their analysis of overlapping generation models of long-lived people that is the main topic of their book. - -Their model of two-period lived overlapping generations is a useful starting point because - -* it sets forth the structure of interactions between generations of different agents who are alive at a given date -* it activates forces and tradeoffs confronting the government and successive generations of people -* it is good laboratory for studying connections between government tax and subsidy programs and for policies for issuing and servicing government debt -* it is a good setting for introducing describing the **shooting method** for solving a system of non-linear difference equations with boundary conditions that take the form of initial and terminal conditions -* interesting experiments involving transitions from one steady state to another can be computed by hand - ```{note} -Auerbach and Kotlikoff use computer code to calculate transition paths for their models with long-lived people. -``` - -We take the liberty of extending Auerbach and Kotlikoff's chapter 2 model by adding ways to redistribute resources across generations - - * these take the form of a sequence of age-specific lump sum taxes and transfers - -We study how these additional instruments for redistributing resources across generations affect capital accumulation and government debt - - - - - - -## Setting - -Time is discrete and is indexed by $t=0, 1, 2, \ldots$. - -The economy lives forever, but the people inside it do not. - -At each time $ t \geq 0$ a representative old person and a representative young person are alive. - -Thus, at time $t$ a representative old person coexists with a representative young person who will become an old person at time $t+1$. - -We assume that the population size is constant over time. - -A young person works, saves, and consumes. - -An old person dissaves and consumes but does not work, - -There is a government that lives forever, i.e., at $t=0, 1, 2, \ldots $. - -Each period $t \geq 0$, the government taxes, spends, transfers, and borrows. - - - - -Initial conditions set from outside the model at time $t=0$ are - -* $K_0$ -- initial capital stock brought into time $t=0$ by a representative initial old person -* $D_0$ government debt falling due at $t=0$ and owned by a representative old person at time $t=0$ - -$K_0$ and $D_0$ are both measured in units of time $0$ goods. - -A government **policy** consists of five sequences $\{G_t, D_t, \tau_t, \delta_{ot}, \delta_{yt}\}_{t=0}^\infty $ whose components are - - * $\tau_t$ -- flat rate tax at time $t$ on wages and earnings from capital and government bonds - * $D_t$ -- one-period government bond principal due at time $t$, per capita - * $G_t$ -- government purchases of goods at time $t$ (`thrown into ocean'), per capita - * $\delta_{yt}$ -- a lump sum tax on each young person at time $t$ - * $\delta_{ot}$ -- a lump sum tax on each old person at time $t$ - - - -An **allocation** is a collection of sequences $\{C_{yt}, C_{ot}, K_{t+1}, L_t, Y_t, G_t\}_{t=0}^\infty $; constituents of the sequences include - - * $K_t$ -- physical capital per capita - * $L_t$ -- labor per capita - * $Y_t$ -- output per capita - -and also - -* $C_{yt}$ -- consumption of young person at time $t \geq 0$ -* $C_{ot}$ -- consumption of old person at time $t \geq 0$ -* $K_{t+1} - K_t \equiv I_t $ -- investment in physical capital at time $t \geq 0$ -* $G_t$ -- government purchases - -National income and product accounts consist of a sequence of equalities - -* $Y_t = C_{yt} + C_{ot} + (K_{t+1} - K_t) + G_t, \quad t \geq 0$ - -A **price system** is a pair of sequences $\{W_t, r_t\}_{t=0}^\infty$; constituents of the sequence include rental rates for the factors of production - -* $W_t$ -- rental rate for labor at time $t \geq 0$ -* $r_t$ -- rental rate for capital at time $t \geq 0$ - - -## Production - -There are two factors of production, physical capital $K_t$ and labor $L_t$. - -Capital does not depreciate. - -The initial capital stock $K_0$ is owned by the initial old person, who rents it to the firm at time $0$. - -The economy's net investment rate $I_t$ at time $t$ is - -$$ -I_t = K_{t+1} - K_t -$$ - -The economy's capital stock at time $t$ emerges from cumulating past rates of investment: - -$$ -K_t = K_0 + \sum_{s=0}^{t-1} I_s -$$ - -There is a Cobb-Douglas technology that converts physical capital $K_t$ and labor services $L_t$ into -output $Y_t$ - -$$ -Y_t = K_t^\alpha L_t^{1-\alpha}, \quad \alpha \in (0,1) -$$ (eq:prodfn) - - -## Government - -At time $t-1$, the government issues one-period risk-free debt that promises to pay $D_t$ time $t$ goods per capita at time $t$. - -Young people at time $t$ purchase government debt $D_{t+1}$ that matures at time $t+1$. - -Government debt issued at $t$ bears a before-tax net rate of interest rate of $r_{t}$ at time $t+1$. - -The government budget constraint at time $t \geq 0$ is - -$$ -D_{t+1} - D_t = r_t D_t + G_t - T_t -$$ - -or - - - - -$$ -D_{t+1} = (1 + r_t) D_t + G_t - T_t . -$$ (eq:govbudgetsequence) - -Here total tax collections net of transfers are given by $T_t$ satisfying - - -$$ -T_t = \tau_t W_t L_t + \tau_t r_t (D_t + K_t) + \delta_{yt} + \delta_{ot} -$$ - - - - -## Households' Activities in Factor Markets - -**Old people:** At each $t \geq 0$, an old person - - * brings $K_t$ and $D_t$ into the period, - * rents capital to a representative firm for $r_{t} K_t$, - * pays taxes $\tau_t (K_t+ D_t)$ on its rental and interest earnings, - * pays a lump sum tax $\delta_{ot}$ to the government, - * sells $K_t$ to a young person. - - - **Young people:** At each $t \geq 0$, a young person - * sells one unit of labor services to a representative firm for $W_t$ in wages, - * pays taxes $\tau_t W_t$ on its labor earnings - * pays a lump sum tax $\delta_{yt}$ to the goverment, - * spends $C_{yt}$ on consumption, - * acquires non-negative assets $A_{t+1}$ consisting of a sum of physical capital $K_{t+1}$ and one-period government bonds $D_{t+1}$ that mature at $t+1$. - -```{note} -If a lump-sum tax is negative, it means that the government pays the person a subsidy. -``` - - -## Representative firm's problem - -The firm hires labor services from young households at competitive wage rate $W_t$ and hires capital from old households at competitive rental rate -$r_t$. - -The rental rate on capital $r_t$ equals the interest rate on government one-period bonds. - -Units of the rental rates are: - -* for $W_t$, output at time $t$ per unit of labor at time $t$ -* for $r_t$, output at time $t$ per unit of capita at time $t$ - - -We take output at time $t$ as *numeraire*, so the price of output at time $t$ is one. - -The firm's profits at time $t$ are thus - -$$ -K_t^\alpha L_t^{1-\alpha} - r_t K_t - W_t L_t . -$$ - -To maximize profits a firm equates marginal products to rental rates: - -$$ -\begin{aligned} -W_t & = (1-\alpha) K_t^\alpha L_t^{-\alpha} \\ -r_t & = \alpha K_t^\alpha L_t^{1-\alpha} -\end{aligned} -$$ (eq:firmfonc) - -Output can either be consumed by old or young households, sold to young households who use it to augment the capital stock, or sold to the government for uses that do not generate utility for the people in the model (e.g., ``thrown into the ocean''). - - -The firm thus sells output to old households, young households, and the government. - - - - - - - - - -## Households' problems - -### Initial old household - -At time $t=0$, a representative initial old household is endowed with $(1 + r_0(1 - \tau_0)) A_0$ in initial assets. - -It must pay a lump sum tax to (if positive) or receive a subsidy from (if negative) -$\delta_{ot}$ the government. - -An old household's budget constraint is - - - -$$ -C_{o0} = (1 + r_0 (1 - \tau_0)) A_0 - \delta_{ot} . -$$ (eq:hbudgetold) - -An initial old household's utility function is $C_{o0}$, so the household's optimal consumption plan -is provided by equation {eq}`eq:hbudgetold`. - -### Young household - -At each $t \geq 0$, a young household inelastically supplies one unit of labor and in return -receives pre-tax labor earnings of $W_t$ units of output. - -A young-household's post-tax-and-transfer earnings are $W_t (1 - \tau_t) - \delta_{yt}$. - -At each $t \geq 0$, a young household chooses a consumption plan $C_{yt}, C_{ot+1}$ -to maximize the Cobb-Douglas utility function - -$$ -U_t = C_{yt}^\beta C_{o,t+1}^{1-\beta}, \quad \beta \in (0,1) -$$ (eq:utilfn) - -subject to the following budget constraints at times $t$ and $t+1$: - -$$ -\begin{aligned} -C_{yt} + A_{t+1} & = W_t (1 - \tau_t) - \delta_{yt} \\ -C_{ot+1} & = (1+ r_{t+1} (1 - \tau_{t+1}))A_{t+1} - \delta_{ot} -\end{aligned} -$$ (eq:twobudgetc) - - -Solving the second equation of {eq}`eq:twobudgetc` for savings $A_{t+1}$ and substituting it into the first equation implies the present value budget constraint - -$$ -C_{yt} + \frac{C_{ot+1}}{1 + r_{t+1}(1 - \tau_{t+1})} = W_t (1 - \tau_t) - \delta_{yt} - \frac{\delta_{ot}}{1 + r_{t+1}(1 - \tau_{t+1})} -$$ (eq:onebudgetc) - -To solve the young household's choice problem, form a Lagrangian - -$$ -\begin{aligned} -{\mathcal L} & = C_{yt}^\beta C_{o,t+1}^{1-\beta} \\ & + \lambda \Bigl[ C_{yt} + \frac{C_{ot+1}}{1 + r_{t+1}(1 - \tau_{t+1})} - W_t (1 - \tau_t) + \delta_{yt} + \frac{\delta_{ot}}{1 + r_{t+1}(1 - \tau_{t+1})}\Bigr], -\end{aligned} -$$ (eq:lagC) - -where $\lambda$ is a Lagrange multiplier on the intertemporal budget constraint {eq}`eq:onebudgetc`. - - -After several lines of algebra, the intertemporal budget constraint {eq}`eq:onebudgetc` and the first-order conditions for maximizing ${\mathcal L}$ with respect to $C_{yt}, C_{ot+1}$ -imply that an optimal consumption plan satisfies - -$$ -\begin{aligned} -C_{yt} & = \beta \Bigl[ W_t (1 - \tau_t) - \delta_{yt} - \frac{\delta_{ot}}{1 + r_{t+1}(1 - \tau_{t+1})}\Bigr] \\ -\frac{C_{0t+1}}{1 + r_{t+1}(1-\tau_{t+1}) } & = (1-\beta) \Bigl[ W_t (1 - \tau_t) - \delta_{yt} - \frac{\delta_{ot}}{1 + r_{t+1}(1 - \tau_{t+1})}\Bigr] -\end{aligned} -$$ (eq:optconsplan) - -The first-order condition for minimizing Lagrangian {eq}`eq:lagC` with respect to the Lagrange multipler $\lambda$ recovers the budget constraint {eq}`eq:onebudgetc`, -which, using {eq}`eq:optconsplan` gives the optimal savings plan - -$$ -A_{t+1} = (1-\beta) [ (1- \tau_t) W_t - \delta_{yt}] + \beta \frac{\delta_{ot}}{1 + r_{t+1}(1 - \tau_{t+1})} -$$ (eq:optsavingsplan) - - -(sec-equilibrium)= -## Equilbrium - -**Definition:** An equilibrium is an allocation, a government policy, and a price system with the properties that -* given the price system and the government policy, the allocation solves - * represenative firms' problems for $t \geq 0$ - * households problems for $t \geq 0$ -* given the price system and the allocation, the government budget constraint is satisfies for all $t \geq 0$. - - -## Next steps - - -To begin our analysis of equilibrium outcomes, we'll study the special case of the model with which Auerbach and -Kotlikoff (1987) {cite}`auerbach1987dynamic` began their analysis in chapter 2. - -It can be solved by hand. - -We shall do that next. - -After we derive a closed form solution, we'll pretend that we don't know and will compute equilibrium outcome paths. - -We'll do that by first formulating an equilibrium as a fixed point of a mapping from sequences of factor prices and tax rates to sequences of factor prices and tax rates. - -We'll compute an equilibrium by iterating to convergence on that mapping. - - -## Closed form solution - -To get the special chapter 2 case of Auerbach and Kotlikoff (1987) {cite}`auerbach1987dynamic`, we set both $\delta_{ot}$ and $\delta_{yt}$ to zero. - -As our special case of {eq}`eq:optconsplan`, we compute the following consumption-savings plan for a representative young person: - - -$$ -\begin{aligned} -C_{yt} & = \beta (1 - \tau_t) W_t \\ -A_{t+1} &= (1-\beta) (1- \tau_t) W_t -\end{aligned} -$$ - -Using {eq}`eq:firmfonc` and $A_t = K_t + D_t$, we obtain the following closed form transition law for capital: - -$$ -K_{t+1}=K_{t}^{\alpha}\left(1-\tau_{t}\right)\left(1-\alpha\right)\left(1-\beta\right) - D_{t}\\ -$$ (eq:Klawclosed) - -### Steady states - -From {eq}`eq:Klawclosed` and the government budget constraint {eq}`eq:govbudgetsequence`, we compute **time-invariant** or **steady state values** $\hat K, \hat D, \hat T$: - -$$ -\begin{aligned} -\hat{K} &=\hat{K}\left(1-\hat{\tau}\right)\left(1-\alpha\right)\left(1-\beta\right) - \hat{D} \\ -\hat{D} &= (1 + \hat{r}) \hat{D} + \hat{G} - \hat{T} \\ -\hat{T} &= \hat{\tau} \hat{Y} + \hat{\tau} \hat{r} \hat{D} . -\end{aligned} -$$ (eq:steadystates) - -These imply - -$$ -\begin{aligned} -\hat{K} &= \left[\left(1-\hat{\tau}\right)\left(1-\alpha\right)\left(1-\beta\right)\right]^{\frac{1}{1-\alpha}} \\ -\hat{\tau} &= \frac{\hat{G} + \hat{r} \hat{D}}{\hat{Y} + \hat{r} \hat{D}} -\end{aligned} -$$ - -Let's take an example in which - -1. there is no initial government debt, $D_t=0$, -2. government consumption $G_t$ equals $15\%$ of output $Y_t$ - -Our formulas for steady-state values tell us that - -$$ -\begin{aligned} -\hat{D} &= 0 \\ -\hat{G} &= 0.15 \hat{Y} \\ -\hat{\tau} &= 0.15 \\ -\end{aligned} -$$ - - - -## Code - - -In addition to what’s in Anaconda, this lecture will need the following libraries: - -```{code-cell} ipython3 -!pip install --upgrade quantecon -``` - -```{code-cell} ipython3 -import numpy as np -import matplotlib.pyplot as plt -from numba import jit, prange -from quantecon.optimize import brent_max -``` - - -For parameters $\alpha = 0.3$ and $\beta = 0.5$, let's compute $\hat{K}$: - -```{code-cell} ipython3 -# parameters -α = 0.3 -β = 0.5 - -# steady state ̂τ -τ_hat = 0.15 -D_hat = 0. - -# solve for steady state -K_hat = ((1 - τ_hat) * (1 - α) * (1 - β)) ** (1 / (1 - α)) -K_hat -``` -Knowing $\hat K$, we can calculate other equilibrium objects. - -Let's first define some Python helper functions. - -```{code-cell} ipython3 -@jit -def K_to_Y(K, α): - return K ** α - -@jit -def K_to_r(K, α): - return α * K ** (α - 1) - -@jit -def K_to_W(K, α): - return (1 - α) * K ** α - -@jit -def K_to_C(K, D, τ, r, α, β): - - # consumption for old - A = K + D - Co = A * (1 + r * (1 - τ)) - - # consumption for young - W = K_to_W(K, α) - Cy = β * W * (1 - τ) - - return Cy, Co -``` - -We can use these helper functions to obtain steady state values $\hat{Y}$, $\hat{r}$, and $\hat{W}$ associated with steady state values $\hat{K}$ and $\hat{r}$. - -```{code-cell} ipython3 -Y_hat, r_hat, W_hat = K_to_Y(K_hat, α), K_to_r(K_hat, α), K_to_W(K_hat, α) -Y_hat, r_hat, W_hat -``` - -Since steady state government debt $\hat{D}$ is $0$, all taxes are used to pay for government expenditures - -```{code-cell} ipython3 -G_hat = τ_hat * Y_hat -G_hat -``` - -We use the optimal consumption plans to find steady state consumption for young and old are given by the - -```{code-cell} ipython3 -Cy_hat, Co_hat = K_to_C(K_hat, D_hat, τ_hat, r_hat, α, β) -Cy_hat, Co_hat -``` - -Let's store the steady state quantities and prices using an array called `init_ss` - -```{code-cell} ipython3 -init_ss = np.array([K_hat, Y_hat, Cy_hat, Co_hat, # quantities - W_hat, r_hat, # prices - τ_hat, D_hat, G_hat # policies - ]) -``` - - -### Transitions - -%Zejin: I tried to edit the following part to describe the fiscal policy %experiment and the objects we are interested in computing. - -We have computed a steady state in which the government policy sequences are each constant over time. - - -We'll use this steady state as an initial condition at time $t=0$ for another economy in which government policy sequences are with time-varying sequences. - -To make sense of our calculation, we'll treat $t=0$ as time when a huge unanticipated shock occurs in the form of - - * a time-varying government policy sequences that disrupts an original steady state - * new government policy sequences are eventually time-invariant in the sense that after some date $T >0$, each sequence is constant over time. - * sudden revelation of a new government policy in the form of sequences starting at time $t=0$ - -We assume that everyone, including old people at time $t=0$, know the new government policy sequence and choose accordingly. - - - - -As the capital stock and other economy aggregates adjust to the fiscal policy change over time, the economy will approach a new steady state. - -We can find a transition path from an old steady state to a new steady state by employing a fixed-point algorithm in a space of sequences. - -But in our special case with its closed form solution, we have available a simpler and faster -approach. - -Here we define a Python class `ClosedFormTrans` that computes length $T$ transitional path of the economy in response to a particular fiscal policy change. - -We choose $T$ large enough so that we have gotten very close to a new steady state after $T$ periods. - -The class takes three keyword arguments, `τ_pol`, `D_pol`, and `G_pol`. - -These are sequences of tax rate, government debt level, and government purchases, respectively. - -In each policy experiment below, we will pass two out of three as inputs that fully depict a fiscal policy change. - -We'll then compute the single remaining policy variable from the government budget constraint. - -When simulating the transitional paths, it is useful to distinguish what **state variables** at time $t$ such as $K_t, Y_t, D_t, W_t, r_t$ from **control variables** including $C_{yt}, C_{ot}, \tau_{t}, G_t$. - -```{code-cell} ipython3 -class ClosedFormTrans: - """ - This class simulates length T transitional path of a economy - in response to a fiscal policy change given its initial steady - state. The simulation is based on the closed form solution when - the lump sum taxations are absent. - - """ - - def __init__(self, α, β): - - self.α, self.β = α, β - - def simulate(self, - T, # length of transitional path to simulate - init_ss, # initial steady state - τ_pol=None, # sequence of tax rates - D_pol=None, # sequence of government debt levels - G_pol=None): # sequence of government purchases - - α, β = self.α, self.β - - # unpack the steady state variables - K_hat, Y_hat, Cy_hat, Co_hat = init_ss[:4] - W_hat, r_hat = init_ss[4:6] - τ_hat, D_hat, G_hat = init_ss[6:9] - - # initialize array containers - # K, Y, Cy, Co - quant_seq = np.empty((T+1, 4)) - - # W, r - price_seq = np.empty((T+1, 2)) - - # τ, D, G - policy_seq = np.empty((T+2, 3)) - - # t=0, starting from steady state - K0, Y0 = K_hat, Y_hat - W0, r0 = W_hat, r_hat - D0 = D_hat - - # fiscal policy - if τ_pol is None: - D1 = D_pol[1] - G0 = G_pol[0] - τ0 = (G0 + (1 + r0) * D0 - D1) / (Y0 + r0 * D0) - elif D_pol is None: - τ0 = τ_pol[0] - G0 = G_pol[0] - D1 = (1 + r0) * D0 + G0 - τ0 * (Y0 + r0 * D0) - elif G_pol is None: - D1 = D_pol[1] - τ0 = τ_pol[0] - G0 = τ0 * (Y0 + r0 * D0) + D1 - (1 + r0) * D0 - - # optimal consumption plans - Cy0, Co0 = K_to_C(K0, D0, τ0, r0, α, β) - - # t=0 economy - quant_seq[0, :] = K0, Y0, Cy0, Co0 - price_seq[0, :] = W0, r0 - policy_seq[0, :] = τ0, D0, G0 - policy_seq[1, 1] = D1 - - # starting from t=1 to T - for t in range(1, T+1): - - # transition of K - K_old, τ_old = quant_seq[t-1, 0], policy_seq[t-1, 0] - D = policy_seq[t, 1] - K = K_old ** α * (1 - τ_old) * (1 - α) * (1 - β) - D - - # output, capital return, wage - Y, r, W = K_to_Y(K, α), K_to_r(K, α), K_to_W(K, α) - - # to satisfy the government budget constraint - if τ_pol is None: - D = D_pol[t] - D_next = D_pol[t+1] - G = G_pol[t] - τ = (G + (1 + r) * D - D_next) / (Y + r * D) - elif D_pol is None: - τ = τ_pol[t] - G = G_pol[t] - D = policy_seq[t, 1] - D_next = (1 + r) * D + G - τ * (Y + r * D) - elif G_pol is None: - D = D_pol[t] - D_next = D_pol[t+1] - τ = τ_pol[t] - G = τ * (Y + r * D) + D_next - (1 + r) * D - - # optimal consumption plans - Cy, Co = K_to_C(K, D, τ, r, α, β) - - # store time t economy aggregates - quant_seq[t, :] = K, Y, Cy, Co - price_seq[t, :] = W, r - policy_seq[t, 0] = τ - policy_seq[t+1, 1] = D_next - policy_seq[t, 2] = G - - self.quant_seq = quant_seq - self.price_seq = price_seq - self.policy_seq = policy_seq - - return quant_seq, price_seq, policy_seq - - def plot(self): - - quant_seq = self.quant_seq - price_seq = self.price_seq - policy_seq = self.policy_seq - - fig, axs = plt.subplots(3, 3, figsize=(14, 10)) - - # quantities - for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): - ax = axs[i//3, i%3] - ax.plot(range(T+1), quant_seq[:T+1, i], label=name) - ax.hlines(init_ss[i], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') - - # prices - for i, name in enumerate(['W', 'r']): - ax = axs[(i+4)//3, (i+4)%3] - ax.plot(range(T+1), price_seq[:T+1, i], label=name) - ax.hlines(init_ss[i+4], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') - - # policies - for i, name in enumerate(['τ', 'D', 'G']): - ax = axs[(i+6)//3, (i+6)%3] - ax.plot(range(T+1), policy_seq[:T+1, i], label=name) - ax.hlines(init_ss[i+6], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') -``` - -We can create an instance `closed` given model parameters $\{\alpha, \beta\}$ and use it for various fiscal policy experiments. - - -```{code-cell} ipython3 -closed = ClosedFormTrans(α, β) -``` - -(exp-tax-cut)= -### Experiment 1: Tax cut - -To illustrate the power of `ClosedFormTrans`, let's first experiment with the following fiscal policy change: - -1. at $t=0$, the government unexpectedly announces a one-period tax cut, $\tau_0 =(1-\frac{1}{3}) \hat{\tau}$, by issuing government debt $\bar{D}$ -2. from $t=1$, the government will keep $D_t=\bar{D}$ and adjust $\tau_{t}$ to collect taxation to pay for the government consumption and interest payments on the debt -3. government consumption $G_t$ will be fixed at $0.15 \hat{Y}$ - -The following equations completely characterize the equilibrium transition path originating from the initial steady state - -$$ -\begin{aligned} -K_{t+1} &= K_{t}^{\alpha}\left(1-\tau_{t}\right)\left(1-\alpha\right)\left(1-\beta\right) - \bar{D} \\ -\tau_{0} &= (1-\frac{1}{3}) \hat{\tau} \\ -\bar{D} &= \hat{G} - \tau_0\hat{Y} \\ -\quad\tau_{t} & =\frac{\hat{G}+r_{t} \bar{D}}{\hat{Y}+r_{t} \bar{D}} -\end{aligned} -$$ - -We can simulate the transition of the economy for $20$ periods, after which the economy will be fairly close to the new steady state. - -The first step is to prepare sequences of policy variables that describe the fiscal policy change. - - In this example, we need to define sequences of government expenditure $\{G_t\}_{t=0}^{T}$ and debt level $\{D_t\}_{t=0}^{T+1}$ in advance, then pass them to the solver. - -```{code-cell} ipython3 -T = 20 - -# tax cut -τ0 = τ_hat * (1 - 1/3) - -# sequence of government purchase -G_seq = τ_hat * Y_hat * np.ones(T+1) - -# sequence of government debt -D_bar = G_hat - τ0 * Y_hat -D_seq = np.ones(T+2) * D_bar -D_seq[0] = D_hat -``` - -Let's use the `simulate` method of `closed` to obtain the dynamic transitions. - -Note that we leave `τ_pol` as `None`, since the tax rates need to be determined to satisfy the government budget constraint. - -```{code-cell} ipython3 -quant_seq1, price_seq1, policy_seq1 = closed.simulate(T, init_ss, - D_pol=D_seq, - G_pol=G_seq) -closed.plot() -``` - -We can also easily experiment with a lower tax cut rate, such as $0.2$, and compare - -```{code-cell} ipython3 -# lower tax cut rate -τ0 = 0.15 * (1 - 0.2) - -# the corresponding debt sequence -D_bar = G_hat - τ0 * Y_hat -D_seq = np.ones(T+2) * D_bar -D_seq[0] = D_hat - -quant_seq2, price_seq2, policy_seq2 = closed.simulate(T, init_ss, - D_pol=D_seq, - G_pol=G_seq) -``` - -```{code-cell} ipython3 -fig, axs = plt.subplots(3, 3, figsize=(14, 10)) - -# quantities -for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): - ax = axs[i//3, i%3] - ax.plot(range(T+1), quant_seq1[:T+1, i], label=name+', 1/3') - ax.plot(range(T+1), quant_seq2[:T+1, i], label=name+', 0.2') - ax.hlines(init_ss[i], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') - -# prices -for i, name in enumerate(['W', 'r']): - ax = axs[(i+4)//3, (i+4)%3] - ax.plot(range(T+1), price_seq1[:T+1, i], label=name+', 1/3') - ax.plot(range(T+1), price_seq2[:T+1, i], label=name+', 0.2') - ax.hlines(init_ss[i+4], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') - -# policies -for i, name in enumerate(['τ', 'D', 'G']): - ax = axs[(i+6)//3, (i+6)%3] - ax.plot(range(T+1), policy_seq1[:T+1, i], label=name+', 1/3') - ax.plot(range(T+1), policy_seq2[:T+1, i], label=name+', 0.2') - ax.hlines(init_ss[i+6], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') -``` - -### Experiment 2: Government asset accumulation - -Assuming that the economy was in the same steady state, but instead of announcing a tax cut at $t=0$, the government now promises to cut its spending on services and goods by a half $\forall t \leq 0$. - -The government wants to target the same tax rate $\tau_t=\hat{\tau}$ and accumulate assets $-D_t$ over time. - -Note that in this experiment, we pass `τ_seq` and `G_seq` as inputs, and let `D_pol` be determined along the path by satisfying the government budget constraint. - -```{code-cell} ipython3 -# government expenditure cut by a half -G_seq = τ_hat * 0.5 * Y_hat * np.ones(T+1) - -# targeted tax rate -τ_seq = τ_hat * np.ones(T+1) - -closed.simulate(T, init_ss, τ_pol=τ_seq, G_pol=G_seq); -closed.plot() -``` - -It will be useful for understanding the transition paths by looking at the ratio of government asset to the output, $-\frac{D_t}{Y_t}$ - -```{code-cell} ipython3 -plt.plot(range(T+1), -closed.policy_seq[:-1, 1] / closed.quant_seq[:, 0]) -plt.xlabel('t') -plt.title('-D/Y'); -``` - -### Experiment 3: Temporary expenditure cut - -Let's now consider the case where the government also cuts its spending by half and accumulates asset. - -But this time the expenditure cut only lasts for one period at $t=0$. - -From $t \geq 1$, the government will return to the original level of consumption $\hat{G}$, and will adjust $\tau_t$ to maintain the same level of asset $-D_t = -D_1$. - -```{code-cell} ipython3 -# sequence of government purchase -G_seq = τ_hat * Y_hat * np.ones(T+1) -G_seq[0] = 0 - -# sequence of government debt -D_bar = G_seq[0] - τ_hat * Y_hat -D_seq = D_bar * np.ones(T+2) -D_seq[0] = D_hat - -closed.simulate(T, init_ss, D_pol=D_seq, G_pol=G_seq); -closed.plot() -``` - - - -## A computational strategy - -In the above illustrations, we studied dynamic transitions associated with various fiscal policy experiments. - -In these experiments, we maintained the assumption that lump sum taxes are absent ($\delta_{yt}=0, \delta_{ot}=0$). - -In this section, we investigate the transition dynamics when the lump sum taxes are present. - -The government will use lump sum taxes and transfers to redistribute resources across successive -generations. - -Including lump sum taxes will break down the closed form solution because now optimal consumption and saving plans will depend on future prices and tax rates. - -Therefore, we use a more general way of solving for equilibriunm transitional paths that involves computing them as a fixed point in a mapping from sequences to sequences. - -We elaborate on the equilibrium conditions as we define in section {ref}`sec-equilibrium`, which characterize the fixed point - -**Definition:** Given model parameters $\{\alpha$, $\beta\}$, a competitive equilibrium consists of - -* sequences of optimal consumptions $\{C_{yt}, C_{ot}\}$ -* sequences of prices $\{W_t, r_t\}$ -* sequences of capital stock and output $\{K_t, Y_t\}$ -* sequences of tax rates, government assets (debt), government purchases $\{\tau_t, D_t, G_t\, \delta_{yt}, \delta_{ot}\}$ - -with the properties that - -* given the price system and government fiscal policy, the household consumption plans are optimal -* the government budget constraints are satisfied for all $t$ - -An equilibrium transition path can be computed by "guessing and verifying" - -In our {ref}`exp-tax-cut` example, sequences $\{D_t\}_{t=0}^{T}$ and $\{G_t\}_{t=0}^{T}$ are exogenous. - -In addition, we assume that the lump sum taxes $\{\delta_{yt}, \delta_{ot}\}_{t=0}^{T}$ are given and known to the households. - -We can solve for sequences of other equilibrium objects following the steps below - -1. guesses prices $\{W_t, r_t\}_{t=0}^{T}$ and tax rates $\{\tau_t\}_{t=0}^{T}$ -2. solve for optimal consumption and saving plans $\{C_{yt}, C_{ot}\}_{t=0}^{T}$, treating the guesses of future prices and taxes as true -3. solve for transitional dynamics of the capital stock $\{K_t\}_{t=0}^{T}$ -4. update the guesses for prices and tax rates with the values implied by the equilibrium conditions -5. iterate until convergence - -Below we implement the "guess and verify" computation. - -We start by defining the Cobb-Douglas utility function - -```{code-cell} ipython3 -@jit -def U(Cy, Co, β): - - return (Cy ** β) * (Co ** (1-β)) -``` - -We use `Cy_val` to compute the lifetime value of choosing an arbitrary consumption plan, $C_y$, given the intertemporal budget constraint. - -Note that it requires knowing future prices $r_{t+1}$ and tax rate $\tau_{t+1}$. - -```{code-cell} ipython3 -@jit -def Cy_val(Cy, W, r_next, τ, τ_next, δy, δo_next, β): - - # Co given by the budget constraint - Co = (W * (1 - τ) - δy - Cy) * (1 + r_next * (1 - τ_next)) - δo_next - - return U(Cy, Co, β) -``` - -The optimal consumption plan $C_y^*$ can be found by maximizing `Cy_val`. - -Here is an example of finding the optimal consumption $C_y^*=\hat{C}_y$ in the steady state as we discussed before, with $\delta_{yt}=\delta_{ot}=0$ - -```{code-cell} ipython3 -W, r_next, τ, τ_next = W_hat, r_hat, τ_hat, τ_hat -δy, δo_next = 0, 0 - -Cy_opt, U_opt, _ = brent_max(Cy_val, # maximand - 1e-6, # lower bound - W*(1-τ)-δy-1e-6, # upper bound - args=(W, r_next, τ, τ_next, δy, δo_next, β)) - -Cy_opt, U_opt -``` - -Below we define a Python class `AK2` that solves for the transitional paths of the economy using the fixed-point algorithm. It can handle any fiscal policy experiment including nonzero lump sum taxations - -```{code-cell} ipython3 -class AK2(): - """ - This class simulates length T transitional path of a economy - in response to a fiscal policy change given its initial steady - state. The transitional path is found by employing a fixed point - algorithm that and uses equilibrium conditions. - - """ - - def __init__(self, α, β): - - self.α, self.β = α, β - - def simulate(self, - T, # length of transitional path to simulate - init_ss, # initial steady state - δy_seq, # sequence of lump sum tax for the young - δo_seq, # sequence of lump sum tax for the old - τ_pol=None, # sequence of tax rates - D_pol=None, # sequence of government debt levels - G_pol=None, # sequence of government purchases - verbose=False, - max_iter=500, - tol=1e-5): - - α, β = self.α, self.β - - # unpack the steady state variables - K_hat, Y_hat, Cy_hat, Co_hat = init_ss[:4] - W_hat, r_hat = init_ss[4:6] - τ_hat, D_hat, G_hat = init_ss[6:9] - - # K, Y, Cy, Co - quant_seq = np.empty((T+2, 4)) - - # W, r - price_seq = np.empty((T+2, 2)) - - # τ, D, G - policy_seq = np.empty((T+2, 3)) - policy_seq[:, 1] = D_pol - policy_seq[:, 2] = G_pol - - # initial guesses of prices - price_seq[:, 0] = np.ones(T+2) * W_hat - price_seq[:, 1] = np.ones(T+2) * r_hat - - # initial guesses of policies - policy_seq[:, 0] = np.ones(T+2) * τ_hat - - # t=0, starting from steady state - quant_seq[0, :2] = K_hat, Y_hat - - if verbose: - # prepare to plot iterations until convergence - fig, axs = plt.subplots(1, 3, figsize=(14, 4)) - - # containers for checking convergence - price_seq_old = np.empty_like(price_seq) - policy_seq_old = np.empty_like(policy_seq) - - # start iteration - i_iter = 0 - while True: - - if verbose: - # plot current prices at ith iteration - for i, name in enumerate(['W', 'r']): - axs[i].plot(range(T+1), price_seq[:T+1, i]) - axs[i].set_title(name) - axs[i].set_xlabel('t') - axs[2].plot(range(T+1), policy_seq[:T+1, 0]) - axs[2].set_title('τ') - axs[2].set_xlabel('t') - - # store old prices from last iteration - price_seq_old[:] = price_seq - policy_seq_old[:] = policy_seq - - # start updating quantities and prices - for t in range(T+1): - K, Y = quant_seq[t, :2] - W, r = price_seq[t, :] - r_next = price_seq[t+1, 1] - τ, D, G = policy_seq[t, :] - τ_next, D_next, G_next = policy_seq[t+1, :] - δy, δo = δy_seq[t], δo_seq[t] - δy_next, δo_next = δy_seq[t+1], δo_seq[t+1] - - # consumption for the old - Co = (1 + r * (1 - τ)) * (K + D) - δo - - # optimal consumption for the young - out = brent_max(Cy_val, 1e-6, W*(1-τ)-δy-1e-6, - args=(W, r_next, τ, τ_next, - δy, δo_next, β)) - Cy = out[0] - - quant_seq[t, 2:] = Cy, Co - τ_num = ((1 + r) * D + G - D_next - δy - δo) - τ_denom = (Y + r * D) - policy_seq[t, 0] = τ_num / τ_denom - - # saving of the young - A_next = W * (1 - τ) - δy - Cy - - # transition of K - K_next = A_next - D_next - Y_next = K_to_Y(K_next, α) - W_next, r_next = K_to_W(K_next, α), K_to_r(K_next, α) - - quant_seq[t+1, :2] = K_next, Y_next - price_seq[t+1, :] = W_next, r_next - - i_iter += 1 - - if (np.max(np.abs(price_seq_old - price_seq)) < tol) & \ - (np.max(np.abs(policy_seq_old - policy_seq)) < tol): - if verbose: - print(f"Converge using {i_iter} iterations") - break - - if i_iter > max_iter: - if verbose: - print(f"Fail to converge using {i_iter} iterations") - break - - self.quant_seq = quant_seq - self.price_seq = price_seq - self.policy_seq = policy_seq - - return quant_seq, price_seq, policy_seq - - def plot(self): - - quant_seq = self.quant_seq - price_seq = self.price_seq - policy_seq = self.policy_seq - - fig, axs = plt.subplots(3, 3, figsize=(14, 10)) - - # quantities - for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): - ax = axs[i//3, i%3] - ax.plot(range(T+1), quant_seq[:T+1, i], label=name) - ax.hlines(init_ss[i], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') - - # prices - for i, name in enumerate(['W', 'r']): - ax = axs[(i+4)//3, (i+4)%3] - ax.plot(range(T+1), price_seq[:T+1, i], label=name) - ax.hlines(init_ss[i+4], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') - - # policies - for i, name in enumerate(['τ', 'D', 'G']): - ax = axs[(i+6)//3, (i+6)%3] - ax.plot(range(T+1), policy_seq[:T+1, i], label=name) - ax.hlines(init_ss[i+6], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') -``` - -We can initialize an instance of class `AK2` with model parameters $\{\alpha, \beta\}$ and then use it for various fiscal policy experiments. - -```{code-cell} ipython3 -ak2 = AK2(α, β) -``` - -We first examine that the "guess and verify" method leads to the same numerical results as we obtain with the closed form solution when lump sum taxes are muted - -```{code-cell} ipython3 -δy_seq = np.ones(T+2) * 0. -δo_seq = np.ones(T+2) * 0. - -D_pol = np.zeros(T+2) -G_pol = np.ones(T+2) * G_hat - -# tax cut -τ0 = τ_hat * (1 - 1/3) -D1 = D_hat * (1 + r_hat * (1 - τ0)) + G_hat - τ0 * Y_hat - δy_seq[0] - δo_seq[0] -D_pol[0] = D_hat -D_pol[1:] = D1 -``` - -```{code-cell} ipython3 -quant_seq3, price_seq3, policy_seq3 = ak2.simulate(T, init_ss, - δy_seq, δo_seq, - D_pol=D_pol, G_pol=G_pol, - verbose=True) -``` - -```{code-cell} ipython3 -ak2.plot() -``` - -Next, we can now try to turn on the lump sum taxes with the more general laboratory at hand. - -For example, let's try the same fiscal policy experiment in {ref}`exp-tax-cut`, but slightly modify it and assume that the government will in addition increase the lump sum taxes for both the young and old households $\delta_{yt}=\delta_{ot}=0.01, t\geq0$. - -```{code-cell} ipython3 -δy_seq = np.ones(T+2) * 0.01 -δo_seq = np.ones(T+2) * 0.01 - -D1 = D_hat * (1 + r_hat * (1 - τ0)) + G_hat - τ0 * Y_hat - δy_seq[0] - δo_seq[0] -D_pol[1:] = D1 - -quant_seq4, price_seq4, policy_seq4 = ak2.simulate(T, init_ss, - δy_seq, δo_seq, - D_pol=D_pol, G_pol=G_pol) -``` - -As a result, we see that the "crowding out" effect is mitigated. - -```{code-cell} ipython3 -fig, axs = plt.subplots(3, 3, figsize=(14, 10)) - -# quantities -for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): - ax = axs[i//3, i%3] - ax.plot(range(T+1), quant_seq3[:T+1, i], label=name+', $\delta$s=0') - ax.plot(range(T+1), quant_seq4[:T+1, i], label=name+', $\delta$s=0.01') - ax.hlines(init_ss[i], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') - -# prices -for i, name in enumerate(['W', 'r']): - ax = axs[(i+4)//3, (i+4)%3] - ax.plot(range(T+1), price_seq3[:T+1, i], label=name+', $\delta$s=0') - ax.plot(range(T+1), price_seq4[:T+1, i], label=name+', $\delta$s=0.01') - ax.hlines(init_ss[i+4], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') - -# policies -for i, name in enumerate(['τ', 'D', 'G']): - ax = axs[(i+6)//3, (i+6)%3] - ax.plot(range(T+1), policy_seq3[:T+1, i], label=name+', $\delta$s=0') - ax.plot(range(T+1), policy_seq4[:T+1, i], label=name+', $\delta$s=0.01') - ax.hlines(init_ss[i+6], 0, T+1, color='r', linestyle='--') - ax.legend() - ax.set_xlabel('t') -``` diff --git a/lectures/ar1_processes.md b/lectures/ar1_processes.md index c4884a7aa..34b93ae7c 100644 --- a/lectures/ar1_processes.md +++ b/lectures/ar1_processes.md @@ -19,13 +19,7 @@ kernelspec: ``` (ar1_processes)= -# AR1 Processes - -```{admonition} Migrated lecture -:class: warning - -This lecture has moved from our [Intermediate Quantitative Economics with Python](https://python.quantecon.org/intro.html) lecture series and is now a part of [A First Course in Quantitative Economics](https://intro.quantecon.org/intro.html). -``` +# AR(1) Processes ```{index} single: Autoregressive processes ``` @@ -41,21 +35,18 @@ These simple models are used again and again in economic research to represent t * dividends * productivity, etc. -AR(1) processes can take negative values but are easily converted into positive processes when necessary by a transformation such as exponentiation. - We are going to study AR(1) processes partly because they are useful and -partly because they help us understand important concepts. +partly because they help us understand important concepts. Let's start with some imports: ```{code-cell} ipython import numpy as np -%matplotlib inline import matplotlib.pyplot as plt plt.rcParams["figure.figsize"] = (11, 5) #set default figure size ``` -## The AR(1) Model +## The AR(1) model The **AR(1) model** (autoregressive model of order 1) takes the form @@ -65,26 +56,45 @@ The **AR(1) model** (autoregressive model of order 1) takes the form X_{t+1} = a X_t + b + c W_{t+1} ``` -where $a, b, c$ are scalar-valued parameters. +where $a, b, c$ are scalar-valued parameters -This law of motion generates a time series $\{ X_t\}$ as soon as we -specify an initial condition $X_0$. +(Equation {eq}`can_ar1` is sometimes called a **stochastic difference equation**.) -This is called the **state process** and the state space is $\mathbb R$. +```{prf:example} +:label: ar1_ex_ar + +For example, $X_t$ might be + +* the log of labor income for a given household, or +* the log of money demand in a given economy. + +In either case, {eq}`can_ar1` shows that the current value evolves as a linear function +of the previous value and an IID shock $W_{t+1}$. + +(We use $t+1$ for the subscript of $W_{t+1}$ because this random variable is not +observed at time $t$.) +``` + +The specification {eq}`can_ar1` generates a time series $\{ X_t\}$ as soon as we +specify an initial condition $X_0$. To make things even simpler, we will assume that -* the process $\{ W_t \}$ is IID and standard normal, +* the process $\{ W_t \}$ is {ref}`IID ` and standard normal, * the initial condition $X_0$ is drawn from the normal distribution $N(\mu_0, v_0)$ and * the initial condition $X_0$ is independent of $\{ W_t \}$. -### Moving Average Representation + + + +### Moving average representation Iterating backwards from time $t$, we obtain $$ X_t = a X_{t-1} + b + c W_t = a^2 X_{t-2} + a b + a c W_{t-1} + b + c W_t + = a^3 X_{t-3} + a^2 b + a^2 c W_{t-2} + b + c W_t = \cdots $$ @@ -106,7 +116,7 @@ Equation {eq}`ar1_ma` shows that $X_t$ is a well defined random variable, the va Throughout, the symbol $\psi_t$ will be used to refer to the density of this random variable $X_t$. -### Distribution Dynamics +### Distribution dynamics One of the nice things about this model is that it's so easy to trace out the sequence of distributions $\{ \psi_t \}$ corresponding to the time series $\{ X_t\}$. @@ -117,10 +127,9 @@ This is immediate from {eq}`ar1_ma`, since linear combinations of independent normal random variables are normal. Given that $X_t$ is normally distributed, we will know the full distribution -$\psi_t$ if we can pin down its first two moments. +$\psi_t$ if we can pin down its first two [moments](https://en.wikipedia.org/wiki/Moment_(mathematics)). -Let $\mu_t$ and $v_t$ denote the mean and variance -of $X_t$ respectively. +Let $\mu_t$ and $v_t$ denote the mean and variance of $X_t$ respectively. We can pin down these values from {eq}`ar1_ma` or we can use the following recursive expressions: @@ -147,8 +156,7 @@ $$ \psi_t = N(\mu_t, v_t) $$ -The following code uses these facts to track the sequence of marginal -distributions $\{ \psi_t \}$. +The following code uses these facts to track the sequence of marginal distributions $\{ \psi_t \}$. The parameters are @@ -172,7 +180,7 @@ for t in range(sim_length): mu = a * mu + b v = a**2 * v + c**2 ax.plot(grid, norm.pdf(grid, loc=mu, scale=np.sqrt(v)), - label=f"$\psi_{t}$", + label=fr"$\psi_{t}$", alpha=0.7) ax.legend(bbox_to_anchor=[1.05,1],loc=2,borderaxespad=1) @@ -180,14 +188,26 @@ ax.legend(bbox_to_anchor=[1.05,1],loc=2,borderaxespad=1) plt.show() ``` -## Stationarity and Asymptotic Stability -Notice that, in the figure above, the sequence $\{ \psi_t \}$ seems to be converging to a limiting distribution. + +## Stationarity and asymptotic stability + +When we use models to study the real world, it is generally preferable that our +models have clear, sharp predictions. + +For dynamic problems, sharp predictions are related to stability. + +For example, if a dynamic model predicts that inflation always converges to some +kind of steady state, then the model gives a sharp prediction. + +(The prediction might be wrong, but even this is helpful, because we can judge the quality of the model.) + +Notice that, in the figure above, the sequence $\{ \psi_t \}$ seems to be converging to a limiting distribution, suggesting some kind of stability. This is even clearer if we project forward further into the future: ```{code-cell} python3 -def plot_density_seq(ax, mu_0=-3.0, v_0=0.6, sim_length=60): +def plot_density_seq(ax, mu_0=-3.0, v_0=0.6, sim_length=40): mu, v = mu_0, v_0 for t in range(sim_length): mu = a * mu + b @@ -207,7 +227,7 @@ For example, this alternative density sequence also converges to the same limit. ```{code-cell} python3 fig, ax = plt.subplots() -plot_density_seq(ax, mu_0=3.0) +plot_density_seq(ax, mu_0=4.0) plt.show() ``` @@ -242,12 +262,12 @@ We can confirm this is valid for the sequence above using the following code. ```{code-cell} python3 fig, ax = plt.subplots() -plot_density_seq(ax, mu_0=3.0) +plot_density_seq(ax, mu_0=4.0) mu_star = b / (1 - a) std_star = np.sqrt(c**2 / (1 - a**2)) # square root of v_star psi_star = norm.pdf(grid, loc=mu_star, scale=std_star) -ax.plot(grid, psi_star, 'k-', lw=2, label="$\psi^*$") +ax.plot(grid, psi_star, 'k-', lw=2, label=r"$\psi^*$") ax.legend() plt.show() @@ -255,16 +275,21 @@ plt.show() As claimed, the sequence $\{ \psi_t \}$ converges to $\psi^*$. -### Stationary Distributions +We see that, at least for these parameters, the AR(1) model has strong stability +properties. + + + + +### Stationary distributions + +Let's try to better understand the limiting distribution $\psi^*$. -A stationary distribution is a distribution that is a fixed -point of the update rule for distributions. +A stationary distribution is a distribution that is a "fixed point" of the update rule for the AR(1) process. -In other words, if $\psi_t$ is stationary, then $\psi_{t+j} = -\psi_t$ for all $j$ in $\mathbb N$. +In other words, if $\psi_t$ is stationary, then $\psi_{t+j} = \psi_t$ for all $j$ in $\mathbb N$. -A different way to put this, specialized to the current setting, is as follows: a -density $\psi$ on $\mathbb R$ is **stationary** for the AR(1) process if +A different way to put this, specialized to the current setting, is as follows: a density $\psi$ on $\mathbb R$ is **stationary** for the AR(1) process if $$ X_t \sim \psi @@ -286,8 +311,8 @@ Thus, when $|a| < 1$, the AR(1) model has exactly one stationary density and tha The concept of ergodicity is used in different ways by different authors. -One way to understand it in the present setting is that a version of the Law -of Large Numbers is valid for $\{X_t\}$, even though it is not IID. +One way to understand it in the present setting is that a version of the law +of large numbers is valid for $\{X_t\}$, even though it is not IID. In particular, averages over time series converge to expectations under the stationary distribution. @@ -309,7 +334,10 @@ Notes: * In {eq}`ar1_ergo`, convergence holds with probability one. * The textbook by {cite}`MeynTweedie2009` is a classic reference on ergodicity. -For example, if we consider the identity function $h(x) = x$, we get +```{prf:example} +:label: ar1_ex_id + +If we consider the identity function $h(x) = x$, we get $$ \frac{1}{m} \sum_{t = 1}^m X_t \to @@ -317,11 +345,21 @@ $$ \quad \text{as } m \to \infty $$ -In other words, the time series sample mean converges to the mean of the -stationary distribution. +In other words, the time series sample mean converges to the mean of the stationary distribution. +``` + +Ergodicity is important for a range of reasons. + +For example, {eq}`ar1_ergo` can be used to test theory. + +In this equation, we can use observed data to evaluate the left hand side of {eq}`ar1_ergo`. + +And we can use a theoretical AR(1) model to calculate the right hand side. + +If $\frac{1}{m} \sum_{t = 1}^m X_t$ is not close to $\psi^(x)$, even for many +observations, then our theory seems to be incorrect and we will need to revise +it. -As will become clear over the next few lectures, ergodicity is a very -important concept for statistics and simulation. ## Exercises @@ -346,7 +384,7 @@ M_k = \end{cases} $$ -Here $n!!$ is the double factorial. +Here $n!!$ is the [double factorial](https://en.wikipedia.org/wiki/Double_factorial). According to {eq}`ar1_ergo`, we should have, for any $k \in \mathbb N$, diff --git a/lectures/cagan_adaptive.md b/lectures/cagan_adaptive.md index 14fe60cc2..f3d48c34c 100644 --- a/lectures/cagan_adaptive.md +++ b/lectures/cagan_adaptive.md @@ -62,7 +62,7 @@ $$ (eq:caganmd_ad) This equation asserts that the demand for real balances -is inversely related to the public's expected rate of inflation. +is inversely related to the public's expected rate of inflation with sensitivity $\alpha$. Equating the logarithm $m_t^d$ of the demand for money to the logarithm $m_t$ of the supply of money in equation {eq}`eq:caganmd_ad` and solving for the logarithm $p_t$ of the price level gives @@ -79,7 +79,7 @@ $$ $$ (eq:eqpipi) We assume that the expected rate of inflation $\pi_t^*$ is governed -by the following adaptive expectations scheme proposed by {cite}`Friedman1956` and {cite}`Cagan`: +by the following adaptive expectations scheme proposed by {cite}`Friedman1956` and {cite}`Cagan`, where $\lambda\in [0,1]$ denotes the weight on expected inflation. $$ \pi_{t+1}^* = \lambda \pi_t^* + (1 -\lambda) \pi_t diff --git a/lectures/cagan_ree.md b/lectures/cagan_ree.md index d694c57da..f0274b56a 100644 --- a/lectures/cagan_ree.md +++ b/lectures/cagan_ree.md @@ -18,7 +18,7 @@ kernelspec: We'll use linear algebra first to explain and then do some experiments with a "monetarist theory of price levels". -Economists call it a "monetary" or "monetarist" theory of price levels because effects on price levels occur via a central banks's decisions to print money supply. +Economists call it a "monetary" or "monetarist" theory of price levels because effects on price levels occur via a central bank's decisions to print money supply. * a goverment's fiscal policies determine whether its _expenditures_ exceed its _tax collections_ * if its expenditures exceed its tax collections, the government can instruct the central bank to cover the difference by _printing money_ @@ -27,7 +27,7 @@ Economists call it a "monetary" or "monetarist" theory of price levels because e Such a theory of price levels was described by Thomas Sargent and Neil Wallace in chapter 5 of {cite}`sargent2013rational`, which reprints a 1981 Federal Reserve Bank of Minneapolis article entitled "Unpleasant Monetarist Arithmetic". -Sometimes this theory is also called a "fiscal theory of price levels" to emphasize the importance of fisal deficits in shaping changes in the money supply. +Sometimes this theory is also called a "fiscal theory of price levels" to emphasize the importance of fiscal deficits in shaping changes in the money supply. The theory has been extended, criticized, and applied by John Cochrane {cite}`cochrane2023fiscal`. @@ -41,7 +41,7 @@ persistent inflation. The "monetarist" or "fiscal theory of price levels" asserts that -* to _start_ a persistent inflation the government beings persistently to run a money-financed government deficit +* to _start_ a persistent inflation the government begins persistently to run a money-financed government deficit * to _stop_ a persistent inflation the government stops persistently running a money-financed government deficit @@ -94,7 +94,7 @@ m_t^d - p_t = -\alpha \pi_t^* \: , \: \alpha > 0 ; \quad t = 0, 1, \ldots, T . $$ (eq:caganmd) This equation asserts that the demand for real balances -is inversely related to the public's expected rate of inflation. +is inversely related to the public's expected rate of inflation with sensitivity $\alpha$. People somehow acquire **perfect foresight** by their having solved a forecasting problem. @@ -296,7 +296,7 @@ $$ \mu_t = \mu^* , \quad t \geq T_1 $$ -so that, in terms of our notation and formula for $\pi_{T+1}^*$ above, $\tilde \gamma = 1$. +so that, in terms of our notation and formula for $\pi_{T+1}^*$ above, $\gamma^* = 1$. #### Experiment 1: Foreseen sudden stabilization diff --git a/lectures/cobweb.md b/lectures/cobweb.md index 2a1c54edf..3bda73f95 100644 --- a/lectures/cobweb.md +++ b/lectures/cobweb.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.14.1 + jupytext_version: 1.16.2 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -14,7 +14,6 @@ kernelspec: (cobweb)= # The Cobweb Model - The cobweb model is a model of prices and quantities in a given market, and how they evolve over time. ## Overview @@ -24,7 +23,7 @@ because it shows the fundamental importance of *expectations*. To give some idea of how the model operates, and why expectations matter, imagine the following scenario. -There is a market for soy beans, say, where prices and traded quantities +There is a market for soybeans, say, where prices and traded quantities depend on the choices of buyers and sellers. The buyers are represented by a demand curve --- they buy more at low prices @@ -38,11 +37,11 @@ However, the sellers (who are farmers) need time to grow their crops. Suppose now that the price is currently high. Seeing this high price, and perhaps expecting that the high price will remain -for some time, the farmers plant many fields with soy beans. +for some time, the farmers plant many fields with soybeans. Next period the resulting high supply floods the market, causing the price to drop. -Seeing this low price, the farmers now shift out of soy beans, restricting +Seeing this low price, the farmers now shift out of soybeans, restricting supply and causing the price to climb again. You can imagine how these dynamics could cause cycles in prices and quantities @@ -52,13 +51,10 @@ The cobweb model puts these ideas into equations so we can try to quantify them, and to study conditions under which cycles persist (or disappear). In this lecture, we investigate and simulate the basic model under different -assumptions regarding the way that produces form expectations. +assumptions regarding the way that producers form expectations. Our discussion and simulations draw on [high quality lectures](https://comp-econ.org/CEF_2013/downloads/Complex%20Econ%20Systems%20Lecture%20II.pdf) by [Cars Hommes](https://www.uva.nl/en/profile/h/o/c.h.hommes/c.h.hommes.html). - -+++ - We will use the following imports. ```{code-cell} ipython3 @@ -70,7 +66,7 @@ import matplotlib.pyplot as plt Early papers on the cobweb cycle include {cite}`cobweb_model` and {cite}`hog_cycle`. -The paper {cite}`hog_cycle` uses the cobweb theorem to explain the prices of hog in the US over 1920--1950 +The paper {cite}`hog_cycle` uses the cobweb theorem to explain the prices of hog in the US over 1920--1950. The next plot replicates part of Figure 2 from that paper, which plots the price of hogs at yearly frequency. @@ -90,13 +86,11 @@ ax.grid() plt.show() ``` - - ## The model -Let's return to our discussion of a hypothetical soy bean market, where price is determined by supply and demand. +Let's return to our discussion of a hypothetical soybean market, where price is determined by supply and demand. -We suppose that demand for soy beans is given by +We suppose that demand for soybeans is given by $$ D(p_t) = a - b p_t @@ -106,15 +100,15 @@ where $a, b$ are nonnegative constants and $p_t$ is the spot (i.e, current marke ($D(p_t)$ is the quantity demanded in some fixed unit, such as thousands of tons.) -Because the crop of soy beans for time $t$ is planted at $t-1$, supply of soy beans at time $t$ depends on *expected* prices at time $t$, which we denote $p^e_{t-1}$. +Because the crop of soybeans for time $t$ is planted at $t-1$, supply of soybeans at time $t$ depends on *expected* prices at time $t$, which we denote $p^e_t$. We suppose that supply is nonlinear in expected prices, and takes the form $$ - S(p^e_{t-1}) = \tanh(\lambda(p^e_{t-1} - c)) + d + S(p^e_t) = \tanh(\lambda(p^e_t - c)) + d $$ -where $\lambda$ is a positive constant and $c, d \geq 0$. +where $\lambda$ is a positive constant, $c, d$ are nonnegative constants and $\tanh$ is a type of [hyperbolic function](https://en.wikipedia.org/wiki/Hyperbolic_functions). Let's make a plot of supply and demand for particular choices of the parameter values. @@ -149,7 +143,7 @@ m = Market() fig, ax = plt.subplots() ax.plot(p_grid, m.demand(p_grid), label="$D$") -ax.plot(p_grid, m.supply(p_grid), label="S") +ax.plot(p_grid, m.supply(p_grid), label="$S$") ax.set_xlabel("price") ax.set_ylabel("quantity") ax.legend() @@ -160,13 +154,13 @@ plt.show() Market equilibrium requires that supply equals demand, or $$ - a - b p_t = S(p^e_{t-1}) + a - b p_t = S(p^e_t) $$ Rewriting in terms of $p_t$ gives $$ - p_t = - \frac{1}{b} [S(p^e_{t-1}) - a] + p_t = - \frac{1}{b} [S(p^e_t) - a] $$ Finally, to complete the model, we need to describe how price expectations are formed. @@ -177,7 +171,7 @@ In particular, we suppose that ```{math} :label: p_et - p^e_{t-1} = f(p_{t-1}, p_{t-2}) + p^e_t = f(p_{t-1}, p_{t-2}) ``` where $f$ is some function. @@ -195,7 +189,6 @@ Combining the last two equations gives the dynamics for prices: The price dynamics depend on the parameter values and also on the function $f$ that determines how producers form expectations. - ## Naive expectations To go further in our analysis we need to specify the function $f$; that is, how expectations are formed. @@ -204,7 +197,9 @@ Let's start with naive expectations, which refers to the case where producers ex In other words, -$$ p_{t-1}^e = p_{t-1} $$ +$$ +p_t^e = p_{t-1} +$$ Using {eq}`price_t`, we then have @@ -225,7 +220,6 @@ where $g$ is the function defined by g(p) = - \frac{1}{b} [ S(p) - a] ``` - Here we represent the function $g$ ```{code-cell} ipython3 @@ -239,9 +233,9 @@ def g(model, current_price): return next_price ``` -Let's try to understand how prices will evolve using a 45 degree diagram, which is a tool for studying one-dimensional dynamics. +Let's try to understand how prices will evolve using a 45-degree diagram, which is a tool for studying one-dimensional dynamics. -The function `plot45` defined below helps us draw the 45 degree diagram. +The function `plot45` defined below helps us draw the 45-degree diagram. ```{code-cell} ipython3 :tags: [hide-input] @@ -277,7 +271,7 @@ def plot45(model, pmin, pmax, p0, num_arrows=5): ax.plot(pgrid, g(model, pgrid), 'b-', lw=2, alpha=0.6, label='g') - ax.plot(pgrid, pgrid, lw=1, alpha=0.7, label='45') + ax.plot(pgrid, pgrid, lw=1, alpha=0.7, label=r'$45\degree$') x = p0 xticks = [pmin] @@ -304,6 +298,8 @@ def plot45(model, pmin, pmax, p0, num_arrows=5): xticks.append(pmax) xtick_labels.append(pmax) + ax.set_ylabel(r'$p_{t+1}$') + ax.set_xlabel(r'$p_t$') ax.set_xticks(xticks) ax.set_yticks(xticks) ax.set_xticklabels(xtick_labels) @@ -316,7 +312,7 @@ def plot45(model, pmin, pmax, p0, num_arrows=5): plt.show() ``` -Now we can set up a market and plot the 45 degree diagram. +Now we can set up a market and plot the 45-degree diagram. ```{code-cell} ipython3 m = Market() @@ -326,7 +322,7 @@ m = Market() plot45(m, 0, 9, 2, num_arrows=3) ``` -The plot shows the function $g$ defined in {eq}`def_g` and the $45$ degree line. +The plot shows the function $g$ defined in {eq}`def_g` and the 45-degree line. Think of $ p_t $ as a value on the horizontal axis. @@ -334,13 +330,13 @@ Since $p_{t+1} = g(p_t)$, we use the graph of $g$ to see $p_{t+1}$ on the vertic Clearly, -- If $ g $ lies above the 45 degree line at $p_t$, then we have $ p_{t+1} > p_t $. -- If $ g $ lies below the 45 degree line at $p_t$, then we have $ p_{t+1} < p_t $. -- If $ g $ hits the 45 degree line at $p_t$, then we have $ p_{t+1} = p_t $, so $ p_t $ is a steady state. +- If $ g $ lies above the 45-degree line at $p_t$, then we have $ p_{t+1} > p_t $. +- If $ g $ lies below the 45-degree line at $p_t$, then we have $ p_{t+1} < p_t $. +- If $ g $ hits the 45-degree line at $p_t$, then we have $ p_{t+1} = p_t $, so $ p_t $ is a steady state. Consider the sequence of prices starting at $p_0$, as shown in the figure. -We find $p_1$ on the vertical axis and then shift it to the horizontal axis using the 45 degree line (where values on the two axes are equal). +We find $p_1$ on the vertical axis and then shift it to the horizontal axis using the 45-degree line (where values on the two axes are equal). Then from $p_1$ we obtain $p_2$ and continue. @@ -408,7 +404,7 @@ That is, ```{math} :label: pe_adaptive -p_{t-1}^e = \alpha p_{t-1} + (1-\alpha) p^e_{t-2} +p_t^e = \alpha p_{t-1} + (1-\alpha) p^e_{t-1} \qquad (0 \leq \alpha \leq 1) ``` @@ -416,7 +412,7 @@ Another way to write this is ```{math} :label: pe_adaptive_2 -p_{t-1}^e = p^e_{t-2} + \alpha (p_{t-1} - p_{t-2}^e) +p_t^e = p^e_{t-1} + \alpha (p_{t-1} - p_{t-1}^e) ``` This equation helps to show that expectations shift @@ -427,10 +423,9 @@ This equation helps to show that expectations shift Using {eq}`pe_adaptive`, we obtain the dynamics $$ - p_t = - \frac{1}{b} [ S(\alpha p_{t-1} + (1-\alpha) p^e_{t-2}) - a] + p_t = - \frac{1}{b} [ S(\alpha p_{t-1} + (1-\alpha) p^e_{t-1}) - a] $$ - Let's try to simulate the price and observe the dynamics using different values of $\alpha$. ```{code-cell} ipython3 @@ -464,8 +459,6 @@ def ts_price_plot_adaptive(model, p0, ts_length=10, α=[1.0, 0.9, 0.75]): Let's call the function with prices starting at $p_0 = 5$. -TODO does this fit well in the page, even in the pdf? If not should it be stacked vertically? - ```{code-cell} ipython3 ts_price_plot_adaptive(m, 5, ts_length=30) ``` @@ -477,9 +470,6 @@ expectations, which stabilizes expected prices. This increased stability can be seen in the figures. - -TODO check / fix exercises - ## Exercises ```{exercise-start} @@ -547,7 +537,7 @@ That is, ```{math} :label: pe_blae -p_{t-1}^e = \alpha p_{t-1} + (1-\alpha) p_{t-2} +p_t^e = \alpha p_{t-1} + (1-\alpha) p_{t-2} ``` @@ -605,9 +595,4 @@ ts_plot_price_blae(m, ``` ```{solution-end} -``` - -```{code-cell} ipython3 - -``` - +``` \ No newline at end of file diff --git a/lectures/commod_price.md b/lectures/commod_price.md index be5d5f337..93654d186 100644 --- a/lectures/commod_price.md +++ b/lectures/commod_price.md @@ -32,8 +32,7 @@ We will solve an equation where the price function is the unknown. This is harder than solving an equation for an unknown number, or vector. -The lecture will discuss one way to solve a "functional equation" for an unknown -function +The lecture will discuss one way to solve a [functional equation](https://en.wikipedia.org/wiki/Functional_equation) (an equation where the unknown object is a function). For this lecture we need the `yfinance` library. @@ -61,7 +60,7 @@ The figure below shows the price of cotton in USD since the start of 2016. ```{code-cell} ipython3 :tags: [hide-input, hide-output] -s = yf.download('CT=F', '2016-1-1', '2023-4-1')['Adj Close'] +s = yf.download('CT=F', '2016-1-1', '2023-4-1')['Close'] ``` ```{code-cell} ipython3 @@ -70,7 +69,7 @@ s = yf.download('CT=F', '2016-1-1', '2023-4-1')['Adj Close'] fig, ax = plt.subplots() ax.plot(s, marker='o', alpha=0.5, ms=1) -ax.set_ylabel('price', fontsize=12) +ax.set_ylabel('cotton price in USD', fontsize=12) ax.set_xlabel('date', fontsize=12) plt.show() @@ -134,13 +133,12 @@ $p_t$. The harvest of the commodity at time $t$ is $Z_t$. -We assume that the sequence $\{ Z_t \}_{t \geq 1}$ is IID with common -density function $\phi$. +We assume that the sequence $\{ Z_t \}_{t \geq 1}$ is IID with common density function $\phi$, where $\phi$ is nonnegative. Speculators can store the commodity between periods, with $I_t$ units purchased in the current period yielding $\alpha I_t$ units in the next. -Here $\alpha \in (0,1)$ is a depreciation rate for the commodity. +Here the parameter $\alpha \in (0,1)$ is a depreciation rate for the commodity. For simplicity, the risk free interest rate is taken to be zero, so expected profit on purchasing $I_t$ units is @@ -175,6 +173,7 @@ $$ \alpha \mathbb{E}_t \, p_{t+1} - p_t \leq 0 $$ (eq:arbi) +This means that if the expected price is lower than the current price, there is no room for arbitrage. Profit maximization gives the additional condition @@ -183,7 +182,7 @@ $$ $$ (eq:pmco) -We also require that the market clears in each period. +We also require that the market clears, with supply equaling demand in each period. We assume that consumers generate demand quantity $D(p)$ corresponding to price $p$. @@ -193,12 +192,12 @@ Let $P := D^{-1}$ be the inverse demand function. Regarding quantities, -* supply is the sum of carryover by speculators and the current harvest +* supply is the sum of carryover by speculators and the current harvest, and * demand is the sum of purchases by consumers and purchases by speculators. Mathematically, -* supply $ = X_t = \alpha I_{t-1} + Z_t$, which takes values in $S := \mathbb R_+$, while +* supply is given by $X_t = \alpha I_{t-1} + Z_t$, which takes values in $S := \mathbb R_+$, while * demand $ = D(p_t) + I_t$ Thus, the market equilibrium condition is @@ -220,6 +219,8 @@ How can we find an equilibrium? Our path of attack will be to seek a system of prices that depend only on the current state. +(Our solution method involves using an [ansatz](https://en.wikipedia.org/wiki/Ansatz), which is an educated guess --- in this case for the price function.) + In other words, we take a function $p$ on $S$ and set $p_t = p(X_t)$ for every $t$. Prices and quantities then follow @@ -235,8 +236,6 @@ conditions above. More precisely, we seek a $p$ such that [](eq:arbi) and [](eq:pmco) hold for the corresponding system [](eq:eosy). -To this end, suppose that there exists a function $p^*$ on $S$ -satisfying $$ p^*(x) = \max @@ -285,7 +284,7 @@ But then $D(p^*(X_t)) = X_t$ and $I_t = I(X_t) = 0$. As a consequence, both [](eq:arbi) and [](eq:pmco) hold. -We have found an equilibrium. +We have found an equilibrium, which verifies the ansatz. ### Computing the equilibrium @@ -347,7 +346,7 @@ The code below implements this iterative process, starting from $p_0 = P$. The distribution $\phi$ is set to a shifted Beta distribution (although many other choices are possible). -The integral in [](eq:dopf3) is computed via Monte Carlo. +The integral in [](eq:dopf3) is computed via {ref}`Monte Carlo `. ```{code-cell} ipython3 @@ -395,7 +394,8 @@ while error > tol: ax.plot(grid, price, 'k-', alpha=0.5, lw=2, label=r'$p^*$') ax.legend() -ax.set_xlabel('$x$', fontsize=12) +ax.set_xlabel('$x$') +ax.set_ylabel("prices") plt.show() ``` diff --git a/lectures/complex_and_trig.md b/lectures/complex_and_trig.md index fd12ec347..7f40497c0 100644 --- a/lectures/complex_and_trig.md +++ b/lectures/complex_and_trig.md @@ -23,12 +23,6 @@ kernelspec: # Complex Numbers and Trigonometry -```{admonition} Migrated lecture -:class: warning - -This lecture has moved from our [Intermediate Quantitative Economics with Python](https://python.quantecon.org/intro.html) lecture series and is now a part of [A First Course in Quantitative Economics](https://intro.quantecon.org/intro.html). -``` - ## Overview This lecture introduces some elementary mathematics and trigonometry. @@ -109,12 +103,16 @@ from sympy import (Symbol, symbols, Eq, nsolve, sqrt, cos, sin, simplify, ### An Example +```{prf:example} +:label: ct_ex_com + Consider the complex number $z = 1 + \sqrt{3} i$. For $z = 1 + \sqrt{3} i$, $x = 1$, $y = \sqrt{3}$. It follows that $r = 2$ and $\theta = \tan^{-1}(\sqrt{3}) = \frac{\pi}{3} = 60^o$. +``` Let's use Python to plot the trigonometric form of the complex number $z = 1 + \sqrt{3} i$. diff --git a/lectures/cons_smooth.md b/lectures/cons_smooth.md index b2bace94f..626f59565 100644 --- a/lectures/cons_smooth.md +++ b/lectures/cons_smooth.md @@ -4,14 +4,13 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 --- - # Consumption Smoothing ## Overview @@ -19,14 +18,16 @@ kernelspec: In this lecture, we'll study a famous model of the "consumption function" that Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`) proposed to fit some empirical data patterns that the original Keynesian consumption function described in this QuantEcon lecture {doc}`geometric series ` missed. -In this lecture, we'll study what is often called the "consumption-smoothing model" using matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. +We'll study what is often called the "consumption-smoothing model." + +We'll use matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. -Formulas presented in {doc}`present value formulas` are at the core of the consumption smoothing model because we shall use them to define a consumer's "human wealth". +Formulas presented in {doc}`present value formulas` are at the core of the consumption-smoothing model because we shall use them to define a consumer's "human wealth". The key idea that inspired Milton Friedman was that a person's non-financial income, i.e., his or -her wages from working, could be viewed as a dividend stream from that person's ''human capital'' -and that standard asset-pricing formulas could be applied to compute a person's -''non-financial wealth'' that capitalizes the earnings stream. +her wages from working, can be viewed as a dividend stream from ''human capital'' +and that standard asset-pricing formulas can be applied to compute +''non-financial wealth'' that capitalizes that earnings stream. ```{note} As we'll see in this QuantEcon lecture {doc}`equalizing difference model `, @@ -34,12 +35,12 @@ Milton Friedman had used this idea in his PhD thesis at Columbia University, eventually published as {cite}`kuznets1939incomes` and {cite}`friedman1954incomes`. ``` -It will take a while for a "present value" or asset price explicilty to appear in this lecture, but when it does it will be a key actor. +It will take a while for a "present value" or asset price explicitly to appear in this lecture, but when it does it will be a key actor. ## Analysis -As usual, we'll start with by importing some Python modules. +As usual, we'll start by importing some Python modules. ```{code-cell} ipython3 import numpy as np @@ -47,16 +48,15 @@ import matplotlib.pyplot as plt from collections import namedtuple ``` - The model describes a consumer who lives from time $t=0, 1, \ldots, T$, receives a stream $\{y_t\}_{t=0}^T$ of non-financial income and chooses a consumption stream $\{c_t\}_{t=0}^T$. -We usually think of the non-financial income stream as coming from the person's salary from supplying labor. +We usually think of the non-financial income stream as coming from the person's earnings from supplying labor. -The model takes a non-financial income stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. +The model takes a non-financial income stream as an input, regarding it as "exogenous" in the sense that it is determined outside the model. -The consumer faces a gross interest rate of $R >1$ that is constant over time, at which she is free to borrow or lend, up to limits that we'll describe below. +The consumer faces a gross interest rate of $R >1$ that is constant over time, at which she is free to borrow or lend, up to limits that we'll describe below. -To set up the model, let +Let * $T \geq 2$ be a positive integer that constitutes a time-horizon. * $y = \{y_t\}_{t=0}^T$ be an exogenous sequence of non-negative non-financial incomes $y_t$. @@ -128,9 +128,12 @@ Indeed, we shall see that when $\beta R = 1$ (a condition assumed by Milton Frie By **smoother** we mean as close as possible to being constant over time. -The preference for smooth consumption paths that is built into the model gives it the name "consumption smoothing model". +The preference for smooth consumption paths that is built into the model gives it the name "consumption-smoothing model". -Let's dive in and do some calculations that will help us understand how the model works. +We'll postpone verifying our claim that a constant consumption path is optimal when $\beta R=1$ +by comparing welfare levels that comes from a constant path with ones that involve non-constant paths. + +Before doing that, let's dive in and do some calculations that will help us understand how the model works in practice when we provide the consumer with some different streams on non-financial income. Here we use default parameters $R = 1.05$, $g_1 = 1$, $g_2 = 1/2$, and $T = 65$. @@ -147,7 +150,6 @@ def create_consumption_smoothing_model(R=1.05, g1=1, g2=1/2, T=65): β_seq, T) ``` - ## Friedman-Hall consumption-smoothing model A key object is what Milton Friedman called "human" or "non-financial" wealth at time $0$: @@ -176,7 +178,7 @@ $$ \sum_{t=0}^T R^{-t} c_t = a_0 + h_0. $$ (eq:budget_intertemp) -Equation {eq}`eq:budget_intertemp` says that the present value of the consumption stream equals the sum of finanical and non-financial (or human) wealth. +Equation {eq}`eq:budget_intertemp` says that the present value of the consumption stream equals the sum of financial and non-financial (or human) wealth. Robert Hall {cite}`Hall1978` showed that when $\beta R = 1$, a condition Milton Friedman had also assumed, it is "optimal" for a consumer to smooth consumption by setting @@ -196,7 +198,7 @@ $$ (eq:conssmoothing) Equation {eq}`eq:conssmoothing` is the consumption-smoothing model in a nutshell. -## Mechanics of Consumption smoothing model +## Mechanics of consumption-smoothing model As promised, we'll provide step-by-step instructions on how to use linear algebra, readily implemented in Python, to compute all objects in play in the consumption-smoothing model. @@ -285,7 +287,7 @@ def compute_optimal(model, a0, y_seq): We use an example where the consumer inherits $a_0<0$. -This can be interpreted as a student debt. +This can be interpreted as student debt with which the consumer begins his or her working life. The non-financial process $\{y_t\}_{t=0}^{T}$ is constant and positive up to $t=45$ and then becomes zero afterward. @@ -308,17 +310,22 @@ print('check a_T+1=0:', The graphs below show paths of non-financial income, consumption, and financial assets. ```{code-cell} ipython3 -# Sequence Length +# Sequence length T = cs_model.T -plt.plot(range(T+1), y_seq, label='non-financial income') -plt.plot(range(T+1), c_seq, label='consumption') -plt.plot(range(T+2), a_seq, label='financial wealth') -plt.plot(range(T+2), np.zeros(T+2), '--') +fig, axes = plt.subplots(1, 2, figsize=(12,5)) + +axes[0].plot(range(T+1), y_seq, label='non-financial income', lw=2) +axes[0].plot(range(T+1), c_seq, label='consumption', lw=2) +axes[1].plot(range(T+2), a_seq, label='financial wealth', color='green', lw=2) +axes[0].set_ylabel(r'$c_t,y_t$') +axes[1].set_ylabel(r'$a_t$') + +for ax in axes: + ax.plot(range(T+2), np.zeros(T+2), '--', lw=1, color='black') + ax.legend() + ax.set_xlabel(r'$t$') -plt.legend() -plt.xlabel(r'$t$') -plt.ylabel(r'$c_t,y_t,a_t$') plt.show() ``` @@ -338,14 +345,14 @@ print('Welfare:', welfare(cs_model, c_seq)) ### Experiments -In this section we decribe how a consumption sequence would optimally respond to different sequences sequences of non-financial income. +In this section we describe how a consumption sequence would optimally respond to different sequences sequences of non-financial income. -First we create a function `plot_cs` that generate graphs for different instances of the consumption smoothing model `cs_model`. +First we create a function `plot_cs` that generates graphs for different instances of the consumption-smoothing model `cs_model`. This will help us avoid rewriting code to plot outcomes for different non-financial income sequences. ```{code-cell} ipython3 -def plot_cs(model, # consumption smoothing model +def plot_cs(model, # consumption-smoothing model a0, # initial financial wealth y_seq # non-financial income process ): @@ -356,19 +363,23 @@ def plot_cs(model, # consumption smoothing model # Sequence length T = cs_model.T - # Generate plot - plt.plot(range(T+1), y_seq, label='non-financial income') - plt.plot(range(T+1), c_seq, label='consumption') - plt.plot(range(T+2), a_seq, label='financial wealth') - plt.plot(range(T+2), np.zeros(T+2), '--') + fig, axes = plt.subplots(1, 2, figsize=(12,5)) + + axes[0].plot(range(T+1), y_seq, label='non-financial income', lw=2) + axes[0].plot(range(T+1), c_seq, label='consumption', lw=2) + axes[1].plot(range(T+2), a_seq, label='financial wealth', color='green', lw=2) + axes[0].set_ylabel(r'$c_t,y_t$') + axes[1].set_ylabel(r'$a_t$') + + for ax in axes: + ax.plot(range(T+2), np.zeros(T+2), '--', lw=1, color='black') + ax.legend() + ax.set_xlabel(r'$t$') - plt.legend() - plt.xlabel(r'$t$') - plt.ylabel(r'$c_t,y_t,a_t$') plt.show() ``` -In the experiments below, please study how consumption and financial asset sequences vary accross different sequences for non-financial income. +In the experiments below, please study how consumption and financial asset sequences vary across different sequences for non-financial income. #### Experiment 1: one-time gain/loss @@ -419,7 +430,7 @@ Now we simulate a $y$ sequence in which a person gets zero for 46 years, and the ```{code-cell} ipython3 # Late starter y_seq_late = np.concatenate( - [np.zeros(46), np.ones(20)]) + [np.ones(46), 2*np.ones(20)]) plot_cs(cs_model, a0, y_seq_late) ``` @@ -461,18 +472,16 @@ What happens when $\lambda$ is negative ```{code-cell} ipython3 λ = -0.95 -geo_seq = λ ** np.arange(t_max) * y_0 +geo_seq = λ ** np.arange(t_max) * y_0 + 1 y_seq_geo = np.concatenate( - [geo_seq, np.zeros(20)]) + [geo_seq, np.ones(20)]) plot_cs(cs_model, a0, y_seq_geo) ``` - ### Feasible consumption variations -We promised to justify our claim that a constant consumption play $c_t = c_0$ for all -$t$ is optimal. +We promised to justify our claim that when $\beta R =1$ as Friedman assumed, a constant consumption play $c_t = c_0$ for all $t$ is optimal. Let's do that now. @@ -554,7 +563,6 @@ def compute_variation(model, ξ1, ϕ, a0, y_seq, verbose=1): return cvar_seq ``` - We visualize variations for $\xi_1 \in \{.01, .05\}$ and $\phi \in \{.95, 1.02\}$ ```{code-cell} ipython3 @@ -591,10 +599,9 @@ plt.ylabel(r'$c_t$') plt.show() ``` - We can even use the Python `np.gradient` command to compute derivatives of welfare with respect to our two parameters. -We are teaching the key idea beneath the **calculus of variations**. +(We are actually discovering the key idea beneath the **calculus of variations**.) First, we define the welfare with respect to $\xi_1$ and $\phi$ @@ -602,7 +609,7 @@ First, we define the welfare with respect to $\xi_1$ and $\phi$ def welfare_rel(ξ1, ϕ): """ Compute welfare of variation sequence - for given ϕ, ξ1 with a consumption smoothing model + for given ϕ, ξ1 with a consumption-smoothing model """ cvar_seq = compute_variation(cs_model, ξ1=ξ1, @@ -615,7 +622,6 @@ def welfare_rel(ξ1, ϕ): welfare_vec = np.vectorize(welfare_rel) ``` - Then we can visualize the relationship between welfare and $\xi_1$ and compute its derivatives ```{code-cell} ipython3 @@ -634,7 +640,6 @@ plt.xlabel(r'$\xi_1$') plt.show() ``` - The same can be done on $\phi$ ```{code-cell} ipython3 @@ -655,19 +660,17 @@ plt.show() ## Wrapping up the consumption-smoothing model -The consumption-smoothing model of Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`) is a cornerstone of modern macro that has important ramifications for the size of the Keynesian "fiscal policy multiplier" described briefly in +The consumption-smoothing model of Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`) is a cornerstone of modern economics that has important ramifications for the size of the Keynesian "fiscal policy multiplier" that we described in QuantEcon lecture {doc}`geometric series `. -In particular, it **lowers** the government expenditure multiplier relative to one implied by -the original Keynesian consumption function presented in {doc}`geometric series `. +The consumption-smoothingmodel **lowers** the government expenditure multiplier relative to one implied by the original Keynesian consumption function presented in {doc}`geometric series `. -Friedman's work opened the door to an enlighening literature on the aggregate consumption function and associated government expenditure multipliers that -remains active today. +Friedman's work opened the door to an enlightening literature on the aggregate consumption function and associated government expenditure multipliers that remains active today. ## Appendix: solving difference equations with linear algebra -In the preceding sections we have used linear algebra to solve a consumption smoothing model. +In the preceding sections we have used linear algebra to solve a consumption-smoothing model. The same tools from linear algebra -- matrix multiplication and matrix inversion -- can be used to study many other dynamic models. @@ -749,7 +752,7 @@ is the inverse of $A$ and check that $A A^{-1} = I$ ``` -### Second order difference equation +### Second-order difference equation A second-order linear difference equation for $\{y_t\}_{t=0}^T$ is @@ -783,6 +786,6 @@ Multiplying both sides by inverse of the matrix on the left again provides the ```{exercise} :label: consmooth_ex2 -As an exercise, we ask you to represent and solve a **third order linear difference equation**. +As an exercise, we ask you to represent and solve a **third-order linear difference equation**. How many initial conditions must you specify? ``` diff --git a/lectures/eigen_I.md b/lectures/eigen_I.md index 46dc221f8..9cd683526 100644 --- a/lectures/eigen_I.md +++ b/lectures/eigen_I.md @@ -88,7 +88,8 @@ itself. This means $A$ is an $n \times n$ matrix that maps (or "transforms") a vector $x$ in $\mathbb{R}^n$ to a new vector $y=Ax$ also in $\mathbb{R}^n$. -Here's one example: +```{prf:example} +:label: eigen1_ex_sq $$ \begin{bmatrix} @@ -116,6 +117,7 @@ $$ transforms the vector $x = \begin{bmatrix} 1 \\ 3 \end{bmatrix}$ to the vector $y = \begin{bmatrix} 5 \\ 2 \end{bmatrix}$. +``` Let's visualize this using Python: @@ -263,7 +265,7 @@ def circle_transform(A=np.array([[-1, 2], [0, 1]])): ax[0].plot(x, y, color='black', zorder=1) ax[0].scatter(a_1, b_1, c=colors, alpha=1, s=60, edgecolors='black', zorder=2) - ax[0].set_title("unit circle in $\mathbb{R}^2$") + ax[0].set_title(r"unit circle in $\mathbb{R}^2$") x1 = x.reshape(1, -1) y1 = y.reshape(1, -1) @@ -540,15 +542,15 @@ def grid_composition_transform(A=np.array([[1, -1], [1, 1]]), # Plot grid points ax[0].scatter(xygrid[0], xygrid[1], s=36, c=colors, edgecolor="none") - ax[0].set_title("points $x_1, x_2, \cdots, x_k$") + ax[0].set_title(r"points $x_1, x_2, \cdots, x_k$") # Plot intermediate grid points ax[1].scatter(uvgrid[0], uvgrid[1], s=36, c=colors, edgecolor="none") - ax[1].set_title("points $Bx_1, Bx_2, \cdots, Bx_k$") + ax[1].set_title(r"points $Bx_1, Bx_2, \cdots, Bx_k$") # Plot transformed grid points ax[2].scatter(abgrid[0], abgrid[1], s=36, c=colors, edgecolor="none") - ax[2].set_title("points $ABx_1, ABx_2, \cdots, ABx_k$") + ax[2].set_title(r"points $ABx_1, ABx_2, \cdots, ABx_k$") plt.show() ``` diff --git a/lectures/eigen_II.md b/lectures/eigen_II.md index 52fd505e5..ce1c38b12 100644 --- a/lectures/eigen_II.md +++ b/lectures/eigen_II.md @@ -26,7 +26,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie In this lecture we will begin with the foundational concepts in spectral theory. -Then we will explore the Perron-Frobenius Theorem and connect it to applications in Markov chains and networks. +Then we will explore the Perron-Frobenius theorem and connect it to applications in Markov chains and networks. We will use the following imports: @@ -64,6 +64,9 @@ An $n \times n$ nonnegative matrix $A$ is called irreducible if $A + A^2 + A^3 + In other words, for each $i,j$ with $1 \leq i, j \leq n$, there exists a $k \geq 0$ such that $a^{k}_{ij} > 0$. +```{prf:example} +:label: eigen2_ex_irr + Here are some examples to illustrate this further: $$ @@ -94,6 +97,7 @@ $$ $C$ is not irreducible since $C^k = C$ for all $k \geq 0$ and thus $c^{k}_{12},c^{k}_{21} = 0$ for all $k \geq 0$. +``` ### Left eigenvectors @@ -159,7 +163,7 @@ This is a more common expression and where the name left eigenvectors originates For a square nonnegative matrix $A$, the behavior of $A^k$ as $k \to \infty$ is controlled by the eigenvalue with the largest absolute value, often called the **dominant eigenvalue**. -For any such matrix $A$, the Perron-Frobenius Theorem characterizes certain +For any such matrix $A$, the Perron-Frobenius theorem characterizes certain properties of the dominant eigenvalue and its corresponding eigenvector. ```{prf:Theorem} Perron-Frobenius Theorem @@ -188,7 +192,7 @@ Let's build our intuition for the theorem using a simple example we have seen [b Now let's consider examples for each case. -#### Example: Irreducible matrix +#### Example: irreducible matrix Consider the following irreducible matrix $A$: @@ -204,7 +208,7 @@ We can compute the dominant eigenvalue and the corresponding eigenvector eig(A) ``` -Now we can see the claims of the Perron-Frobenius Theorem holds for the irreducible matrix $A$: +Now we can see the claims of the Perron-Frobenius theorem holds for the irreducible matrix $A$: 1. The dominant eigenvalue is real-valued and non-negative. 2. All other eigenvalues have absolute values less than or equal to the dominant eigenvalue. @@ -223,6 +227,9 @@ Let $A$ be a square nonnegative matrix and let $A^k$ be the $k^{th}$ power of $A A matrix is called **primitive** if there exists a $k \in \mathbb{N}$ such that $A^k$ is everywhere positive. +```{prf:example} +:label: eigen2_ex_prim + Recall the examples given in irreducible matrices: $$ @@ -231,7 +238,7 @@ A = \begin{bmatrix} 0.5 & 0.1 \\ \end{bmatrix} $$ -$A$ here is also a primitive matrix since $A^k$ is everywhere nonnegative for $k \in \mathbb{N}$. +$A$ here is also a primitive matrix since $A^k$ is everywhere positive for some $k \in \mathbb{N}$. $$ B = \begin{bmatrix} 0 & 1 \\ @@ -244,10 +251,11 @@ B^2 = \begin{bmatrix} 1 & 0 \\ $$ $B$ is irreducible but not primitive since there are always zeros in either principal diagonal or secondary diagonal. +``` We can see that if a matrix is primitive, then it implies the matrix is irreducible but not vice versa. -Now let's step back to the primitive matrices part of the Perron-Frobenius Theorem +Now let's step back to the primitive matrices part of the Perron-Frobenius theorem ```{prf:Theorem} Continous of Perron-Frobenius Theorem :label: con-perron-frobenius @@ -259,7 +267,7 @@ If $A$ is primitive then, $ r(A)^{-m} A^m$ converges to $v w^{\top}$ when $m \rightarrow \infty$. The matrix $v w^{\top}$ is called the **Perron projection** of $A$. ``` -#### Example 1: Primitive matrix +#### Example 1: primitive matrix Consider the following primitive matrix $B$: @@ -277,7 +285,7 @@ We compute the dominant eigenvalue and the corresponding eigenvector eig(B) ``` -Now let's give some examples to see if the claims of the Perron-Frobenius Theorem hold for the primitive matrix $B$: +Now let's give some examples to see if the claims of the Perron-Frobenius theorem hold for the primitive matrix $B$: 1. The dominant eigenvalue is real-valued and non-negative. 2. All other eigenvalues have absolute values strictly less than the dominant eigenvalue. @@ -373,18 +381,18 @@ check_convergence(B) The result shows that the matrix is not primitive as it is not everywhere positive. -These examples show how the Perron-Frobenius Theorem relates to the eigenvalues and eigenvectors of positive matrices and the convergence of the power of matrices. +These examples show how the Perron-Frobenius theorem relates to the eigenvalues and eigenvectors of positive matrices and the convergence of the power of matrices. In fact we have already seen the theorem in action before in {ref}`the Markov chain lecture `. (spec_markov)= -#### Example 2: Connection to Markov chains +#### Example 2: connection to Markov chains We are now prepared to bridge the languages spoken in the two lectures. A primitive matrix is both irreducible and aperiodic. -So Perron-Frobenius Theorem explains why both {ref}`Imam and Temple matrix ` and [Hamilton matrix](https://en.wikipedia.org/wiki/Hamiltonian_matrix) converge to a stationary distribution, which is the Perron projection of the two matrices +So Perron-Frobenius theorem explains why both {ref}`Imam and Temple matrix ` and {ref}`Hamilton matrix ` converge to a stationary distribution, which is the Perron projection of the two matrices ```{code-cell} ipython3 P = np.array([[0.68, 0.12, 0.20], @@ -449,7 +457,7 @@ As we have seen, the largest eigenvalue for a primitive stochastic matrix is one This can be proven using [Gershgorin Circle Theorem](https://en.wikipedia.org/wiki/Gershgorin_circle_theorem), but it is out of the scope of this lecture. -So by the statement (6) of Perron-Frobenius Theorem, $\lambda_i<1$ for all $i # Inflation During French Revolution ## Overview -This lecture describes some monetary and fiscal features of the French Revolution -described by {cite}`sargent_velde1995`. +This lecture describes some of the monetary and fiscal features of the French Revolution (1789-1799) described by {cite}`sargent_velde1995`. -We use matplotlib to replicate several of the graphs that they used to present salient patterns. +To finance public expenditures and service its debts, +the French government embarked on policy experiments. +The authors of these experiments had in mind theories about how government monetary and fiscal policies affected economic outcomes. +Some of those theories about monetary and fiscal policies still interest us today. -## Fiscal Situation and Response of National Assembly +* a **tax-smoothing** model like Robert Barro's {cite}`Barro1979` + * this normative (i.e., prescriptive model) advises a government to finance temporary war-time surges in expenditures mostly by issuing government debt, raising taxes by just enough to service the additional debt issued during the wary; then, after the war, to roll over whatever debt the government had accumulated during the war; and to increase taxes after the war permanently by just enough to finance interest payments on that post-war government debt -In response to a motion by Catholic Bishop Talleyrand, -the National Assembly confiscated and nationalized Church lands. - -But the National Assembly was dominated by free market advocates, not socialists. +* **unpleasant monetarist arithmetic** like that described in this quanteon lecture {doc}`unpleasant` + + * mathematics involving compound interest governed French government debt dynamics in the decades preceding 1789; according to leading historians, that arithmetic set the stage for the French Revolution -The National Assembly intended to use earnings from Church lands to service its national debt. +* a *real bills* theory of the effects of government open market operations in which the government *backs* new issues of paper money with government holdings of valuable real property or financial assets that holders of money can purchase from the government in exchange for their money. -To do this, it began to implement a ''privatization plan'' that would let it service its debt while -not raising taxes. + * The Revolutionaries learned about this theory from Adam Smith's 1776 book The Wealth of Nations + {cite}`smith2010wealth` and other contemporary sources -Their plan involved issuing paper notes called ''assignats'' that entitled bearers to use them to purchase state lands. + * It shaped how the Revolutionaries issued a paper money called **assignats** from 1789 to 1791 -These paper notes would be ''as good as silver coins'' in the sense that both were acceptable means of payment in exchange for those (formerly) church lands. +* a classical **gold** or **silver standard** + + * Napoleon Bonaparte became head of the French government in 1799. He used this theory to guide his monetary and fiscal policies -Finance Minister Necker and the Constituants planned -to solve the privatization problem **and** the debt problem simultaneously -by creating a new currency. +* a classical **inflation-tax** theory of inflation in which Philip Cagan's ({cite}`Cagan`) demand for money studied in this lecture {doc}`cagan_ree` is a key component -They devised a scheme to raise revenues by auctioning -the confiscated lands, thereby withdrawing paper notes issued on the security of -the lands sold by the government. + * This theory helps explain French price level and money supply data from 1794 to 1797 - This ''tax-backed money'' scheme propelled the National Assembly into the domain of monetary experimentation. +* a **legal restrictions** or **financial repression** theory of the demand for real balances -Records of their debates show -how members of the Assembly marshaled theory and evidence to assess the likely -effects of their innovation. - -They quoted David Hume and Adam Smith and cited John -Law's System of 1720 and the American experiences with paper money fifteen years -earlier as examples of how paper money schemes can go awry. - - -### Necker's plan and how it was tweaked + * The Twelve Members comprising the Committee of Public Safety who adminstered the Terror from June 1793 to July 1794 used this theory to shape their monetary policy -Necker's original plan embodied two components: a national bank and a new -financial instrument, the ''assignat''. - - -Necker's national -bank was patterned after the Bank of England. He proposed to transform the *Caisse d'Escompte* into a national bank by granting it a monopoly on issuing -notes and marketing government debt. The *Caisse* was a -discount bank founded in 1776 whose main function was to discount commercial bills -and issue convertible notes. Although independent of the government in principle, -it had occasionally been used as a source of loans. Its notes had been declared -inconvertible in August 1788, and by the time of Necker's proposal, its reserves -were exhausted. Necker's plan placed the National Estates (as the Church lands -became known after the addition of the royal demesne) at the center of the financial -picture: a ''Bank of France'' would issue a $5\%$ security mortgaged on the prospective -receipts from the modest sale of some 400 millions' worth of National Estates in -the years 1791 to 1793. -```{note} - Only 170 million was to be used initially -to cover the deficits of 1789 and 1790. -``` +We use matplotlib to replicate several of the graphs with which {cite}`sargent_velde1995` portrayed outcomes of these experiments +## Data Sources -By mid-1790, members of the National Assembly had agreed to sell the National -Estates and to use the proceeds to service the debt in a ``tax-backed money'' scheme -```{note} -Debt service costs absorbed - over 60\% of French government expenditures. -``` +This lecture uses data from three spreadsheets assembled by {cite}`sargent_velde1995`: + * [datasets/fig_3.xlsx](https://github.com/QuantEcon/lecture-python-intro/blob/main/lectures/datasets/fig_3.xlsx) + * [datasets/dette.xlsx](https://github.com/QuantEcon/lecture-python-intro/blob/main/lectures/datasets/dette.xlsx) + * [datasets/assignat.xlsx](https://github.com/QuantEcon/lecture-python-intro/blob/main/lectures/datasets/assignat.xlsx) -The government would issue securities with which it would reimburse debt. +```{code-cell} ipython3 +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +plt.rcParams.update({'font.size': 12}) -The securities -were acceptable as payment for National Estates purchased at auctions; once received -in payment, they were to be burned. +base_url = 'https://github.com/QuantEcon/lecture-python-intro/raw/'\ + + 'main/lectures/datasets/' -```{note} -The appendix to {cite}`sargent_velde1995` describes the -auction rules in detail. -``` -The Estates available for sale were thought to be worth about 2,400 -million, while the exactable debt (essentially fixed-term loans, unpaid arrears, -and liquidated offices) stood at about 2,000 million. The value of the land was -sufficient to let the Assembly retire all of the exactable debt and thereby eliminate -the interest payments on it. After lengthy debates, in August 1790, the Assembly set the denomination -and interest rate structure of the debt. - - -```{note} Two distinct -aspects of monetary theory help in thinking about the assignat plan. First, a system -beginning with a commodity standard typically has room for a once-and-for-all emission -of (an unbacked) paper currency that can replace the commodity money without generating -inflation. \citet{Sargent/Wallace:1983} describe models with this property. That -commodity money systems are wasteful underlies Milton Friedman's (1960) TOM:ADD REFERENCE preference -for a fiat money regime over a commodity money. Second, in a small country on a -commodity money system that starts with restrictions on intermediation, those restrictions -can be relaxed by letting the government issue bank notes on the security of safe -private indebtedness, while leaving bank notes convertible into gold at par. See -Adam Smith and Sargent and Wallace (1982) for expressions of this idea. TOM: ADD REFERENCES HEREAND IN BIBTEX FILE. +fig_3_url = f'{base_url}fig_3.xlsx' +dette_url = f'{base_url}dette.xlsx' +assignat_url = f'{base_url}assignat.xlsx' ``` +## Government Expenditures and Taxes Collected -```{note} -The -National Assembly debated many now classic questions in monetary economics. Under -what conditions would money creation generate inflation, with what consequences -for business conditions? Distinctions were made between issue of money to pay off -debt, on one hand, and monetization of deficits, on the other. Would *assignats* be akin -to notes emitted under a real bills regime, and cause loss of specie, or would -they circulate alongside specie, thus increasing the money stock? Would inflation -affect real wages? How would it impact foreign trade, competitiveness of French -industry and agriculture, balance of trade, foreign exchange? -``` -## Data Sources -This notebook uses data from three spreadsheets: +We'll start by using `matplotlib` to construct several graphs that will provide important historical context. - * datasets/fig_3.ods - * datasets/dette.xlsx - * datasets/assignat.xlsx +These graphs are versions of ones that appear in {cite}`sargent_velde1995`. -```{code-cell} ipython3 -import numpy as np -import pandas as pd -import matplotlib.pyplot as plt -plt.rcParams.update({'font.size': 12}) -``` +These graphs show that during the 18th century - -## Figure 1 - + * government expenditures in France and Great Britain both surged during four big wars, and by comparable amounts + * In Britain, tax revenues were approximately equal to government expenditures during peace times, + but were substantially less than government expenditures during wars + * In France, even in peace time, tax revenues were substantially less than government expenditures ```{code-cell} ipython3 --- mystnb: figure: - caption: "Ratio of debt service to taxes, Britain and France" - name: fig1 + caption: Military Spending in Britain and France + name: fr_fig4 --- +# Read the data from Excel file +data2 = pd.read_excel(dette_url, + sheet_name='Militspe', usecols='M:X', + skiprows=7, nrows=102, header=None) -# Read the data from the Excel file -data1 = pd.read_excel('datasets/dette.xlsx', sheet_name='Debt', usecols='R:S', skiprows=5, nrows=99, header=None) -data1a = pd.read_excel('datasets/dette.xlsx', sheet_name='Debt', usecols='P', skiprows=89, nrows=15, header=None) +# French military spending, 1685-1789, in 1726 livres +data4 = pd.read_excel(dette_url, + sheet_name='Militspe', usecols='D', + skiprows=3, nrows=105, header=None).squeeze() + +years = range(1685, 1790) -# Plot the data plt.figure() -plt.plot(range(1690, 1789), 100 * data1.iloc[:, 1], linewidth=0.8) - -date = np.arange(1690, 1789) -index = (date < 1774) & (data1.iloc[:, 0] > 0) -plt.plot(date[index], 100 * data1[index].iloc[:, 0], '*:', color='r', linewidth=0.8) +plt.plot(years, data4, '*-', linewidth=0.8) -# Plot the additional data -plt.plot(range(1774, 1789), 100 * data1a, '*:', color='orange') +plt.plot(range(1689, 1791), data2.iloc[:, 4], linewidth=0.8) -# Note about the data -# The French data before 1720 don't match up with the published version -# Set the plot properties plt.gca().spines['top'].set_visible(False) plt.gca().spines['right'].set_visible(False) -plt.gca().set_facecolor('white') -plt.gca().set_xlim([1688, 1788]) -plt.ylabel('% of Taxes') +plt.gca().tick_params(labelsize=12) +plt.xlim([1689, 1790]) +plt.xlabel('*: France') +plt.ylabel('Millions of livres') +plt.ylim([0, 475]) plt.tight_layout() plt.show() - -#plt.savefig('frfinfig1.pdf', dpi=600) -#plt.savefig('frfinfig1.jpg', dpi=600) ``` +During the 18th century, Britain and France fought four large wars. + +Britain won the first three wars and lost the fourth. + +Each of those wars produced surges in both countries' government expenditures that each country somehow had to finance. -TO TEACH TOM: By staring at {numref}`fig1` carefully - +Figure {numref}`fr_fig4` shows surges in military expenditures in France (in blue) and Great Britain. +during those four wars. -## Figure 2 - +A remarkable aspect of figure {numref}`fr_fig4` is that despite having a population less than half of France's, Britain was able to finance military expenses of about the same amounts as France's. + +This testifies to Britain's having created state institutions that could sustain high tax collections, government spending , and government borrowing. See {cite}`north1989`. ```{code-cell} ipython3 --- mystnb: figure: - caption: "Government Expenditures and Tax Revenues in Britain" - name: fig2 + caption: Government Expenditures and Tax Revenues in Britain + name: fr_fig2 --- - # Read the data from Excel file -data2 = pd.read_excel('datasets/dette.xlsx', sheet_name='Militspe', usecols='M:X', skiprows=7, nrows=102, header=None) +data2 = pd.read_excel(dette_url, sheet_name='Militspe', usecols='M:X', + skiprows=7, nrows=102, header=None) # Plot the data plt.figure() plt.plot(range(1689, 1791), data2.iloc[:, 5], linewidth=0.8) plt.plot(range(1689, 1791), data2.iloc[:, 11], linewidth=0.8, color='red') plt.plot(range(1689, 1791), data2.iloc[:, 9], linewidth=0.8, color='orange') -plt.plot(range(1689, 1791), data2.iloc[:, 8], 'o-', markerfacecolor='none', linewidth=0.8, color='purple') +plt.plot(range(1689, 1791), data2.iloc[:, 8], 'o-', + markerfacecolor='none', linewidth=0.8, color='purple') # Customize the plot plt.gca().spines['top'].set_visible(False) @@ -231,23 +171,99 @@ plt.text(1760, 4.2, 'civil plus debt service', fontsize=10) plt.text(1708, 15.5, 'total govt spending', fontsize=10) plt.text(1759, 7.3, 'revenues', fontsize=10) - plt.tight_layout() plt.show() +``` + +Figures {numref}`fr_fig2` and {numref}`fr_fig3` summarize British and French government fiscal policies during the century before the start of the French Revolution in 1789. + + +Before 1789, progressive forces in France admired how Britain had financed its government expenditures and wanted to redesign French fiscal arrangements to make them more like Britain's. + +Figure {numref}`fr_fig2` shows government expenditures and how it was distributed among expenditures for + + * civil (non-military) activities + * debt service, i.e., interest payments + * military expenditures (the yellow line minus the red line) + +Figure {numref}`fr_fig2` also plots total government revenues from tax collections (the purple circled line) + +Notice the surges in total government expenditures associated with surges in military expenditures +in these four wars + + * Wars against France's King Louis XIV early in the 18th century + * The War of the Austrian Succession in the 1740s + * The French and Indian War in the 1750's and 1760s + * The American War for Independence from 1775 to 1783 + +Figure {numref}`fr_fig2` indicates that + + * during times of peace, government expenditures approximately equal taxes and debt service payments neither grow nor decline over time + * during times of wars, government expenditures exceed tax revenues + * the government finances the deficit of revenues relative to expenditures by issuing debt + * after a war is over, the government's tax revenues exceed its non-interest expenditures by just enough to service the debt that the government issued to finance earlier deficits + * thus, after a war, the government does *not* raise taxes by enough to pay off its debt + * instead, it just rolls over whatever debt it inherits, raising taxes by just enough to service the interest payments on that debt + +Eighteenth-century British fiscal policy portrayed Figure {numref}`fr_fig2` thus looks very much like a text-book example of a *tax-smoothing* model like Robert Barro's {cite}`Barro1979`. + +A striking feature of the graph is what we'll label a *law of gravity* between tax collections and government expenditures. + + * levels of government expenditures at taxes attract each other + * while they can temporarily differ -- as they do during wars -- they come back together when peace returns + + + +Next we'll plot data on debt service costs as fractions of government revenues in Great Britain and France during the 18th century. + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Ratio of debt service to taxes, Britain and France + name: fr_fig1 +--- +# Read the data from the Excel file +data1 = pd.read_excel(dette_url, sheet_name='Debt', + usecols='R:S', skiprows=5, nrows=99, header=None) +data1a = pd.read_excel(dette_url, sheet_name='Debt', + usecols='P', skiprows=89, nrows=15, header=None) + +# Plot the data +plt.figure() +plt.plot(range(1690, 1789), 100 * data1.iloc[:, 1], linewidth=0.8) + +date = np.arange(1690, 1789) +index = (date < 1774) & (data1.iloc[:, 0] > 0) +plt.plot(date[index], 100 * data1[index].iloc[:, 0], + '*:', color='r', linewidth=0.8) + +# Plot the additional data +plt.plot(range(1774, 1789), 100 * data1a, '*:', color='orange') + +# Note about the data +# The French data before 1720 don't match up with the published version +# Set the plot properties +plt.gca().spines['top'].set_visible(False) +plt.gca().spines['right'].set_visible(False) +plt.gca().set_facecolor('white') +plt.gca().set_xlim([1688, 1788]) +plt.ylabel('% of Taxes') -# Save the figure as a PDF -#plt.savefig('frfinfig2.pdf', dpi=600) +plt.tight_layout() +plt.show() ``` - -## Figure 3 +Figure {numref}`fr_fig1` shows that interest payments on government debt (i.e., so-called ''debt service'') were high fractions of government tax revenues in both Great Britain and France. +{numref}`fr_fig2` showed us that in peace times Britain managed to balance its budget despite those large interest costs. - +But as we'll see in our next graph, on the eve of the French Revolution in 1788, the fiscal *law of gravity* that worked so well in Britain did not working very well in France. ```{code-cell} ipython3 # Read the data from the Excel file -data1 = pd.read_excel('datasets/fig_3.xlsx', sheet_name='Sheet1', usecols='C:F', skiprows=5, nrows=30, header=None) +data1 = pd.read_excel(fig_3_url, sheet_name='Sheet1', + usecols='C:F', skiprows=5, nrows=30, header=None) data1.replace(0, np.nan, inplace=True) ``` @@ -256,7 +272,7 @@ data1.replace(0, np.nan, inplace=True) --- mystnb: figure: - caption: "Government Spending and Tax Revenues in France" + caption: Government Spending and Tax Revenues in France name: fr_fig3 --- # Plot the data @@ -264,7 +280,8 @@ plt.figure() plt.plot(range(1759, 1789, 1), data1.iloc[:, 0], '-x', linewidth=0.8) plt.plot(range(1759, 1789, 1), data1.iloc[:, 1], '--*', linewidth=0.8) -plt.plot(range(1759, 1789, 1), data1.iloc[:, 2], '-o', linewidth=0.8, markerfacecolor='none') +plt.plot(range(1759, 1789, 1), data1.iloc[:, 2], + '-o', linewidth=0.8, markerfacecolor='none') plt.plot(range(1759, 1789, 1), data1.iloc[:, 3], '-*', linewidth=0.8) plt.text(1775, 610, 'total spending', fontsize=10) @@ -273,8 +290,6 @@ plt.text(1773, 220, 'civil plus debt service', fontsize=10) plt.text(1773, 80, 'debt service', fontsize=10) plt.text(1785, 500, 'revenues', fontsize=10) - - plt.gca().spines['top'].set_visible(False) plt.gca().spines['right'].set_visible(False) plt.ylim([0, 700]) @@ -282,88 +297,139 @@ plt.ylabel('millions of livres') plt.tight_layout() plt.show() - -#plt.savefig('frfinfig3.jpg', dpi=600) ``` +{numref}`fr_fig3` shows that on the eve of the French Revolution in 1788, government expenditures exceeded tax revenues. -TO TEACH TOM: By staring at {numref}`fr_fig3` carefully -```{code-cell} ipython3 -# Plot the data -plt.figure() +Especially during and after France's expenditures to help the Americans in their War of Independence from Great Britain, growing government debt service (i.e., interest payments) +contributed to this situation. -plt.plot(np.arange(1759, 1789, 1)[~np.isnan(data1.iloc[:, 0])], data1.iloc[:, 0][~np.isnan(data1.iloc[:, 0])], '-x', linewidth=0.8) -plt.plot(np.arange(1759, 1789, 1)[~np.isnan(data1.iloc[:, 1])], data1.iloc[:, 1][~np.isnan(data1.iloc[:, 1])], '--*', linewidth=0.8) -plt.plot(np.arange(1759, 1789, 1)[~np.isnan(data1.iloc[:, 2])], data1.iloc[:, 2][~np.isnan(data1.iloc[:, 2])], '-o', linewidth=0.8, markerfacecolor='none') -plt.plot(np.arange(1759, 1789, 1)[~np.isnan(data1.iloc[:, 3])], data1.iloc[:, 3][~np.isnan(data1.iloc[:, 3])], '-*', linewidth=0.8) +This was partly a consequence of the unfolding of the debt dynamics that underlies the Unpleasant Arithmetic discussed in this quantecon lecture {doc}`unpleasant`. -plt.text(1775, 610, 'total spending', fontsize=10) -plt.text(1773, 325, 'military', fontsize=10) -plt.text(1773, 220, 'civil plus debt service', fontsize=10) -plt.text(1773, 80, 'debt service', fontsize=10) -plt.text(1785, 500, 'revenues', fontsize=10) +{cite}`sargent_velde1995` describe how the Ancient Regime that until 1788 had governed France had stable institutional features that made it difficult for the government to balance its budget. -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) -plt.ylim([0, 700]) -plt.ylabel('millions of livres') +Powerful contending interests had prevented from the government from closing the gap between its +total expenditures and its tax revenues by either -plt.tight_layout() -plt.show() + * raising taxes, or + * lowering government's non-debt service (i.e., non-interest) expenditures, or + * lowering debt service (i.e., interest) costs by rescheduling, i.e., defaulting on some debts -#plt.savefig('frfinfig3_ignore_nan.jpg', dpi=600) -``` +Precedents and prevailing French arrangements had empowered three constituencies to block adjustments to components of the government budget constraint that they cared especially about - -## Figure 4 - +* tax payers +* beneficiaries of government expenditures +* government creditors (i.e., owners of government bonds) -```{code-cell} ipython3 ---- -mystnb: - figure: - caption: "Military Spending in Britain and France" - name: fig4 ---- -# French military spending, 1685-1789, in 1726 livres -data4 = pd.read_excel('datasets/dette.xlsx', sheet_name='Militspe', usecols='D', skiprows=3, nrows=105, header=None).squeeze() -years = range(1685, 1790) +When the French government had confronted a similar situation around 1720 after King Louis XIV's +Wars had left it with a debt crisis, it had sacrificed the interests of +government creditors, i.e., by defaulting enough of its debt to bring reduce interest payments down enough to balance the budget. -plt.figure() -plt.plot(years, data4, '*-', linewidth=0.8) +Somehow, in 1789, creditors of the French government were more powerful than they had been in 1720. -plt.plot(range(1689, 1791), data2.iloc[:, 4], linewidth=0.8) +Therefore, King Louis XVI convened the Estates General together to ask them to redesign the French constitution in a way that would lower government expenditures or increase taxes, thereby +allowing him to balance the budget while also honoring his promises to creditors of the French government. -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) -plt.gca().tick_params(labelsize=12) -plt.xlim([1689, 1790]) -plt.xlabel('*: France') -plt.ylabel('Millions of livres') -plt.ylim([0, 475]) +The King called the Estates General together in an effort to promote the reforms that would +would bring sustained budget balance. -plt.tight_layout() -plt.show() +{cite}`sargent_velde1995` describe how the French Revolutionaries set out to accomplish that. -#plt.savefig('frfinfig4.pdf', dpi=600) -``` +## Nationalization, Privatization, Debt Reduction + +In 1789, the Revolutionaries quickly reorganized the Estates General into a National Assembly. + +A first piece of business was to address the fiscal crisis, the situation that had motivated the King to convene the Estates General. + +The Revolutionaries were not socialists or communists. + +To the contrary, they respected private property and knew state-of-the-art economics. + +They knew that to honor government debts, they would have to raise new revenues or reduce expenditures. + +A coincidence was that the Catholic Church owned vast income-producing properties. + +Indeed, the capitalized value of those income streams put estimates of the value of church lands at +about the same amount as the entire French government debt. + +This coincidence fostered a three step plan for servicing the French government debt + + * nationalize the church lands -- i.e., sequester or confiscate it without paying for it + * sell the church lands + * use the proceeds from those sales to service or even retire French government debt + +The monetary theory underlying this plan had been set out by Adam Smith in his analysis of what he called *real bills* in his 1776 book +**The Wealth of Nations** {cite}`smith2010wealth`, which many of the revolutionaries had read. + +Adam Smith defined a *real bill* as a paper money note that is backed by a claims on a real asset like productive capital or inventories. + +The National Assembly put together an ingenious institutional arrangement to implement this plan. + +In response to a motion by Catholic Bishop Talleyrand (an atheist), +the National Assembly confiscated and nationalized Church lands. + +The National Assembly intended to use earnings from Church lands to service its national debt. + +To do this, it began to implement a ''privatization plan'' that would let it service its debt while +not raising taxes. + +Their plan involved issuing paper notes called ''assignats'' that entitled bearers to use them to purchase state lands. + +These paper notes would be ''as good as silver coins'' in the sense that both were acceptable means of payment in exchange for those (formerly) church lands. + +Finance Minister Necker and the Constituents of the National Assembly thus planned +to solve the privatization problem *and* the debt problem simultaneously +by creating a new currency. + +They devised a scheme to raise revenues by auctioning +the confiscated lands, thereby withdrawing paper notes issued on the security of +the lands sold by the government. + + This ''tax-backed money'' scheme propelled the National Assembly into the domains of then modern monetary theories. + +Records of debates show +how members of the Assembly marshaled theory and evidence to assess the likely +effects of their innovation. + + * Members of the National Assembly quoted David Hume and Adam Smith + * They cited John Law's System of 1720 and the American experiences with paper money fifteen years +earlier as examples of how paper money schemes can go awry + * Knowing pitfalls, they set out to avoid them + +They succeeded for two or three years. + +But after that, France entered a big War that disrupted the plan in ways that completely altered the character of France's paper money. {cite}`sargent_velde1995` describe what happened. + +## Remaking the tax code and tax administration + +In 1789 the French Revolutionaries formed a National Assembly and set out to remake French +fiscal policy. + +They wanted to honor government debts -- interests of French government creditors were well represented in the National Assembly. + +But they set out to remake the French tax code and the administrative machinery for collecting taxes. + + * they abolished many taxes + * they abolished the Ancient Regimes scheme for *tax farming* + * tax farming meant that the government had privatized tax collection by hiring private citizens -- so-called tax farmers to collect taxes, while retaining a fraction of them as payment for their services + * the great chemist Lavoisier was also a tax farmer, one of the reasons that the Committee for Public Safety sent him to the guillotine in 1794 + +As a consequence of these tax reforms, government tax revenues declined -TO TEACH TOM: By staring at {numref}`fig4` carefully - -## Figure 5 - +The next figure shows this ```{code-cell} ipython3 --- mystnb: figure: - caption: "Index of real per capital revenues, France" - name: fig5 + caption: Index of real per capital revenues, France + name: fr_fig5 --- # Read data from Excel file -data5 = pd.read_excel('datasets/dette.xlsx', sheet_name='Debt', usecols='K', skiprows=41, nrows=120, header=None) +data5 = pd.read_excel(dette_url, sheet_name='Debt', usecols='K', + skiprows=41, nrows=120, header=None) # Plot the data plt.figure() @@ -378,261 +444,309 @@ plt.ylabel('1726 = 1', fontsize=12) plt.tight_layout() plt.show() - -# Save the figure as a PDF -#plt.savefig('frfinfig5.pdf', dpi=600) ``` -TO TEACH TOM: By staring at {numref}`fig5` carefully +According to {numref}`fr_fig5`, tax revenues per capita did not rise to their pre 1789 levels +until after 1815, when Napoleon Bonaparte was exiled to St Helena and King Louis XVIII was restored to the French Crown. -## Rise and Fall of the *Assignat* + * from 1799 to 1814, Napoleon Bonaparte had other sources of revenues -- booty and reparations from provinces and nations that he defeated in war + * from 1789 to 1799, the French Revolutionaries turned to another source to raise resources to pay for government purchases of goods and services and to service French government debt. +And as the next figure shows, government expenditures exceeded tax revenues by substantial +amounts during the period form 1789 to 1799. - We have partitioned Figures~\ref{fig:fig7}, \ref{fig:fig8}, and \ref{fig:fig9} - into three periods, corresponding -to different monetary regimes or episodes. The three clouds of points in -Figure~\ref{fig:fig7} - depict different real balance-inflation relationships. Only the cloud for the -third period has the inverse relationship familiar to us now from twentieth-century -hyperinflations. The first period ends in the late summer of 1793, and is characterized -by growing real balances and moderate inflation. The second period begins and ends -with the Terror. It is marked by high real balances, around 2,500 millions, and -roughly stable prices. The fall of Robespierre in late July 1794 begins the third -of our episodes, in which real balances decline and prices rise rapidly. We interpret -these three episodes in terms of three separate theories about money: a ``backing'' -or ''real bills'' theory (the text is Adam Smith (1776)), -a legal restrictions theory (TOM: HERE PLEASE CITE -Keynes,1940, AS WELL AS Bryant/Wallace:1984 and Villamil:1988) -and a classical hyperinflation theory.% -```{note} -According to the empirical definition of hyperinflation adopted by {cite}`Cagan`, -beginning in the month that inflation exceeds 50 percent -per month and ending in the month before inflation drops below 50 percent per month -for at least a year, the *assignat* experienced a hyperinflation from May to December -1795. -``` -We view these -theories not as competitors but as alternative collections of ``if-then'' -statements about government note issues, each of which finds its conditions more -nearly met in one of these episodes than in the other two. +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Spending (blue) and Revenues (orange), (real values) + name: fr_fig11 +--- +# Read data from Excel file +data11 = pd.read_excel(assignat_url, sheet_name='Budgets', + usecols='J:K', skiprows=22, nrows=52, header=None) - +# Prepare the x-axis data +x_data = np.concatenate([ + np.arange(1791, 1794 + 8/12, 1/12), + np.arange(1794 + 9/12, 1795 + 3/12, 1/12) +]) +# Remove NaN values from the data +data11_clean = data11.dropna() +# Plot the data +plt.figure() +h = plt.plot(x_data, data11_clean.values[:, 0], linewidth=0.8) +h = plt.plot(x_data, data11_clean.values[:, 1], '--', linewidth=0.8) -## Figure 7 +# Set plot properties +plt.gca().spines['top'].set_visible(False) +plt.gca().spines['right'].set_visible(False) +plt.gca().set_facecolor('white') +plt.gca().tick_params(axis='both', which='major', labelsize=12) +plt.xlim([1791, 1795 + 3/12]) +plt.xticks(np.arange(1791, 1796)) +plt.yticks(np.arange(0, 201, 20)) +# Set the y-axis label +plt.ylabel('millions of livres', fontsize=12) -## To Do for Zejin +plt.tight_layout() +plt.show() +``` -I want to tweak and consolidate the extra lines that Zejin drew on the beautiful **Figure 7**. +To cover the discrepancies between government expenditures and tax revenues revealed in {numref}`fr_fig11`, the French revolutionaries printed paper money and spent it. -I'd like to experiment in plotting the **six** extra lines all on one graph -- a pair of lines for each of our subsamples +The next figure shows that by printing money, they were able to finance substantial purchases +of goods and services, including military goods and soldiers' pay. - * one for the $y$ on $x$ regression line - * another for the $x$ on $y$ regression line +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Revenues raised by printing paper money notes + name: fr_fig24 +--- +# Read data from Excel file +data12 = pd.read_excel(assignat_url, sheet_name='seignor', + usecols='F', skiprows=6, nrows=75, header=None).squeeze() -I'd like the $y$ on $x$ and $x$ on $y$ lines to be in separate colors. +# Create a figure and plot the data +plt.figure() +plt.plot(pd.date_range(start='1790', periods=len(data12), freq='ME'), + data12, linewidth=0.8) -Once we are satisfied with this new graph with its six additional lines, we can dispense with the other graphs that add one line at a time. +plt.gca().spines['top'].set_visible(False) +plt.gca().spines['right'].set_visible(False) -Zejin, I can explain on zoom the lessons I want to convey with this. +plt.axhline(y=472.42/12, color='r', linestyle=':') +plt.xticks(ticks=pd.date_range(start='1790', + end='1796', freq='YS'), labels=range(1790, 1797)) +plt.xlim(pd.Timestamp('1791'), + pd.Timestamp('1796-02') + pd.DateOffset(months=2)) +plt.ylabel('millions of livres', fontsize=12) +plt.text(pd.Timestamp('1793-11'), 39.5, 'revenues in 1788', + verticalalignment='top', fontsize=12) +plt.tight_layout() +plt.show() +``` +{numref}`fr_fig24` compares the revenues raised by printing money from 1789 to 1796 with tax revenues that the Ancient Regime had raised in 1788. -Just to recall, to compute the regression lines, Zejin wrote a function that use standard formulas -for a and b in a least squares regression y = a + b x + residual -- i.e., b is ratio of sample covariance of y,x to sample variance of x; while a is then computed from a = sample mean of y - \hat b *sample mean of x +Measured in goods, revenues raised at time $t$ by printing new money equal -We could presumably tell students how to do this with a couple of numpy lines -I'd like to create three additional versions of the following figure. +$$ +\frac{M_{t+1} - M_t}{p_t} +$$ -To remind you, we focused on three subperiods: +where +* $M_t$ is the stock of paper money at time $t$ measured in livres +* $p_t$ is the price level at time $t$ measured in units of goods per livre at time $t$ +* $M_{t+1} - M_t$ is the amount of new money printed at time $t$ -* subperiod 1: ("real bills period): January 1791 to July 1793 +Notice the 1793-1794 surge in revenues raised by printing money. -* subperiod 2: ("terror:): August 1793 - July 1794 +* This reflects extraordinary measures that the Committee for Public Safety adopted to force citizens to accept paper money, or else. -* subperiod 3: ("classic Cagan hyperinflation): August 1794 - March 1796 +Also note the abrupt fall off in revenues raised by 1797 and the absence of further observations after 1797. +* This reflects the end of using the printing press to raise revenues. -I can explain what this is designed to show. +What French paper money entitled its holders to changed over time in interesting ways. - +These led to outcomes that vary over time and that illustrate the playing out in practice of theories that guided the Revolutionaries' monetary policy decisions. -```{code-cell} ipython3 -def fit(x, y): - b = np.cov(x, y)[0, 1] / np.var(x) - a = y.mean() - b * x.mean() +The next figure shows the price level in France during the time that the Revolutionaries used paper money to finance parts of their expenditures. - return a, b -``` - -```{code-cell} ipython3 -# load data -caron = np.load('datasets/caron.npy') -nom_balances = np.load('datasets/nom_balances.npy') - -infl = np.concatenate(([np.nan], -np.log(caron[1:63, 1] / caron[0:62, 1]))) -bal = nom_balances[14:77, 1] * caron[:, 1] / 1000 -``` - -```{code-cell} ipython3 -# fit data - -# reg y on x for three periods -a1, b1 = fit(bal[1:31], infl[1:31]) -a2, b2 = fit(bal[31:44], infl[31:44]) -a3, b3 = fit(bal[44:63], infl[44:63]) - -# reg x on y for three periods -a1_rev, b1_rev = fit(infl[1:31], bal[1:31]) -a2_rev, b2_rev = fit(infl[31:44], bal[31:44]) -a3_rev, b3_rev = fit(infl[44:63], bal[44:63]) -``` +Note that we use a log scale because the price level rose so much. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Price Level and Price of Gold (log scale) + name: fr_fig9 +--- +# Read the data from Excel file +data7 = pd.read_excel(assignat_url, sheet_name='Data', + usecols='P:Q', skiprows=4, nrows=80, header=None) +data7a = pd.read_excel(assignat_url, sheet_name='Data', + usecols='L', skiprows=4, nrows=80, header=None) +# Create the figure and plot plt.figure() +x = np.arange(1789 + 10/12, 1796 + 5/12, 1/12) +h, = plt.plot(x, 1. / data7.iloc[:, 0], linestyle='--') +h, = plt.plot(x, 1. / data7.iloc[:, 1], color='r') + +# Set properties of the plot +plt.gca().tick_params(labelsize=12) +plt.yscale('log') +plt.xlim([1789 + 10/12, 1796 + 5/12]) plt.gca().spines['top'].set_visible(False) plt.gca().spines['right'].set_visible(False) -# first subsample -plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', color='blue', label='real bills period') - -# second subsample -plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') +# Add vertical lines +plt.axvline(x=1793 + 6.5/12, linestyle='-', linewidth=0.8, color='orange') +plt.axvline(x=1794 + 6.5/12, linestyle='-', linewidth=0.8, color='purple') -# third subsample -plt.plot(bal[44:63], infl[44:63], '*', color='orange', label='classic Cagan hyperinflation') +# Add text +plt.text(1793.75, 120, 'Terror', fontsize=12) +plt.text(1795, 2.8, 'price level', fontsize=12) +plt.text(1794.9, 40, 'gold', fontsize=12) -plt.xlabel('real balances') -plt.ylabel('inflation') -plt.legend() plt.tight_layout() plt.show() -#plt.savefig('frfinfig7.pdf', dpi=600) ``` +We have partioned {numref}`fr_fig9` that shows the log of the price level and {numref}`fr_fig8` +below that plots real balances $\frac{M_t}{p_t}$ into three periods that correspond to different monetary experiments or *regimes*. +The first period ends in the late summer of 1793, and is characterized +by growing real balances and moderate inflation. -```{code-cell} ipython3 -# fit data +The second period begins and ends +with the Terror. It is marked by high real balances, around 2,500 million, and +roughly stable prices. The fall of Robespierre in late July 1794 begins the third +of our episodes, in which real balances decline and prices rise rapidly. -# reg y on x for three periods -a1, b1 = fit(bal[1:31], infl[1:31]) -a2, b2 = fit(bal[31:44], infl[31:44]) -a3, b3 = fit(bal[44:63], infl[44:63]) +We interpret +these three episodes in terms of distinct theories -# reg x on y for three periods -a1_rev, b1_rev = fit(infl[1:31], bal[1:31]) -a2_rev, b2_rev = fit(infl[31:44], bal[31:44]) -a3_rev, b3_rev = fit(infl[44:63], bal[44:63]) +* a *backing* or *real bills* theory (the classic text for this theory is Adam Smith {cite}`smith2010wealth`) +* a legal restrictions theory ( {cite}`keynes1940pay`, {cite}`bryant1984price` ) +* a classical hyperinflation theory ({cite}`Cagan`) +* +```{note} +According to the empirical definition of hyperinflation adopted by {cite}`Cagan`, +beginning in the month that inflation exceeds 50 percent +per month and ending in the month before inflation drops below 50 percent per month +for at least a year, the *assignat* experienced a hyperinflation from May to December +1795. ``` +We view these +theories not as competitors but as alternative collections of ''if-then'' +statements about government note issues, each of which finds its conditions more +nearly met in one of these episodes than in the other two. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Real balances of assignats (in gold and goods) + name: fr_fig8 +--- +# Read the data from Excel file +data7 = pd.read_excel(assignat_url, sheet_name='Data', + usecols='P:Q', skiprows=4, nrows=80, header=None) +data7a = pd.read_excel(assignat_url, sheet_name='Data', + usecols='L', skiprows=4, nrows=80, header=None) + +# Create the figure and plot plt.figure() -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) +h = plt.plot(pd.date_range(start='1789-11-01', periods=len(data7), freq='ME'), + (data7a.values * [1, 1]) * data7.values, linewidth=1.) +plt.setp(h[1], linestyle='--', color='red') -# first subsample -plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', color='blue', label='real bills period') +plt.vlines([pd.Timestamp('1793-07-15'), pd.Timestamp('1793-07-15')], + 0, 3000, linewidth=0.8, color='orange') +plt.vlines([pd.Timestamp('1794-07-15'), pd.Timestamp('1794-07-15')], + 0, 3000, linewidth=0.8, color='purple') -# second subsample -plt.plot(bal[34:44], infl[34:44], '+', color='red', label='terror') +plt.ylim([0, 3000]) -# third subsample # Tom tinkered with subsample period -plt.plot(bal[44:63], infl[44:63], '*', color='orange', label='classic Cagan hyperinflation') +# Set properties of the plot +plt.gca().spines['top'].set_visible(False) +plt.gca().spines['right'].set_visible(False) +plt.gca().set_facecolor('white') +plt.gca().tick_params(labelsize=12) +plt.xlim(pd.Timestamp('1789-11-01'), pd.Timestamp('1796-06-01')) +plt.ylabel('millions of livres', fontsize=12) + +# Add text annotations +plt.text(pd.Timestamp('1793-09-01'), 200, 'Terror', fontsize=12) +plt.text(pd.Timestamp('1791-05-01'), 750, 'gold value', fontsize=12) +plt.text(pd.Timestamp('1794-10-01'), 2500, 'real value', fontsize=12) -plt.xlabel('real balances') -plt.ylabel('inflation') -plt.legend() plt.tight_layout() plt.show() -#plt.savefig('frfinfig7.pdf', dpi=600) ``` +The three clouds of points in Figure +{numref}`fr_fig104` + depict different real balance-inflation relationships. + +Only the cloud for the +third period has the inverse relationship familiar to us now from twentieth-century +hyperinflations. -

The above graph is Tom's experimental lab. We'll delete it eventually.

- -

Zejin: below is the grapth with six lines in one graph. The lines generated by regressing y on x have the same color as the corresponding data points, while the lines generated by regressing x on y are all in green.

-```{code-cell} ipython3 -plt.figure() -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) -# first subsample -plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', color='blue', label='real bills period') -plt.plot(bal[1:31], a1 + bal[1:31] * b1, color='blue', linewidth=0.8) -plt.plot(a1_rev + b1_rev * infl[1:31], infl[1:31], color='green', linewidth=0.8) -# second subsample -plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') -plt.plot(bal[31:44], a2 + bal[31:44] * b2, color='red', linewidth=0.8) -plt.plot(a2_rev + b2_rev * infl[31:44], infl[31:44], color='green', linewidth=0.8) +* subperiod 1: ("*real bills* period): January 1791 to July 1793 -# third subsample -plt.plot(bal[44:63], infl[44:63], '*', color='orange', label='classic Cagan hyperinflation') -plt.plot(bal[44:63], a3 + bal[44:63] * b3, color='orange', linewidth=0.8) -plt.plot(a3_rev + b3_rev * infl[44:63], infl[44:63], color='green', linewidth=0.8) +* subperiod 2: ("terror"): August 1793 - July 1794 -plt.xlabel('real balances') -plt.ylabel('inflation') -plt.legend() -#plt.savefig('frfinfig7.pdf', dpi=600) -``` +* subperiod 3: ("classic Cagan hyperinflation"): August 1794 - March 1796 +```{code-cell} ipython3 +def fit(x, y): + b = np.cov(x, y)[0, 1] / np.var(x) + a = y.mean() - b * x.mean() -

The graph below is Tom's version of the six lines in one graph. The lines generated by regressing y on x have the same color as the corresponding data points, while the lines generated by regressing x on y are all in green.

+ return a, b +``` ```{code-cell} ipython3 -plt.figure() -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) - -# first subsample -plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', color='blue', label='real bills period') -plt.plot(bal[1:31], a1 + bal[1:31] * b1, color='blue', linewidth=0.8) -plt.plot(a1_rev + b1_rev * infl[1:31], infl[1:31], color='green', linewidth=0.8) - -# second subsample -plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') -plt.plot(bal[34:44], a2 + bal[34:44] * b2, color='red', linewidth=0.8) -plt.plot(a2_rev + b2_rev * infl[34:44], infl[34:44], color='green', linewidth=0.8) +# Load data +caron = np.load('datasets/caron.npy') +nom_balances = np.load('datasets/nom_balances.npy') -# third subsample -plt.plot(bal[44:63], infl[44:63], '*', color='orange', label='classic Cagan hyperinflation') -plt.plot(bal[44:63], a3 + bal[44:63] * b3, color='orange', linewidth=0.8) -plt.plot(a3_rev + b3_rev * infl[44:63], infl[44:63], color='green', linewidth=0.8) +infl = np.concatenate(([np.nan], + -np.log(caron[1:63, 1] / caron[0:62, 1]))) +bal = nom_balances[14:77, 1] * caron[:, 1] / 1000 +``` -plt.xlabel('real balances') -plt.ylabel('inflation') -plt.legend() +```{code-cell} ipython3 +# Regress y on x for three periods +a1, b1 = fit(bal[1:31], infl[1:31]) +a2, b2 = fit(bal[31:44], infl[31:44]) +a3, b3 = fit(bal[44:63], infl[44:63]) -plt.tight_layout() -plt.show() -#plt.savefig('frfinfig7.pdf', dpi=600) +# Regress x on y for three periods +a1_rev, b1_rev = fit(infl[1:31], bal[1:31]) +a2_rev, b2_rev = fit(infl[31:44], bal[31:44]) +a3_rev, b3_rev = fit(infl[44:63], bal[44:63]) ``` ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Inflation and Real Balances + name: fr_fig104 +--- plt.figure() plt.gca().spines['top'].set_visible(False) plt.gca().spines['right'].set_visible(False) -# first subsample -plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', color='blue', label='real bills period') -plt.plot(bal[1:31], a1 + bal[1:31] * b1, color='blue') +# First subsample +plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', + color='blue', label='real bills period') -# second subsample +# Second subsample plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') -# third subsample -plt.plot(bal[44:63], infl[44:63], '*', color='orange', label='classic Cagan hyperinflation') +# Third subsample +plt.plot(bal[44:63], infl[44:63], '*', + color='orange', label='classic Cagan hyperinflation') plt.xlabel('real balances') plt.ylabel('inflation') @@ -640,46 +754,51 @@ plt.legend() plt.tight_layout() plt.show() -#plt.savefig('frfinfig7_line1.pdf', dpi=600) ``` -```{code-cell} ipython3 -plt.figure() -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) +The three clouds of points in {numref}`fr_fig104` evidently + depict different real balance-inflation relationships. -# first subsample -plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', color='blue', label='real bills period') -plt.plot(a1_rev + b1_rev * infl[1:31], infl[1:31], color='blue') +Only the cloud for the +third period has the inverse relationship familiar to us now from twentieth-century +hyperinflations. -# second subsample -plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') + To bring this out, we'll use linear regressions to draw straight lines that compress the + inflation-real balance relationship for our three sub-periods. -# third subsample -plt.plot(bal[44:63], infl[44:63], '*', color='orange', label='classic Cagan hyperinflation') + Before we do that, we'll drop some of the early observations during the terror period + to obtain the following graph. -plt.xlabel('real balances') -plt.ylabel('inflation') -plt.legend() +```{code-cell} ipython3 +# Regress y on x for three periods +a1, b1 = fit(bal[1:31], infl[1:31]) +a2, b2 = fit(bal[31:44], infl[31:44]) +a3, b3 = fit(bal[44:63], infl[44:63]) -plt.tight_layout() -plt.show() -#plt.savefig('frfinfig7_line1_rev.pdf', dpi=600) +# Regress x on y for three periods +a1_rev, b1_rev = fit(infl[1:31], bal[1:31]) +a2_rev, b2_rev = fit(infl[31:44], bal[31:44]) +a3_rev, b3_rev = fit(infl[44:63], bal[44:63]) ``` ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Inflation and Real Balances + name: fr_fig104b +--- plt.figure() plt.gca().spines['top'].set_visible(False) plt.gca().spines['right'].set_visible(False) -# first subsample +# First subsample plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', color='blue', label='real bills period') -# second subsample -plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') -plt.plot(bal[31:44], a2 + bal[31:44] * b2, color='red') +# Second subsample +plt.plot(bal[34:44], infl[34:44], '+', color='red', label='terror') -# third subsample +# Third subsample plt.plot(bal[44:63], infl[44:63], '*', color='orange', label='classic Cagan hyperinflation') plt.xlabel('real balances') @@ -688,23 +807,33 @@ plt.legend() plt.tight_layout() plt.show() -#plt.savefig('frfinfig7_line2.pdf', dpi=600) ``` +Now let's regress inflation on real balances during the *real bills* period and plot the regression +line. + ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Inflation and Real Balances + name: fr_fig104c +--- plt.figure() plt.gca().spines['top'].set_visible(False) plt.gca().spines['right'].set_visible(False) -# first subsample -plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', color='blue', label='real bills period') +# First subsample +plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', + color='blue', label='real bills period') +plt.plot(bal[1:31], a1 + bal[1:31] * b1, color='blue') -# second subsample +# Second subsample plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') -plt.plot(a2_rev + b2_rev * infl[31:44], infl[31:44], color='red') -# third subsample -plt.plot(bal[44:63], infl[44:63], '*', color='orange', label='classic Cagan hyperinflation') +# Third subsample +plt.plot(bal[44:63], infl[44:63], '*', + color='orange', label='classic Cagan hyperinflation') plt.xlabel('real balances') plt.ylabel('inflation') @@ -712,47 +841,44 @@ plt.legend() plt.tight_layout() plt.show() -#plt.savefig('frfinfig7_line2_rev.pdf', dpi=600) ``` -```{code-cell} ipython3 -plt.figure() -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) - -# first subsample -plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', color='blue', label='real bills period') +The regression line in {numref}`fr_fig104c` shows that large increases in real balances of +assignats (paper money) were accompanied by only modest rises in the price level, an outcome in line +with the *real bills* theory. -# second subsample -plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') +During this period, assignats were claims on church lands. -# third subsample -plt.plot(bal[44:63], infl[44:63], '*', color='orange', label='classic Cagan hyperinflation') -plt.plot(bal[44:63], a3 + bal[44:63] * b3, color='orange') +But towards the end of this period, the price level started to rise and real balances to fall +as the government continued to print money but stopped selling church land. -plt.xlabel('real balances') -plt.ylabel('inflation') -plt.legend() +To get people to hold that paper money, the government forced people to hold it by using legal restrictions. -plt.tight_layout() -plt.show() -#plt.savefig('frfinfig7_line3.pdf', dpi=600) -``` +Now let's regress real balances on inflation during the terror and plot the regression +line. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Inflation and Real Balances + name: fr_fig104d +--- plt.figure() plt.gca().spines['top'].set_visible(False) plt.gca().spines['right'].set_visible(False) -# first subsample -plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', color='blue', label='real bills period') +# First subsample +plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', + color='blue', label='real bills period') -# second subsample +# Second subsample plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') +plt.plot(a2_rev + b2_rev * infl[31:44], infl[31:44], color='red') -# third subsample -plt.plot(bal[44:63], infl[44:63], '*', color='orange', label='classic Cagan hyperinflation') -plt.plot(a3_rev + b3_rev * infl[44:63], infl[44:63], color='orange') +# Third subsample +plt.plot(bal[44:63], infl[44:63], '*', + color='orange', label='classic Cagan hyperinflation') plt.xlabel('real balances') plt.ylabel('inflation') @@ -760,272 +886,105 @@ plt.legend() plt.tight_layout() plt.show() -#plt.savefig('frfinfig7_line3_rev.pdf', dpi=600) ``` - -## Figure 8 - - -```{code-cell} ipython3 ---- -mystnb: - figure: - caption: "Real balances of assignats (in gold and goods)" - name: fig8 ---- -# Read the data from Excel file -data7 = pd.read_excel('datasets/assignat.xlsx', sheet_name='Data', usecols='P:Q', skiprows=4, nrows=80, header=None) -data7a = pd.read_excel('datasets/assignat.xlsx', sheet_name='Data', usecols='L', skiprows=4, nrows=80, header=None) - -# Create the figure and plot -plt.figure() -h = plt.plot(pd.date_range(start='1789-11-01', periods=len(data7), freq='M'), (data7a.values * [1, 1]) * data7.values, linewidth=1.) -plt.setp(h[1], linestyle='--', color='red') - -plt.vlines([pd.Timestamp('1793-07-15'), pd.Timestamp('1793-07-15')], 0, 3000, linewidth=0.8, color='orange') -plt.vlines([pd.Timestamp('1794-07-15'), pd.Timestamp('1794-07-15')], 0, 3000, linewidth=0.8, color='purple') - -plt.ylim([0, 3000]) - -# Set properties of the plot -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) -plt.gca().set_facecolor('white') -plt.gca().tick_params(labelsize=12) -plt.xlim(pd.Timestamp('1789-11-01'), pd.Timestamp('1796-06-01')) -plt.ylabel('millions of livres', fontsize=12) - -# Add text annotations -plt.text(pd.Timestamp('1793-09-01'), 200, 'Terror', fontsize=12) -plt.text(pd.Timestamp('1791-05-01'), 750, 'gold value', fontsize=12) -plt.text(pd.Timestamp('1794-10-01'), 2500, 'real value', fontsize=12) +The regression line in {numref}`fr_fig104d` shows that large increases in real balances of +assignats (paper money) were accompanied by little upward price level pressure, even some declines in prices. +This reflects how well legal restrictions -- financial repression -- was working during the period of the Terror. -plt.tight_layout() -plt.show() +But the Terror ended in July 1794. That unleashed a big inflation as people tried to find other ways to transact and store values. -# Save the figure as a PDF -#plt.savefig('frfinfig8.pdf', dpi=600) -``` +The following two graphs are for the classical hyperinflation period. -TO TEACH TOM: By staring at {numref}`fig8` carefully +One regresses inflation on real balances, the other regresses real balances on inflation. - -## Figure 9 - +Both show a prounced inverse relationship that is the hallmark of the hyperinflations studied by +Cagan {cite}`Cagan`. ```{code-cell} ipython3 --- mystnb: figure: - caption: "Price Level and Price of Gold (log scale)" - name: fig9 + caption: Inflation and Real Balances + name: fr_fig104e --- -# Create the figure and plot plt.figure() -x = np.arange(1789 + 10/12, 1796 + 5/12, 1/12) -h, = plt.plot(x, 1. / data7.iloc[:, 0], linestyle='--') -h, = plt.plot(x, 1. / data7.iloc[:, 1], color='r') - -# Set properties of the plot -plt.gca().tick_params(labelsize=12) -plt.yscale('log') -plt.xlim([1789 + 10/12, 1796 + 5/12]) plt.gca().spines['top'].set_visible(False) plt.gca().spines['right'].set_visible(False) -# Add vertical lines -plt.axvline(x=1793 + 6.5/12, linestyle='-', linewidth=0.8, color='orange') -plt.axvline(x=1794 + 6.5/12, linestyle='-', linewidth=0.8, color='purple') +# First subsample +plt.plot(bal[1:31], infl[1:31], 'o', markerfacecolor='none', + color='blue', label='real bills period') -# Add text -plt.text(1793.75, 120, 'Terror', fontsize=12) -plt.text(1795, 2.8, 'price level', fontsize=12) -plt.text(1794.9, 40, 'gold', fontsize=12) +# Second subsample +plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') + +# Third subsample +plt.plot(bal[44:63], infl[44:63], '*', + color='orange', label='classic Cagan hyperinflation') +plt.plot(bal[44:63], a3 + bal[44:63] * b3, color='orange') +plt.xlabel('real balances') +plt.ylabel('inflation') +plt.legend() plt.tight_layout() plt.show() -#plt.savefig('frfinfig9.pdf', dpi=600) ``` -TO TEACH TOM: By staring at {numref}`fig9` carefully - - -## Figure 11 - - - +{numref}`fr_fig104e` shows the results of regressing inflation on real balances during the +period of the hyperinflation. ```{code-cell} ipython3 --- mystnb: figure: - caption: "Spending (blue) and Revenues (orange), (real values)" - name: fig11 + caption: Inflation and Real Balances + name: fr_fig104f --- -# Read data from Excel file -data11 = pd.read_excel('datasets/assignat.xlsx', sheet_name='Budgets', usecols='J:K', skiprows=22, nrows=52, header=None) - -# Prepare the x-axis data -x_data = np.concatenate([ - np.arange(1791, 1794 + 8/12, 1/12), - np.arange(1794 + 9/12, 1795 + 3/12, 1/12) -]) - -# Remove NaN values from the data -data11_clean = data11.dropna() - -# Plot the data plt.figure() -h = plt.plot(x_data, data11_clean.values[:, 0], linewidth=0.8) -h = plt.plot(x_data, data11_clean.values[:, 1], '--', linewidth=0.8) - - - -# Set plot properties plt.gca().spines['top'].set_visible(False) plt.gca().spines['right'].set_visible(False) -plt.gca().set_facecolor('white') -plt.gca().tick_params(axis='both', which='major', labelsize=12) -plt.xlim([1791, 1795 + 3/12]) -plt.xticks(np.arange(1791, 1796)) -plt.yticks(np.arange(0, 201, 20)) - -# Set the y-axis label -plt.ylabel('millions of livres', fontsize=12) +# First subsample +plt.plot(bal[1:31], infl[1:31], 'o', + markerfacecolor='none', color='blue', label='real bills period') +# Second subsample +plt.plot(bal[31:44], infl[31:44], '+', color='red', label='terror') -plt.tight_layout() -plt.show() - -#plt.savefig('frfinfig11.pdf', dpi=600) -``` -TO TEACH TOM: By staring at {numref}`fig11` carefully - - -## Figure 12 - - -```{code-cell} ipython3 -# Read data from Excel file -data12 = pd.read_excel('datasets/assignat.xlsx', sheet_name='seignor', usecols='F', skiprows=6, nrows=75, header=None).squeeze() - - -# Create a figure and plot the data -plt.figure() -plt.plot(pd.date_range(start='1790', periods=len(data12), freq='M'), data12, linewidth=0.8) - -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) - -plt.axhline(y=472.42/12, color='r', linestyle=':') -plt.xticks(ticks=pd.date_range(start='1790', end='1796', freq='AS'), labels=range(1790, 1797)) -plt.xlim(pd.Timestamp('1791'), pd.Timestamp('1796-02') + pd.DateOffset(months=2)) -plt.ylabel('millions of livres', fontsize=12) -plt.text(pd.Timestamp('1793-11'), 39.5, 'revenues in 1788', verticalalignment='top', fontsize=12) - - -plt.tight_layout() -plt.show() - -#plt.savefig('frfinfig12.pdf', dpi=600) -``` - - -## Figure 13 - - -```{code-cell} ipython3 -# Read data from Excel file -data13 = pd.read_excel('datasets/assignat.xlsx', sheet_name='Exchge', usecols='P:T', skiprows=3, nrows=502, header=None) - -# Plot the last column of the data -plt.figure() -plt.plot(data13.iloc[:, -1], linewidth=0.8) - -# Set properties of the plot -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) -plt.gca().set_xlim([1, len(data13)]) - -# Set x-ticks and x-tick labels -ttt = np.arange(1, len(data13) + 1) -plt.xticks(ttt[~np.isnan(data13.iloc[:, 0])], - ['Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'Jan', 'Feb', - 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep']) - -# Add text to the plot -plt.text(1, 120, '1795', fontsize=12, ha='center') -plt.text(262, 120, '1796', fontsize=12, ha='center') - -# Draw a horizontal line and add text -plt.axhline(y=186.7, color='red', linestyle='-', linewidth=0.8) -plt.text(150, 190, 'silver parity', fontsize=12) - -# Add an annotation with an arrow -plt.annotate('end of the assignat', xy=(340, 172), xytext=(380, 160), - arrowprops=dict(facecolor='black', arrowstyle='->'), fontsize=12) +# Third subsample +plt.plot(bal[44:63], infl[44:63], '*', + color='orange', label='classic Cagan hyperinflation') +plt.plot(a3_rev + b3_rev * infl[44:63], infl[44:63], color='orange') +plt.xlabel('real balances') +plt.ylabel('inflation') +plt.legend() plt.tight_layout() plt.show() -#plt.savefig('frfinfig13.pdf', dpi=600) ``` - -## Figure 14 - +{numref}`fr_fig104e` shows the results of regressing real money balances on inflation during the +period of the hyperinflation. -```{code-cell} ipython3 -# figure 14 -data14 = pd.read_excel('datasets/assignat.xlsx', sheet_name='Post-95', usecols='I', skiprows=9, nrows=91, header=None).squeeze() -data14a = pd.read_excel('datasets/assignat.xlsx', sheet_name='Post-95', usecols='F', skiprows=100, nrows=151, header=None).squeeze() +## Hyperinflation Ends -plt.figure() -h = plt.plot(data14, '*-', markersize=2, linewidth=0.8) -plt.plot(np.concatenate([np.full(data14.shape, np.nan), data14a]), linewidth=0.8) -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) -plt.gca().set_xticks(range(20, 237, 36)) -plt.gca().set_xticklabels(range(1796, 1803)) -plt.xlabel('*: Before the 2/3 bankruptcy') -plt.ylabel('Francs') +{cite}`sargent_velde1995` tell how in 1797 the Revolutionary government abruptly ended the inflation by -plt.tight_layout() -plt.show() -#plt.savefig('frfinfig14.pdf', dpi=600) -``` + * repudiating 2/3 of the national debt, and thereby + * eliminating the net-of-interest government defict + * no longer printing money, but instead + * using gold and silver coins as money - -## Figure 15 - +In 1799, Napoleon Bonaparte became first consul and for the next 15 years used resources confiscated from conquered territories to help pay for French government expenditures. -```{code-cell} ipython3 -# figure 15 -data15 = pd.read_excel('datasets/assignat.xlsx', sheet_name='Post-95', usecols='N', skiprows=4, nrows=88, header=None).squeeze() - -plt.figure() -h = plt.plot(range(2, 90), data15, '*-', linewidth=0.8) -plt.setp(h, markersize=2) -plt.gca().spines['top'].set_visible(False) -plt.gca().spines['right'].set_visible(False) -plt.text(47.5, 11.4, '17 brumaire', horizontalalignment='left', fontsize=12) -plt.text(49.5, 14.75, '19 brumaire', horizontalalignment='left', fontsize=12) -plt.text(15, -1, 'Vendémiaire 8', fontsize=12, horizontalalignment='center') -plt.text(45, -1, 'Brumaire', fontsize=12, horizontalalignment='center') -plt.text(75, -1, 'Frimaire', fontsize=12, horizontalalignment='center') -plt.ylim([0, 25]) -plt.xticks([], []) -plt.ylabel('Francs') +## Underlying Theories -plt.tight_layout() -plt.show() -#plt.savefig('frfinfig15.pdf', dpi=600) -``` +This lecture sets the stage for studying theories of inflation and the government monetary and fiscal policies that bring it about. -```{code-cell} ipython3 +A *monetarist theory of the price level* is described in this quantecon lecture {doc}`cagan_ree`. -``` +That lecture sets the stage for these quantecon lectures {doc}`money_inflation` and {doc}`unpleasant`. diff --git a/lectures/geom_series.md b/lectures/geom_series.md index 7a7d4c9dc..e33ed5c47 100644 --- a/lectures/geom_series.md +++ b/lectures/geom_series.md @@ -25,12 +25,6 @@ kernelspec: # Geometric Series for Elementary Economics -```{admonition} Migrated lecture -:class: warning - -This lecture has moved from our [Intermediate Quantitative Economics with Python](https://python.quantecon.org/intro.html) lecture series and is now a part of [A First Course in Quantitative Economics](https://intro.quantecon.org/intro.html). -``` - ## Overview The lecture describes important ideas in economics that use the mathematics of geometric series. @@ -53,7 +47,6 @@ These and other applications prove the truth of the wise crack that Below we'll use the following imports: ```{code-cell} ipython -%matplotlib inline import matplotlib.pyplot as plt plt.rcParams["figure.figsize"] = (11, 5) #set default figure size import numpy as np @@ -112,9 +105,12 @@ $$ 1 + c + c^2 + c^3 + \cdots + c^T = \frac{1 - c^{T+1}}{1-c} $$ -**Remark:** The above formula works for any value of the scalar +```{prf:remark} +:label: geom_formula +The above formula works for any value of the scalar $c$. We don't have to restrict $c$ to be in the set $(-1,1)$. +``` We now move on to describe some famous economic applications of geometric series. @@ -765,7 +761,7 @@ T_max = 10 T=np.arange(0, T_max+1) rs, gs = (0.9, 0.5, 0.4001, 0.4), (0.4, 0.4, 0.4, 0.5), -comparisons = ('$\gg$', '$>$', r'$\approx$', '$<$') +comparisons = (r'$\gg$', '$>$', r'$\approx$', '$<$') for r, g, comp in zip(rs, gs, comparisons): ax.plot(finite_lease_pv_true(T, g, r, x_0), label=f'r(={r}) {comp} g(={g})') diff --git a/lectures/greek_square.md b/lectures/greek_square.md new file mode 100644 index 000000000..ee34e1def --- /dev/null +++ b/lectures/greek_square.md @@ -0,0 +1,800 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Computing Square Roots + + +## Introduction + +Chapter 24 of {cite}`russell2004history` about early Greek mathematics and astronomy contains this +fascinating passage: + + ```{epigraph} + The square root of 2, which was the first irrational to be discovered, was known to the early Pythagoreans, and ingenious methods of approximating to its value were discovered. The best was as follows: Form two columns of numbers, which we will call the $a$'s and the $b$'s; each starts with a $1$. The next $a$, at each stage, is formed by adding the last $a$ and the $b$ already obtained; the next $b$ is formed by adding twice the previous $a$ to the previous $b$. The first 6 pairs so obtained are $(1,1), (2,3), (5,7), (12,17), (29,41), (70,99)$. In each pair, $2 a^2 - b^2$ is $1$ or $-1$. Thus $b/a$ is nearly the square root of two, and at each fresh step it gets nearer. For instance, the reader may satisy himself that the square of $99/70$ is very nearly equal to $2$. + ``` + +This lecture drills down and studies this ancient method for computing square roots by using some of the matrix algebra that we've learned in earlier quantecon lectures. + +In particular, this lecture can be viewed as a sequel to {doc}`eigen_I`. + +It provides an example of how eigenvectors isolate *invariant subspaces* that help construct and analyze solutions of linear difference equations. + +When vector $x_t$ starts in an invariant subspace, iterating the different equation keeps $x_{t+j}$ +in that subspace for all $j \geq 1$. + +Invariant subspace methods are used throughout applied economic dynamics, for example, in the lecture {doc}`money_inflation`. + +Our approach here is to illustrate the method with an ancient example, one that ancient Greek mathematicians used to compute square roots of positive integers. + +## Perfect squares and irrational numbers + +An integer is called a **perfect square** if its square root is also an integer. + +An ordered sequence of perfect squares starts with + +$$ +4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, \ldots +$$ + +If an integer is not a perfect square, then its square root is an irrational number -- i.e., it cannot be expressed as a ratio of two integers, and its decimal expansion is indefinite. + +The ancient Greeks invented an algorithm to compute square roots of integers, including integers that are not perfect squares. + +Their method involved + + * computing a particular sequence of integers $\{y_t\}_{t=0}^\infty$; + + * computing $\lim_{t \rightarrow \infty} \left(\frac{y_{t+1}}{y_t}\right) = \bar r$; + + * deducing the desired square root from $\bar r$. + +In this lecture, we'll describe this method. + +We'll also use invariant subspaces to describe variations on this method that are faster. + +## Second-order linear difference equations + +Before telling how the ancient Greeks computed square roots, we'll provide a quick introduction +to second-order linear difference equations. + +We'll study the following second-order linear difference equation + +$$ +y_t = a_1 y_{t-1} + a_2 y_{t-2}, \quad t \geq 0 +$$ (eq:2diff1) + +where $(y_{-1}, y_{-2})$ is a pair of given initial conditions. + +Equation {eq}`eq:2diff1` is actually an infinite number of linear equations in the sequence +$\{y_t\}_{t=0}^\infty$. + +There is one equation each for $t = 0, 1, 2, \ldots$. + +We could follow an approach taken in the lecture on {doc}`present values` and stack all of these equations into a single matrix equation that we would then solve by using matrix inversion. + +```{note} +In the present instance, the matrix equation would multiply a countably infinite dimensional square matrix by a countably infinite dimensional vector. With some qualifications, matrix multiplication and inversion tools apply to such an equation. +``` + +But we won't pursue that approach here. + + +Instead, we'll seek to find a time-invariant function that *solves* our difference equation, meaning +that it provides a formula for a $\{y_t\}_{t=0}^\infty$ sequence that satisfies +equation {eq}`eq:2diff1` for each $t \geq 0$. + +We seek an expression for $y_t, t \geq 0$ as functions of the initial conditions $(y_{-1}, y_{-2})$: + +$$ +y_t = g((y_{-1}, y_{-2});t), \quad t \geq 0. +$$ (eq:2diff2) + +We call such a function $g$ a *solution* of the difference equation {eq}`eq:2diff1`. + +One way to discover a solution is to use a guess and verify method. + +We shall begin by considering a special initial pair of initial conditions +that satisfy + +$$ +y_{-1} = \delta y_{-2} +$$ (eq:2diff3) + +where $\delta$ is a scalar to be determined. + +For initial condition that satisfy {eq}`eq:2diff3` +equation {eq}`eq:2diff1` impllies that + +$$ +y_0 = \left(a_1 + \frac{a_2}{\delta}\right) y_{-1}. +$$ (eq:2diff4) + +We want + +$$ +\left(a_1 + \frac{a_2}{\delta}\right) = \delta +$$ (eq:2diff5) + +which we can rewrite as the *characteristic equation* + +$$ +\delta^2 - a_1 \delta - a_2 = 0. +$$ (eq:2diff6) + +Applying the quadratic formula to solve for the roots of {eq}`eq:2diff6` we find that + +$$ +\delta = \frac{ a_1 \pm \sqrt{a_1^2 + 4 a_2}}{2}. +$$ (eq:2diff7) + +For either of the two $\delta$'s that satisfy equation {eq}`eq:2diff7`, +a solution of difference equation {eq}`eq:2diff1` is + +$$ +y_t = \delta^t y_0 , \forall t \geq 0 +$$ (eq:2diff8) + +provided that we set + +$$ +y_0 = \delta y_{-1} . +$$ + +The *general* solution of difference equation {eq}`eq:2diff1` takes the form + +$$ +y_t = \eta_1 \delta_1^t + \eta_2 \delta_2^t +$$ (eq:2diff9) + +where $\delta_1, \delta_2$ are the two solutions {eq}`eq:2diff7` of the characteristic equation {eq}`eq:2diff6`, and $\eta_1, \eta_2$ are two constants chosen to satisfy + +$$ + \begin{bmatrix} y_{-1} \cr y_{-2} \end{bmatrix} = \begin{bmatrix} \delta_1^{-1} & \delta_2^{-1} \cr \delta_1^{-2} & \delta_2^{-2} \end{bmatrix} \begin{bmatrix} \eta_1 \cr \eta_2 \end{bmatrix} +$$ (eq:2diff10) + +or + +$$ +\begin{bmatrix} \eta_1 \cr \eta_2 \end{bmatrix} = \begin{bmatrix} \delta_1^{-1} & \delta_2^{-1} \cr \delta_1^{-2} & \delta_2^{-2} \end{bmatrix}^{-1} \begin{bmatrix} y_{-1} \cr y_{-2} \end{bmatrix} +$$ (eq:2diff11) + +Sometimes we are free to choose the initial conditions $(y_{-1}, y_{-2})$, in which case we +use system {eq}`eq:2diff10` to find the associated $(\eta_1, \eta_2)$. + +If we choose $(y_{-1}, y_{-2})$ to set $(\eta_1, \eta_2) = (1, 0)$, then $y_t = \delta_1^t$ for all $t \geq 0$. + + +If we choose $(y_{-1}, y_{-2})$ to set $(\eta_1, \eta_2) = (0, 1)$, then $y_t = \delta_2^t$ for all $t \geq 0$. + +Soon we'll relate the preceding calculations to components an eigen decomposition of a transition matrix that represents difference equation {eq}`eq:2diff1` in a very convenient way. + +We'll turn to that after we describe how Ancient Greeks figured out how to compute square roots of positive integers that are not perfect squares. + + +## Algorithm of the Ancient Greeks + +Let $\sigma$ be a positive integer greater than $1$. + +So $\sigma \in {\mathcal I} \equiv \{2, 3, \ldots \}$. + +We want an algorithm to compute the square root of $\sigma \in {\mathcal I}$. + +If $\sqrt{\sigma} \in {\mathcal I}$, $\sigma $ is said to be a *perfect square*. + +If $\sqrt{\sigma} \not\in {\mathcal I}$, it turns out that it is irrational. + +Ancient Greeks used a recursive algorithm to compute square roots of integers that are not perfect squares. + +The algorithm iterates on a second-order linear difference equation in the sequence $\{y_t\}_{t=0}^\infty$: + +$$ +y_{t} = 2 y_{t-1} - (1 - \sigma) y_{t-2}, \quad t \geq 0 +$$ (eq:second_order) + +together with a pair of integers that are initial conditions for $y_{-1}, y_{-2}$. + +First, we'll deploy some techniques for solving the difference equations that are also deployed in {doc}`dynam:samuelson`. + +The characteristic equation associated with difference equation {eq}`eq:second_order` is + +$$ +c(x) \equiv x^2 - 2 x + (1 - \sigma) = 0 +$$ (eq:cha_eq0) + +(Notice how this is an instance of equation {eq}`eq:2diff6` above.) + +Factoring the right side of equation {eq}`eq:cha_eq0`, we obtain + +$$ +c(x)= (x - \lambda_1) (x-\lambda_2) = 0 +$$(eq:cha_eq) + + +where + +$$ +c(x) = 0 +$$ + +for $x = \lambda_1$ or $x = \lambda_2$. + +These two special values of $x$ are sometimes called zeros or roots of $c(x)$. + + +By applying the quadratic formula to solve for the roots the characteristic equation +{eq}`eq:cha_eq0`, we find that + +$$ +\lambda_1 = 1 + \sqrt{\sigma}, \quad \lambda_2 = 1 - \sqrt{\sigma}. +$$ (eq:secretweapon) + +Formulas {eq}`eq:secretweapon` indicate that $\lambda_1$ and $\lambda_2$ are each functions +of a single variable, namely, $\sqrt{\sigma}$, the object that we along with some Ancient Greeks want to compute. + +Ancient Greeks had an indirect way of exploiting this fact to compute square roots of a positive integer. + +They did this by starting from particular initial conditions $y_{-1}, y_{-2}$ and iterating on the difference equation {eq}`eq:second_order`. + + +Solutions of difference equation {eq}`eq:second_order` take the form + +$$ +y_t = \lambda_1^t \eta_1 + \lambda_2^t \eta_2 +$$ + +where $\eta_1$ and $\eta_2$ are chosen to satisfy prescribed initial conditions $y_{-1}, y_{-2}$: + +$$ +\begin{aligned} +\lambda_1^{-1} \eta_1 + \lambda_2^{-1} \eta_2 & = y_{-1} \cr +\lambda_1^{-2} \eta_1 + \lambda_2^{-2} \eta_2 & = y_{-2} +\end{aligned} +$$(eq:leq_sq) + +System {eq}`eq:leq_sq` of simultaneous linear equations will play a big role in the remainder of this lecture. + +Since $\lambda_1 = 1 + \sqrt{\sigma} > 1 > \lambda_2 = 1 - \sqrt{\sigma} $, +it follows that for *almost all* (but not all) initial conditions + +$$ +\lim_{t \rightarrow \infty} \left(\frac{y_{t+1}}{y_t}\right) = 1 + \sqrt{\sigma}. +$$ + +Thus, + +$$ +\sqrt{\sigma} = \lim_{t \rightarrow \infty} \left(\frac{y_{t+1}}{y_t}\right) - 1. +$$ + +However, notice that if $\eta_1 = 0$, then + +$$ +\lim_{t \rightarrow \infty} \left(\frac{y_{t+1}}{y_t}\right) = 1 - \sqrt{\sigma} +$$ + +so that + +$$ +\sqrt{\sigma} = 1 - \lim_{t \rightarrow \infty} \left(\frac{y_{t+1}}{y_t}\right). +$$ + +Actually, if $\eta_1 =0$, it follows that + +$$ +\sqrt{\sigma} = 1 - \left(\frac{y_{t+1}}{y_t}\right) \quad \forall t \geq 0, +$$ + +so that convergence is immediate and there is no need to take limits. + +Symmetrically, if $\eta_2 =0$, it follows that + + +$$ +\sqrt{\sigma} = \left(\frac{y_{t+1}}{y_t}\right) - 1 \quad \forall t \geq 0 +$$ + +so again, convergence is immediate, and we have no need to compute a limit. + + +System {eq}`eq:leq_sq` of simultaneous linear equations can be used in various ways. + + * we can take $y_{-1}, y_{-2}$ as given initial conditions and solve for $\eta_1, \eta_2$; + + * we can instead take $\eta_1, \eta_2$ as given and solve for initial conditions $y_{-1}, y_{-2}$. + +Notice how we used the second approach above when we set $\eta_1, \eta_2$ either to $(0, 1)$, for example, or $(1, 0)$, for example. + +In taking this second approach, we constructed an *invariant subspace* of ${\bf R}^2$. + +Here is what is going on. + +For $ t \geq 0$ and for most pairs of initial conditions $(y_{-1}, y_{-2}) \in {\bf R}^2$ for equation {eq}`eq:second_order`, $y_t$ can be expressed as a linear combination of $y_{t-1}$ and $y_{t-2}$. + +But for some special initial conditions $(y_{-1}, y_{-2}) \in {\bf R}^2$, $y_t$ can be expressed as a linear function of $y_{t-1}$ only. + +These special initial conditions require that $y_{-1}$ be a linear function of $y_{-2}$. + +We'll study these special initial conditions soon. + +But first let's write some Python code to iterate on equation {eq}`eq:second_order` starting from an arbitrary $(y_{-1}, y_{-2}) \in {\bf R}^2$. + +## Implementation + +We now implement the above algorithm to compute the square root of $\sigma$. + +In this lecture, we use the following import: + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +``` + +```{code-cell} ipython3 +def solve_λs(coefs): + # Calculate the roots using numpy.roots + λs = np.roots(coefs) + + # Sort the roots for consistency + return sorted(λs, reverse=True) + +def solve_η(λ_1, λ_2, y_neg1, y_neg2): + # Solve the system of linear equation + A = np.array([ + [1/λ_1, 1/λ_2], + [1/(λ_1**2), 1/(λ_2**2)] + ]) + b = np.array((y_neg1, y_neg2)) + ηs = np.linalg.solve(A, b) + + return ηs + +def solve_sqrt(σ, coefs, y_neg1, y_neg2, t_max=100): + # Ensure σ is greater than 1 + if σ <= 1: + raise ValueError("σ must be greater than 1") + + # Characteristic roots + λ_1, λ_2 = solve_λs(coefs) + + # Solve for η_1 and η_2 + η_1, η_2 = solve_η(λ_1, λ_2, y_neg1, y_neg2) + + # Compute the sequence up to t_max + t = np.arange(t_max + 1) + y = (λ_1 ** t) * η_1 + (λ_2 ** t) * η_2 + + # Compute the ratio y_{t+1} / y_t for large t + sqrt_σ_estimate = (y[-1] / y[-2]) - 1 + + return sqrt_σ_estimate + +# Use σ = 2 as an example +σ = 2 + +# Encode characteristic equation +coefs = (1, -2, (1 - σ)) + +# Solve for the square root of σ +sqrt_σ = solve_sqrt(σ, coefs, y_neg1=2, y_neg2=1) + +# Calculate the deviation +dev = abs(sqrt_σ-np.sqrt(σ)) +print(f"sqrt({σ}) is approximately {sqrt_σ:.5f} (error: {dev:.5f})") +``` + +Now we consider cases where $(\eta_1, \eta_2) = (0, 1)$ and $(\eta_1, \eta_2) = (1, 0)$ + +```{code-cell} ipython3 +# Compute λ_1, λ_2 +λ_1, λ_2 = solve_λs(coefs) +print(f'Roots for the characteristic equation are ({λ_1:.5f}, {λ_2:.5f}))') +``` + +```{code-cell} ipython3 +# Case 1: η_1, η_2 = (0, 1) +ηs = (0, 1) + +# Compute y_{t} and y_{t-1} with t >= 0 +y = lambda t, ηs: (λ_1 ** t) * ηs[0] + (λ_2 ** t) * ηs[1] +sqrt_σ = 1 - y(1, ηs) / y(0, ηs) + +print(f"For η_1, η_2 = (0, 1), sqrt_σ = {sqrt_σ:.5f}") +``` + +```{code-cell} ipython3 +# Case 2: η_1, η_2 = (1, 0) +ηs = (1, 0) +sqrt_σ = y(1, ηs) / y(0, ηs) - 1 + +print(f"For η_1, η_2 = (1, 0), sqrt_σ = {sqrt_σ:.5f}") +``` + +We find that convergence is immediate. + +Next, we'll represent the preceding analysis by first vectorizing our second-order difference equation {eq}`eq:second_order` and then using eigendecompositions of an associated state transition matrix. + +## Vectorizing the difference equation + + +Represent {eq}`eq:second_order` with the first-order matrix difference equation + +$$ +\begin{bmatrix} y_{t+1} \cr y_{t} \end{bmatrix} += \begin{bmatrix} 2 & - ( 1 - \sigma) \cr 1 & 0 \end{bmatrix} \begin{bmatrix} y_{t} \cr y_{t-1} \end{bmatrix} +$$ + +or + +$$ +x_{t+1} = M x_t +$$ + +where + +$$ +M = \begin{bmatrix} 2 & - (1 - \sigma ) \cr 1 & 0 \end{bmatrix}, \quad x_t= \begin{bmatrix} y_{t} \cr y_{t-1} \end{bmatrix} +$$ + +Construct an eigendecomposition of $M$: + +$$ +M = V \begin{bmatrix} \lambda_1 & 0 \cr 0 & \lambda_2 \end{bmatrix} V^{-1} +$$ (eq:eigen_sqrt) + +where columns of $V$ are eigenvectors corresponding to eigenvalues $\lambda_1$ and $\lambda_2$. + +The eigenvalues can be ordered so that $\lambda_1 > 1 > \lambda_2$. + +Write equation {eq}`eq:second_order` as + +$$ +x_{t+1} = V \Lambda V^{-1} x_t +$$ + +Now we implement the algorithm above. + +First we write a function that iterates $M$ + +```{code-cell} ipython3 +def iterate_M(x_0, M, num_steps, dtype=np.float64): + + # Eigendecomposition of M + Λ, V = np.linalg.eig(M) + V_inv = np.linalg.inv(V) + + # Initialize the array to store results + xs = np.zeros((x_0.shape[0], + num_steps + 1)) + + # Perform the iterations + xs[:, 0] = x_0 + for t in range(num_steps): + xs[:, t + 1] = M @ xs[:, t] + + return xs, Λ, V, V_inv + +# Define the state transition matrix M +M = np.array([ + [2, -(1 - σ)], + [1, 0]]) + +# Initial condition vector x_0 +x_0 = np.array([2, 2]) + +# Perform the iteration +xs, Λ, V, V_inv = iterate_M(x_0, M, num_steps=100) + +print(f"eigenvalues:\n{Λ}") +print(f"eigenvectors:\n{V}") +print(f"inverse eigenvectors:\n{V_inv}") +``` + +Let's compare the eigenvalues to the roots {eq}`eq:secretweapon` of equation +{eq}`eq:cha_eq0` that we computed above. + +```{code-cell} ipython3 +roots = solve_λs((1, -2, (1 - σ))) +print(f"roots: {np.round(roots, 8)}") +``` + +Hence we confirmed {eq}`eq:eigen_sqrt`. + +Information about the square root we are after is also contained +in the two eigenvectors. + +Indeed, each eigenvector is just a two-dimensional subspace of ${\mathbb R}^3$ pinned down by dynamics of the form + +$$ +y_{t} = \lambda_i y_{t-1}, \quad i = 1, 2 +$$ (eq:invariantsub101) + +that we encountered above in equation {eq}`eq:2diff8` above. + +In equation {eq}`eq:invariantsub101`, the $i$th $\lambda_i$ equals the $V_{i, 1}/V_{i,2}$. + +The following graph verifies this for our example. + +```{code-cell} ipython3 +:tags: [hide-input] + +# Plotting the eigenvectors +plt.figure(figsize=(8, 8)) + +plt.quiver(0, 0, V[0, 0], V[1, 0], angles='xy', scale_units='xy', + scale=1, color='C0', label=fr'$\lambda_1={np.round(Λ[0], 4)}$') +plt.quiver(0, 0, V[0, 1], V[1, 1], angles='xy', scale_units='xy', + scale=1, color='C1', label=fr'$\lambda_2={np.round(Λ[1], 4)}$') + +# Annotating the slopes +plt.text(V[0, 0]-0.5, V[1, 0]*1.2, + r'slope=$\frac{V_{1,1}}{V_{1,2}}=$'+f'{np.round(V[0, 0] / V[1, 0], 4)}', + fontsize=12, color='C0') +plt.text(V[0, 1]-0.5, V[1, 1]*1.2, + r'slope=$\frac{V_{2,1}}{V_{2,2}}=$'+f'{np.round(V[0, 1] / V[1, 1], 4)}', + fontsize=12, color='C1') + +# Adding labels +plt.axhline(0, color='grey', linewidth=0.5, alpha=0.4) +plt.axvline(0, color='grey', linewidth=0.5, alpha=0.4) +plt.legend() + +plt.xlim(-1.5, 1.5) +plt.ylim(-1.5, 1.5) +plt.show() +``` + +## Invariant subspace approach + +The preceding calculation indicates that we can use the eigenvectors $V$ to construct 2-dimensional *invariant subspaces*. + +We'll pursue that possibility now. + +Define the transformed variables + + +$$ +x_t^* = V^{-1} x_t +$$ + +Evidently, we can recover $x_t$ from $x_t^*$: + +$$ +x_t = V x_t^* +$$ + + +The following notations and equations will help us. + +Let + +$$ + +V = \begin{bmatrix} V_{1,1} & V_{1,2} \cr + V_{2,1} & V_{2,2} \end{bmatrix}, \quad +V^{-1} = \begin{bmatrix} V^{1,1} & V^{1,2} \cr + V^{2,1} & V^{2,2} \end{bmatrix} +$$ + +Notice that it follows from + +$$ + \begin{bmatrix} V^{1,1} & V^{1,2} \cr + V^{2,1} & V^{2,2} \end{bmatrix} \begin{bmatrix} V_{1,1} & V_{1,2} \cr + V_{2,1} & V_{2,2} \end{bmatrix} = \begin{bmatrix} 1 & 0 \cr 0 & 1 \end{bmatrix} +$$ + +that + +$$ +V^{2,1} V_{1,1} + V^{2,2} V_{2,1} = 0 +$$ + +and + +$$ +V^{1,1}V_{1,2} + V^{1,2} V_{2,2} = 0. +$$ + +These equations will be very useful soon. + + +Notice that + +$$ +\begin{bmatrix} x_{1,t+1}^* \cr x_{2,t+1}^* \end{bmatrix} = \begin{bmatrix} \lambda_1 & 0 \cr 0 & \lambda_2 \end{bmatrix} +\begin{bmatrix} x_{1,t}^* \cr x_{2,t}^* \end{bmatrix} +$$ + +To deactivate $\lambda_1$ we want to set + +$$ +x_{1,0}^* = 0. +$$ + + +This can be achieved by setting + +$$ +x_{2,0} = -( V^{1,2})^{-1} V^{1,1} x_{1,0} = V_{2,2} V_{1,2}^{-1} x_{1,0}. +$$ (eq:deactivate1) + +To deactivate $\lambda_2$, we want to set + +$$ +x_{2,0}^* = 0 +$$ + +This can be achieved by setting + +$$ +x_{2,0} = -(V^{2,2})^{-1} V^{2,1} x_{1,0} = V_{2,1} V_{1,1}^{-1} x_{1,0}. +$$ (eq:deactivate2) + +Let's verify {eq}`eq:deactivate1` and {eq}`eq:deactivate2` below + +To deactivate $\lambda_1$ we use {eq}`eq:deactivate1` + +```{code-cell} ipython3 +xd_1 = np.array((x_0[0], + V[1,1]/V[0,1] * x_0[0]), + dtype=np.float64) + +# Compute x_{1,0}^* +np.round(V_inv @ xd_1, 8) +``` + +We find $x_{1,0}^* = 0$. + +Now we deactivate $\lambda_2$ using {eq}`eq:deactivate2` + +```{code-cell} ipython3 +xd_2 = np.array((x_0[0], + V[1,0]/V[0,0] * x_0[0]), + dtype=np.float64) + +# Compute x_{2,0}^* +np.round(V_inv @ xd_2, 8) +``` + +We find $x_{2,0}^* = 0$. + +```{code-cell} ipython3 +# Simulate with muted λ1 λ2. +num_steps = 10 +xs_λ1 = iterate_M(xd_1, M, num_steps)[0] +xs_λ2 = iterate_M(xd_2, M, num_steps)[0] + +# Compute ratios y_t / y_{t-1} +ratios_λ1 = xs_λ1[1, 1:] / xs_λ1[1, :-1] +ratios_λ2 = xs_λ2[1, 1:] / xs_λ2[1, :-1] +``` + +The following graph shows the ratios $y_t / y_{t-1}$ for the two cases. + +We find that the ratios converge to $\lambda_2$ in the first case and $\lambda_1$ in the second case. + +```{code-cell} ipython3 +:tags: [hide-input] + +# Plot the ratios for y_t / y_{t-1} +fig, axs = plt.subplots(1, 2, figsize=(12, 6), dpi=500) + +# First subplot +axs[0].plot(np.round(ratios_λ1, 6), + label=r'$\frac{y_t}{y_{t-1}}$', linewidth=3) +axs[0].axhline(y=Λ[1], color='red', linestyle='--', + label=r'$\lambda_2$', alpha=0.5) +axs[0].set_xlabel('t', size=18) +axs[0].set_ylabel(r'$\frac{y_t}{y_{t-1}}$', size=18) +axs[0].set_title(r'$\frac{y_t}{y_{t-1}}$ after Muting $\lambda_1$', + size=13) +axs[0].legend() + +# Second subplot +axs[1].plot(ratios_λ2, label=r'$\frac{y_t}{y_{t-1}}$', + linewidth=3) +axs[1].axhline(y=Λ[0], color='green', linestyle='--', + label=r'$\lambda_1$', alpha=0.5) +axs[1].set_xlabel('t', size=18) +axs[1].set_ylabel(r'$\frac{y_t}{y_{t-1}}$', size=18) +axs[1].set_title(r'$\frac{y_t}{y_{t-1}}$ after Muting $\lambda_2$', + size=13) +axs[1].legend() + +plt.tight_layout() +plt.show() +``` + +## Concluding remarks + +This lecture sets the stage for many other applications of the *invariant subspace* methods. + +All of these exploit very similar equations based on eigen decompositions. + +We shall encounter equations very similar to {eq}`eq:deactivate1` and {eq}`eq:deactivate2` +in {doc}`money_inflation` and in many other places in dynamic economic theory. + + +## Exercise + +```{exercise-start} +:label: greek_square_ex_a +``` +Please use matrix algebra to formulate the method described by Bertrand Russell at the beginning of this lecture. + +1. Define a state vector $x_t = \begin{bmatrix} a_t \cr b_t \end{bmatrix}$. +2. Formulate a first-order vector difference equation for $x_t$ of the form $x_{t+1} = A x_t$ and +compute the matrix $A$. +3. Use the system $x_{t+1} = A x_t$ to replicate the sequence of $a_t$'s and $b_t$'s described by Bertrand Russell. +4. Compute the eigenvectors and eigenvalues of $A$ and compare them to corresponding objects computed in the text of this lecture. + +```{exercise-end} +``` + +```{solution-start} greek_square_ex_a +:class: dropdown +``` + +Here is one soluition. + +According to the quote, we can formulate + +$$ +\begin{aligned} +a_{t+1} &= a_t + b_t \\ +b_{t+1} &= 2a_t + b_t +\end{aligned} +$$ (eq:gs_ex1system) + +with $x_0 = \begin{bmatrix} a_0 \cr b_0 \end{bmatrix} = \begin{bmatrix} 1 \cr 1 \end{bmatrix}$ + +By {eq}`eq:gs_ex1system`, we can write matrix $A$ as + +$$ +A = \begin{bmatrix} 1 & 1 \cr + 2 & 1 \end{bmatrix} +$$ + +Then $x_{t+1} = A x_t$ for $t \in \{0, \dots, 5\}$ + +```{code-cell} ipython3 +# Define the matrix A +A = np.array([[1, 1], + [2, 1]]) + +# Initial vector x_0 +x_0 = np.array([1, 1]) + +# Number of iterations +n = 6 + +# Generate the sequence +xs = np.array([x_0]) +x_t = x_0 +for _ in range(1, n): + x_t = A @ x_t + xs = np.vstack([xs, x_t]) + +# Print the sequence +for i, (a_t, b_t) in enumerate(xs): + print(f"Iter {i}: a_t = {a_t}, b_t = {b_t}") + +# Compute eigenvalues and eigenvectors of A +eigenvalues, eigenvectors = np.linalg.eig(A) + +print(f'\nEigenvalues:\n{eigenvalues}') +print(f'\nEigenvectors:\n{eigenvectors}') +``` + +```{solution-end} +``` diff --git a/lectures/heavy_tails.md b/lectures/heavy_tails.md index 639e6b1d1..6a27df318 100644 --- a/lectures/heavy_tails.md +++ b/lectures/heavy_tails.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.14.5 + jupytext_version: 1.16.7 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -19,7 +19,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie ```{code-cell} ipython3 :tags: [hide-output] -!pip install --upgrade yfinance pandas_datareader +!pip install --upgrade yfinance wbgapi ``` We use the following imports. @@ -31,7 +31,7 @@ import yfinance as yf import pandas as pd import statsmodels.api as sm -from pandas_datareader import wb +import wbgapi as wb from scipy.stats import norm, cauchy from pandas.plotting import register_matplotlib_converters register_matplotlib_converters() @@ -45,7 +45,7 @@ In the natural sciences (and in more traditional economics courses), heavy-taile However, it turns out that heavy-tailed distributions play a crucial role in economics. -In fact many -- if not most -- of the important distributions in economics are heavy tailed. +In fact many -- if not most -- of the important distributions in economics are heavy-tailed. In this lecture we explain what heavy tails are and why they are -- or at least why they should be -- central to economic analysis. @@ -58,13 +58,16 @@ the natural sciences have "light tails." To explain this concept, let's look first at examples. +```{prf:example} +:label: ht_ex_nd + The classic example is the [normal distribution](https://en.wikipedia.org/wiki/Normal_distribution), which has density $$ - f(x) = \frac{1}{\sqrt{2\pi}\sigma} - \exp\left( -\frac{(x-\mu)^2}{2 \sigma^2} \right) - \qquad - (-\infty < x < \infty) +f(x) = \frac{1}{\sqrt{2\pi}\sigma} +\exp\left( -\frac{(x-\mu)^2}{2 \sigma^2} \right) +\qquad +(-\infty < x < \infty) $$ @@ -73,11 +76,18 @@ respectively. As $x$ deviates from $\mu$, the value of $f(x)$ goes to zero extremely quickly. +``` We can see this when we plot the density and show a histogram of observations, as with the following code (which assumes $\mu=0$ and $\sigma=1$). ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Histogram of observations + name: hist-obs +--- fig, ax = plt.subplots() X = norm.rvs(size=1_000_000) ax.hist(X, bins=40, alpha=0.4, label='histogram', density=True) @@ -101,6 +111,12 @@ X.min(), X.max() Here's another view of draws from the same distribution: ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Histogram of observations + name: hist-obs2 +--- n = 2000 fig, ax = plt.subplots() data = norm.rvs(size=n) @@ -122,7 +138,7 @@ too much from the mean. Putting this another way, light-tailed distributions are those that rarely generate extreme values. -(A more formal definition is given [below](https://intro.quantecon.org/heavy_tails.html#light-and-heavy-tails).) +(A more formal definition is given {ref}`below `.) Many statisticians and econometricians use rules of thumb such as "outcomes more than four or five @@ -169,7 +185,19 @@ This equates to daily returns if we set dividends aside. The code below produces the desired plot using Yahoo financial data via the `yfinance` library. ```{code-cell} ipython3 -s = yf.download('AMZN', '2015-1-1', '2022-7-1')['Adj Close'] +:tags: [hide-output] + +data = yf.download('AMZN', '2015-1-1', '2022-7-1') +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Daily Amazon returns + name: dailyreturns-amzn +--- +s = data['Close'] r = s.pct_change() fig, ax = plt.subplots() @@ -189,7 +217,19 @@ Several of observations are quite extreme. We get a similar picture if we look at other assets, such as Bitcoin ```{code-cell} ipython3 -s = yf.download('BTC-USD', '2015-1-1', '2022-7-1')['Adj Close'] +:tags: [hide-output] + +data = yf.download('BTC-USD', '2015-1-1', '2022-7-1') +``` + +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Daily Bitcoin returns + name: dailyreturns-btc +--- +s = data['Close'] r = s.pct_change() fig, ax = plt.subplots() @@ -206,6 +246,12 @@ The histogram also looks different to the histogram of the normal distribution: ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Histogram (normal vs bitcoin returns) + name: hist-normal-btc +--- r = np.random.standard_t(df=5, size=1000) fig, ax = plt.subplots() @@ -214,7 +260,7 @@ ax.hist(r, bins=60, alpha=0.4, label='bitcoin returns', density=True) xmin, xmax = plt.xlim() x = np.linspace(xmin, xmax, 100) p = norm.pdf(x, np.mean(r), np.std(r)) -ax.plot(x, p, 'k', linewidth=2, label='normal distribution') +ax.plot(x, p, linewidth=2, label='normal distribution') ax.set_xlabel('returns', fontsize=12) ax.legend() @@ -235,6 +281,9 @@ The data we have just seen is said to be "heavy-tailed". With heavy-tailed distributions, extreme outcomes occur relatively frequently. +```{prf:example} +:label: ht_ex_od + Importantly, there are many examples of heavy-tailed distributions observed in economic and financial settings! @@ -250,6 +299,7 @@ The firm size distribution is also heavy-tailed The distribution of town and city sizes is heavy-tailed * Most towns and cities are small but some are very large. +``` Later in this lecture, we examine heavy tails in these distributions. @@ -266,11 +316,7 @@ like * forecasting * taxation (across a heavy-tailed income distribution), etc. -We return to these points [below](https://intro.quantecon.org/heavy_tails.html#why-do-heavy-tails-matter). - - - - +We return to these points {ref}`below `. ## Visual comparisons @@ -295,6 +341,12 @@ distribution](https://en.wikipedia.org/wiki/Cauchy_distribution), which is heavy-tailed. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Draws from normal and Cauchy distributions + name: draws-normal-cauchy +--- n = 120 np.random.seed(11) @@ -309,7 +361,7 @@ for ax, s in zip(axes[:2], s_vals): data = np.random.randn(n) * s ax.plot(list(range(n)), data, linestyle='', marker='o', alpha=0.5, ms=4) ax.vlines(list(range(n)), 0, data, lw=0.2) - ax.set_title(f"draws from $N(0, \sigma^2)$ with $\sigma = {s}$", fontsize=11) + ax.set_title(fr"draws from $N(0, \sigma^2)$ with $\sigma = {s}$", fontsize=11) ax = axes[2] distribution = cauchy() @@ -348,6 +400,12 @@ The exponential distribution is a light-tailed distribution. Here are some draws from the exponential distribution. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Draws of exponential distribution + name: draws-exponential +--- n = 120 np.random.seed(11) @@ -389,7 +447,9 @@ exponential random variable. In particular, if $X$ is exponentially distributed with rate parameter $\alpha$, then -$$ Y = \bar x \exp(X) $$ +$$ +Y = \bar x \exp(X) +$$ is Pareto-distributed with minimum $\bar x$ and tail index $\alpha$. @@ -397,6 +457,12 @@ Here are some draws from the Pareto distribution with tail index $1$ and minimum $1$. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Draws from Pareto distribution + name: draws-pareto +--- n = 120 np.random.seed(11) @@ -420,7 +486,9 @@ light and heavy tails is to look at the For a random variable $X$ with CDF $F$, the CCDF is the function -$$ G(x) := 1 - F(x) = \mathbb P\{X > x\} $$ +$$ +G(x) := 1 - F(x) = \mathbb P\{X > x\} +$$ (Some authors call $G$ the "survival" function.) @@ -428,13 +496,17 @@ The CCDF shows how fast the upper tail goes to zero as $x \to \infty$. If $X$ is exponentially distributed with rate parameter $\alpha$, then the CCDF is -$$ G_E(x) = \exp(- \alpha x) $$ +$$ +G_E(x) = \exp(- \alpha x) +$$ This function goes to zero relatively quickly as $x$ gets large. The standard Pareto distribution, where $\bar x = 1$, has CCDF -$$ G_P(x) = x^{- \alpha} $$ +$$ +G_P(x) = x^{- \alpha} +$$ This function goes to zero as $x \to \infty$, but much slower than $G_E$. @@ -466,11 +538,19 @@ $$ Here's a plot that illustrates how $G_E$ goes to zero faster than $G_P$. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Pareto and exponential distribution comparison + name: compare-pareto-exponential +--- x = np.linspace(1.5, 100, 1000) fig, ax = plt.subplots() alpha = 1.0 ax.plot(x, np.exp(- alpha * x), label='exponential', alpha=0.8) ax.plot(x, x**(- alpha), label='Pareto', alpha=0.8) +ax.set_xlabel('X value') +ax.set_ylabel('CCDF') ax.legend() plt.show() ``` @@ -479,10 +559,18 @@ Here's a log-log plot of the same functions, which makes visual comparison easier. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Pareto and exponential distribution comparison (log-log) + name: compare-pareto-exponential-log-log +--- fig, ax = plt.subplots() alpha = 1.0 ax.loglog(x, np.exp(- alpha * x), label='exponential', alpha=0.8) ax.loglog(x, x**(- alpha), label='Pareto', alpha=0.8) +ax.set_xlabel('log value') +ax.set_ylabel('log prob') ax.legend() plt.show() ``` @@ -500,28 +588,41 @@ The sample counterpart of the CCDF function is the **empirical CCDF**. Given a sample $x_1, \ldots, x_n$, the empirical CCDF is given by -$$ \hat G(x) = \frac{1}{n} \sum_{i=1}^n \mathbb 1\{x_i > x\} $$ +$$ +\hat G(x) = \frac{1}{n} \sum_{i=1}^n \mathbb 1\{x_i > x\} +$$ Thus, $\hat G(x)$ shows the fraction of the sample that exceeds $x$. -Here's a figure containing some empirical CCDFs from simulated data. - ```{code-cell} ipython3 def eccdf(x, data): "Simple empirical CCDF function." return np.mean(data > x) +``` + +Here's a figure containing some empirical CCDFs from simulated data. +```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Empirical CCDFs + name: ccdf-empirics +--- +# Parameters and grid x_grid = np.linspace(1, 1000, 1000) sample_size = 1000 np.random.seed(13) z = np.random.randn(sample_size) -data_1 = np.random.exponential(size=sample_size) -data_2 = np.exp(z) -data_3 = np.exp(np.random.exponential(size=sample_size)) +# Draws +data_exp = np.random.exponential(size=sample_size) +data_logn = np.exp(z) +data_pareto = np.exp(np.random.exponential(size=sample_size)) -data_list = [data_1, data_2, data_3] +data_list = [data_exp, data_logn, data_pareto] +# Build figure fig, axes = plt.subplots(3, 1, figsize=(6, 8)) axes = axes.flatten() labels = ['exponential', 'lognormal', 'Pareto'] @@ -546,6 +647,35 @@ approximately linear in a log-log plot. We will use this idea [below](https://intro.quantecon.org/heavy_tails.html#heavy-tails-in-economic-cross-sections) when we look at real data. ++++ + +#### Q-Q Plots + +We can also use a [qq plot](https://en.wikipedia.org/wiki/Q%E2%80%93Q_plot) to do a visual comparison between two probability distributions. + +The [statsmodels](https://www.statsmodels.org/stable/index.html) package provides a convenient [qqplot](https://www.statsmodels.org/stable/generated/statsmodels.graphics.gofplots.qqplot.html) function that, by default, compares sample data to the quintiles of the normal distribution. + +If the data is drawn from a normal distribution, the plot would look like: + +```{code-cell} ipython3 +data_normal = np.random.normal(size=sample_size) +sm.qqplot(data_normal, line='45') +plt.show() +``` + +We can now compare this with the exponential, log-normal, and Pareto distributions + +```{code-cell} ipython3 +# Build figure +fig, axes = plt.subplots(1, 3, figsize=(12, 4)) +axes = axes.flatten() +labels = ['exponential', 'lognormal', 'Pareto'] +for data, label, ax in zip(data_list, labels, axes): + sm.qqplot(data, line='45', ax=ax, ) + ax.set_title(label) +plt.tight_layout() +plt.show() +``` ### Power laws @@ -660,24 +790,21 @@ def empirical_ccdf(data, :tags: [hide-input] def extract_wb(varlist=['NY.GDP.MKTP.CD'], - c='all_countries', + c='all', s=1900, e=2021, varnames=None): - if c == "all_countries": - # Keep countries only (no aggregated regions) - countries = wb.get_countries() - countries_name = countries[countries['region'] != 'Aggregates']['name'].values - c = "all" - df = wb.download(indicator=varlist, country=c, start=s, end=e).stack().unstack(0).reset_index() - df = df.drop(['level_1'], axis=1).transpose() + df = wb.data.DataFrame(varlist, economy=c, time=range(s, e+1, 1), skipAggs=True) + df.index.name = 'country' + if varnames is not None: - df.columns = varnames - df = df[1:] + df.columns = variable_names + + cntry_mapper = pd.DataFrame(wb.economy.info().items)[['id','value']].set_index('id').to_dict()['value'] + df.index = df.index.map(lambda x: cntry_mapper[x]) #map iso3c to name values - df1 =df[df.index.isin(countries_name)] - return df1 + return df ``` ### Firm size @@ -685,8 +812,13 @@ def extract_wb(varlist=['NY.GDP.MKTP.CD'], Here is a plot of the firm size distribution for the largest 500 firms in 2020 taken from Forbes Global 2000. ```{code-cell} ipython3 -:tags: [hide-input] - +--- +mystnb: + figure: + caption: Firm size distribution + name: firm-size-dist +tags: [hide-input] +--- df_fs = pd.read_csv('https://media.githubusercontent.com/media/QuantEcon/high_dim_data/main/cross_section/forbes-global2000.csv') df_fs = df_fs[['Country', 'Sales', 'Profits', 'Assets', 'Market Value']] fig, ax = plt.subplots(figsize=(6.4, 3.5)) @@ -701,13 +833,18 @@ plt.show() ### City size -Here are plots of the city size distribution for the US and Brazil in 2023 from world population review. +Here are plots of the city size distribution for the US and Brazil in 2023 from the World Population Review. The size is measured by population. ```{code-cell} ipython3 -:tags: [hide-input] - +--- +mystnb: + figure: + caption: City size distribution + name: city-size-dist +tags: [hide-input] +--- # import population data of cities in 2023 United States and 2023 Brazil from world population review df_cs_us = pd.read_csv('https://media.githubusercontent.com/media/QuantEcon/high_dim_data/main/cross_section/cities_us.csv') df_cs_br = pd.read_csv('https://media.githubusercontent.com/media/QuantEcon/high_dim_data/main/cross_section/cities_brazil.csv') @@ -727,8 +864,13 @@ Here is a plot of the upper tail (top 500) of the wealth distribution. The data is from the Forbes Billionaires list in 2020. ```{code-cell} ipython3 -:tags: [hide-input] - +--- +mystnb: + figure: + caption: Wealth distribution (Forbes billionaires in 2020) + name: wealth-dist +tags: [hide-input] +--- df_w = pd.read_csv('https://media.githubusercontent.com/media/QuantEcon/high_dim_data/main/cross_section/forbes-billionaires.csv') df_w = df_w[['country', 'realTimeWorth', 'realTimeRank']].dropna() df_w = df_w.astype({'realTimeRank': int}) @@ -769,16 +911,21 @@ variable_code = ['NY.GDP.MKTP.CD', 'NY.GDP.PCAP.CD'] variable_names = ['GDP', 'GDP per capita'] df_gdp1 = extract_wb(varlist=variable_code, - c="all_countries", - s="2021", - e="2021", + c="all", + s=2021, + e=2021, varnames=variable_names) df_gdp1.dropna(inplace=True) ``` ```{code-cell} ipython3 -:tags: [hide-input] - +--- +mystnb: + figure: + caption: GDP per capita distribution + name: gdppc-dist +tags: [hide-input] +--- fig, axes = plt.subplots(1, 2, figsize=(8.8, 3.6)) for name, ax in zip(variable_names, axes): @@ -801,7 +948,7 @@ One impact of heavy tails is that sample averages can be poor estimators of the underlying mean of the distribution. To understand this point better, recall {doc}`our earlier discussion ` -of the Law of Large Numbers, which considered IID $X_1, \ldots, X_n$ with common distribution $F$ +of the law of large numbers, which considered IID $X_1, \ldots, X_n$ with common distribution $F$ If $\mathbb E |X_i|$ is finite, then the sample mean $\bar X_n := \frac{1}{n} \sum_{i=1}^n X_i$ satisfies @@ -815,7 +962,7 @@ the sample mean $\bar X_n := \frac{1}{n} \sum_{i=1}^n X_i$ satisfies where $\mu := \mathbb E X_i = \int x F(dx)$ is the common mean of the sample. The condition $\mathbb E | X_i | = \int |x| F(dx) < \infty$ holds -in most cases but can fail if the distribution $F$ is very heavy tailed. +in most cases but can fail if the distribution $F$ is very heavy-tailed. For example, it fails for the Cauchy distribution. @@ -823,6 +970,12 @@ Let's have a look at the behavior of the sample mean in this case, and see whether or not the LLN is still valid. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: LLN failure + name: fail-lln +--- from scipy.stats import cauchy np.random.seed(1234) @@ -852,12 +1005,13 @@ The sequence shows no sign of converging. We return to this point in the exercises. +(heavy-tail:application)= ## Why do heavy tails matter? We have now seen that 1. heavy tails are frequent in economics and -2. the Law of Large Numbers fails when tails are very heavy. +2. the law of large numbers fails when tails are very heavy. But what about in the real world? Do heavy tails matter? @@ -882,7 +1036,9 @@ portfolio is $\mu$ and the variance is $\sigma^2$. If instead the investor puts share $1/n$ of her wealth in each asset, then the portfolio payoff is -$$ Y_n = \sum_{i=1}^n \frac{X_i}{n} = \frac{1}{n} \sum_{i=1}^n X_i. $$ +$$ +Y_n = \sum_{i=1}^n \frac{X_i}{n} = \frac{1}{n} \sum_{i=1}^n X_i. +$$ Try computing the mean and variance. @@ -913,8 +1069,6 @@ For example, the heaviness of the tail of the income distribution helps determine {doc}`how much revenue a given tax policy will raise `. - - (cltail)= ## Classifying tail properties @@ -929,9 +1083,10 @@ nonnegative random variables and their distributions. The definitions for left hand tails are very similar and we omit them to simplify the exposition. +(heavy-tail:formal-definition)= ### Light and heavy tails -A distribution $F$ with density $f$ on $\mathbb R_+$ is called **heavy-tailed** if +A distribution $F$ with density $f$ on $\mathbb R_+$ is called [heavy-tailed](https://en.wikipedia.org/wiki/Heavy-tailed_distribution) if ```{math} :label: defht @@ -951,6 +1106,8 @@ $(0, \infty)$. The Pareto distribution is also heavy-tailed. +Less formally, a heavy-tailed distribution is one that is not exponentially bounded (i.e. the tails are heavier than the exponential distribution). + A distribution $F$ on $\mathbb R_+$ is called **light-tailed** if it is not heavy-tailed. A nonnegative random variable $X$ is **light-tailed** if its distribution $F$ is light-tailed. @@ -959,7 +1116,9 @@ For example, every random variable with bounded support is light-tailed. (Why?) As another example, if $X$ has the [exponential distribution](https://en.wikipedia.org/wiki/Exponential_distribution), with cdf $F(x) = 1 - \exp(-\lambda x)$ for some $\lambda > 0$, then its moment generating function is -$$ m(t) = \frac{\lambda}{\lambda - t} \quad \text{when } t < \lambda $$ +$$ +m(t) = \frac{\lambda}{\lambda - t} \quad \text{when } t < \lambda +$$ In particular, $m(t)$ is finite whenever $t < \lambda$, so $X$ is light-tailed. @@ -1018,7 +1177,7 @@ $$ But then $$ - \mathbb E X^r = r \int_0^\infty x^{r-1} \mathbb P\{ X > x \} dx +\mathbb E X^r = r \int_0^\infty x^{r-1} \mathbb P\{ X > x \} dx \geq r \int_0^{\bar x} x^{r-1} \mathbb P\{ X > x \} dx + r \int_{\bar x}^\infty x^{r-1} b x^{-\alpha} dx. @@ -1107,7 +1266,7 @@ Present discounted value of tax revenue will be estimated by The Pareto distribution is assumed to take the form {eq}`pareto` with $\bar x = 1$ and $\alpha = 1.05$. -(The value the tail index $\alpha$ is plausible given the data {cite}`gabaix2016power`.) +(The value of the tail index $\alpha$ is plausible given the data {cite}`gabaix2016power`.) To make the lognormal option as similar as possible to the Pareto option, choose its parameters such that the mean and median of both distributions are the same. @@ -1161,7 +1320,7 @@ $$ which we solve for $\mu$ and $\sigma$ given $\alpha = 1.05$. -Here is code that generates the two samples, produces the violin plot and +Here is the code that generates the two samples, produces the violin plot and prints the mean and standard deviation of the two samples. ```{code-cell} ipython3 @@ -1249,7 +1408,7 @@ assumption leads to a lower mean and greater dispersion. The [characteristic function](https://en.wikipedia.org/wiki/Characteristic_function_%28probability_theory%29) of the Cauchy distribution is $$ - \phi(t) = \mathbb E e^{itX} = \int e^{i t x} f(x) dx = e^{-|t|} +\phi(t) = \mathbb E e^{itX} = \int e^{i t x} f(x) dx = e^{-|t|} $$ (lln_cch) Prove that the sample mean $\bar X_n$ of $n$ independent draws $X_1, \ldots, diff --git a/lectures/inequality.md b/lectures/inequality.md index acfded55c..f87645a7b 100644 --- a/lectures/inequality.md +++ b/lectures/inequality.md @@ -15,15 +15,39 @@ kernelspec: ## Overview -In this section we +In the lecture {doc}`long_run_growth` we studied how GDP per capita has changed +for certain countries and regions. + +Per capita GDP is important because it gives us an idea of average income for +households in a given country. + +However, when we study income and wealth, averages are only part of the story. + +```{prf:example} +:label: ie_ex_av + +For example, imagine two societies, each with one million people, where + +* in the first society, the yearly income of one man is $100,000,000 and the income of the + others are zero +* in the second society, the yearly income of everyone is $100 + +These countries have the same income per capita (average income is $100) but the lives of the people will be very different (e.g., almost everyone in the first society is +starving, even though one person is fabulously rich). +``` + +The example above suggests that we should go beyond simple averages when we study income and wealth. + +This leads us to the topic of economic inequality, which examines how income and wealth (and other quantities) are distributed across a population. + +In this lecture we study inequality, beginning with measures of inequality and +then applying them to wealth and income data from the US and other countries. + -* provide motivation for the techniques deployed in the lecture and -* import code libraries needed for our work. ### Some history -Many historians argue that inequality played a key role in the fall of the -Roman Republic. +Many historians argue that inequality played a role in the fall of the Roman Republic (see, e.g., {cite}`levitt2019did`). Following the defeat of Carthage and the invasion of Spain, money flowed into Rome from across the empire, greatly enriched those in power. @@ -31,30 +55,24 @@ Rome from across the empire, greatly enriched those in power. Meanwhile, ordinary citizens were taken from their farms to fight for long periods, diminishing their wealth. -The resulting growth in inequality caused political turmoil that shook the -foundations of the republic. +The resulting growth in inequality was a driving factor behind political turmoil that shook the foundations of the republic. -Eventually, the Roman Republic gave way to a series of dictatorships, starting -with Octavian (Augustus) in 27 BCE. +Eventually, the Roman Republic gave way to a series of dictatorships, starting with [Octavian](https://en.wikipedia.org/wiki/Augustus) (Augustus) in 27 BCE. -This history is fascinating in its own right, and we can see some -parallels with certain countries in the modern world. +This history tells us that inequality matters, in the sense that it can drive major world events. -Let's now look at inequality in some of these countries. - - -### Measurement +There are other reasons that inequality might matter, such as how it affects +human welfare. +With this motivation, let us start to think about what inequality is and how we +can quantify and analyze it. -Political debates often revolve around inequality. -One problem with these debates is that inequality is often poorly defined. - -Moreover, debates on inequality are often tied to political beliefs. +### Measurement -This is dangerous for economists because allowing political beliefs to shape our findings reduces objectivity. +In politics and popular media, the word "inequality" is often used quite loosely, without any firm definition. -To bring a truly scientific perspective to the topic of inequality we must start with careful definitions. +To bring a scientific perspective to the topic of inequality we must start with careful definitions. Hence we begin by discussing ways that inequality can be measured in economic research. @@ -77,6 +95,8 @@ import wbgapi as wb import plotly.express as px ``` + + ## The Lorenz curve One popular measure of inequality is the Lorenz curve. @@ -197,7 +217,7 @@ households own just over 40\% of total wealth. --- mystnb: figure: - caption: Lorenz curve of simulated data + caption: Lorenz curve of simulated wealth data name: lorenz_simulated --- n = 2000 @@ -212,13 +232,16 @@ ax.plot(f_vals, f_vals, label='equality', lw=2) ax.vlines([0.8], [0.0], [0.43], alpha=0.5, colors='k', ls='--') ax.hlines([0.43], [0], [0.8], alpha=0.5, colors='k', ls='--') ax.set_xlim((0, 1)) -ax.set_xlabel("share of households (%)") +ax.set_xlabel("share of households") ax.set_ylim((0, 1)) -ax.set_ylabel("share of income (%)") +ax.set_ylabel("share of wealth") ax.legend() plt.show() ``` + + + ### Lorenz curves for US data Next let's look at US data for both income and wealth. @@ -228,7 +251,7 @@ The following code block imports a subset of the dataset `SCF_plus` for 2016, which is derived from the [Survey of Consumer Finances](https://en.wikipedia.org/wiki/Survey_of_Consumer_Finances) (SCF). ```{code-cell} ipython3 -url = 'https://media.githubusercontent.com/media/QuantEcon/high_dim_data/main/SCF_plus/SCF_plus_mini.csv' +url = 'https://github.com/QuantEcon/high_dim_data/raw/main/SCF_plus/SCF_plus_mini.csv' df = pd.read_csv(url) df_income_wealth = df.dropna() ``` @@ -304,8 +327,8 @@ ax.plot(f_vals_nw[-1], l_vals_nw[-1], label=f'net wealth') ax.plot(f_vals_ti[-1], l_vals_ti[-1], label=f'total income') ax.plot(f_vals_li[-1], l_vals_li[-1], label=f'labor income') ax.plot(f_vals_nw[-1], f_vals_nw[-1], label=f'equality') -ax.set_xlabel("share of households (%)") -ax.set_ylabel("share of income/wealth (%)") +ax.set_xlabel("share of households") +ax.set_ylabel("share of income/wealth") ax.legend() plt.show() ``` @@ -316,14 +339,15 @@ One key finding from this figure is that wealth inequality is more extreme than + + ## The Gini coefficient -The Lorenz curve is a useful visual representation of inequality in a distribution. +The Lorenz curve provides a visual representation of inequality in a distribution. Another way to study income and wealth inequality is via the Gini coefficient. -In this section we discuss the Gini coefficient and its relationship to the -Lorenz curve. +In this section we discuss the Gini coefficient and its relationship to the Lorenz curve. @@ -354,21 +378,19 @@ The idea is that $G=0$ indicates complete equality, while $G=1$ indicates comple --- mystnb: figure: - caption: Shaded Lorenz curve of simulated data + caption: Gini coefficient (simulated wealth data) name: lorenz_gini --- fig, ax = plt.subplots() f_vals, l_vals = lorenz_curve(sample) ax.plot(f_vals, l_vals, label=f'lognormal sample', lw=2) ax.plot(f_vals, f_vals, label='equality', lw=2) -ax.vlines([0.8], [0.0], [0.43], alpha=0.5, colors='k', ls='--') -ax.hlines([0.43], [0], [0.8], alpha=0.5, colors='k', ls='--') ax.fill_between(f_vals, l_vals, f_vals, alpha=0.06) ax.set_ylim((0, 1)) ax.set_xlim((0, 1)) ax.text(0.04, 0.5, r'$G = 2 \times$ shaded area') ax.set_xlabel("share of households (%)") -ax.set_ylabel("share of income/wealth (%)") +ax.set_ylabel("share of wealth (%)") ax.legend() plt.show() ``` @@ -399,8 +421,8 @@ ax.set_ylim((0, 1)) ax.set_xlim((0, 1)) ax.text(0.55, 0.4, 'A') ax.text(0.75, 0.15, 'B') -ax.set_xlabel("share of households (%)") -ax.set_ylabel("share of income/wealth (%)") +ax.set_xlabel("share of households") +ax.set_ylabel("share of wealth") ax.legend() plt.show() ``` @@ -408,7 +430,7 @@ plt.show() ```{seealso} -The World in Data project has a [nice graphical exploration of the Lorenz curve and the Gini coefficient](https://ourworldindata.org/what-is-the-gini-coefficient) +The World in Data project has a [graphical exploration of the Lorenz curve and the Gini coefficient](https://ourworldindata.org/what-is-the-gini-coefficient) ``` ### Gini coefficient of simulated data @@ -417,6 +439,8 @@ Let's examine the Gini coefficient in some simulations. The code below computes the Gini coefficient from a sample. +(code:gini-coefficient)= + ```{code-cell} ipython3 def gini_coefficient(y): @@ -463,6 +487,7 @@ You can check this by looking up the expression for the mean of a lognormal distribution. ```{code-cell} ipython3 +%%time k = 5 σ_vals = np.linspace(0.2, 4, k) n = 2_000 @@ -497,7 +522,7 @@ mystnb: fix, ax = plot_inequality_measures(σ_vals, ginis, 'simulated', - '$\sigma$', + r'$\sigma$', 'Gini coefficients') plt.show() ``` @@ -511,7 +536,7 @@ Let's look at the Gini coefficient for the distribution of income in the US. We will get pre-computed Gini coefficients (based on income) from the World Bank using the [wbgapi](https://blogs.worldbank.org/opendata/introducing-wbgapi-new-python-package-accessing-world-bank-data). -Let's use the `wbgapi` package we imported earlier to search the world bank data for Gini to find the Series ID. +Let's use the `wbgapi` package we imported earlier to search the World Bank data for Gini to find the Series ID. ```{code-cell} ipython3 wb.search("gini") @@ -527,7 +552,7 @@ To get a quick overview, let's histogram Gini coefficients across all countries --- mystnb: figure: - caption: Histogram of Gini coefficients + caption: Histogram of Gini coefficients across countries name: gini_histogram --- # Fetch gini data for all countries @@ -585,65 +610,24 @@ As can be seen in {numref}`gini_usa1`, the income Gini trended upward from 1980 to 2020 and then dropped following at the start of the COVID pandemic. (compare-income-wealth-usa-over-time)= -### Gini coefficient for wealth (US data) +### Gini coefficient for wealth -In the previous section we looked at the Gini coefficient for income using US data. +In the previous section we looked at the Gini coefficient for income, focusing on using US data. Now let's look at the Gini coefficient for the distribution of wealth. -We can use the {ref}`Survey of Consumer Finances data ` to look at the Gini coefficient -computed over the wealth distribution. +We will use US data from the {ref}`Survey of Consumer Finances` ```{code-cell} ipython3 df_income_wealth.year.describe() ``` -**Note:** This code can be used to compute this information over the full dataset. +[This notebook](https://github.com/QuantEcon/lecture-python-intro/tree/main/lectures/_static/lecture_specific/inequality/data.ipynb) can be used to compute this information over the full dataset. ```{code-cell} ipython3 -:tags: [skip-execution, hide-input, hide-output] - -!pip install quantecon -import quantecon as qe - -varlist = ['n_wealth', # net wealth - 't_income', # total income - 'l_income'] # labor income - -df = df_income_wealth - -# create lists to store Gini for each inequality measure -results = {} - -for var in varlist: - # create lists to store Gini - gini_yr = [] - for year in years: - # repeat the observations according to their weights - counts = list(round(df[df['year'] == year]['weights'] )) - y = df[df['year'] == year][var].repeat(counts) - y = np.asarray(y) - - rd.shuffle(y) # shuffle the sequence - - # calculate and store Gini - gini = qe.gini_coefficient(y) - gini_yr.append(gini) - - results[var] = gini_yr - -# Convert to DataFrame -results = pd.DataFrame(results, index=years) -results.to_csv("_static/lecture_specific/inequality/usa-gini-nwealth-tincome-lincome.csv", index_label='year') -``` - -However, to speed up execution we will import a pre-computed dataset from the lecture repository. - - - -```{code-cell} ipython3 -ginis = pd.read_csv("_static/lecture_specific/inequality/usa-gini-nwealth-tincome-lincome.csv", index_col='year') +data_url = 'https://github.com/QuantEcon/lecture-python-intro/raw/main/lectures/_static/lecture_specific/inequality/usa-gini-nwealth-tincome-lincome.csv' +ginis = pd.read_csv(data_url, index_col='year') ginis.head(n=5) ``` @@ -666,18 +650,14 @@ plt.show() The time series for the wealth Gini exhibits a U-shape, falling until the early 1980s and then increasing rapidly. - One possibility is that this change is mainly driven by technology. However, we will see below that not all advanced economies experienced similar growth of inequality. - - - - ### Cross-country comparisons of income inequality -Earlier in this lecture we used `wbgapi` to get Gini data across many countries and saved it in a variable called `gini_all` +Earlier in this lecture we used `wbgapi` to get Gini data across many countries +and saved it in a variable called `gini_all` In this section we will use this data to compare several advanced economies, and to look at the evolution in their respective income Ginis. @@ -779,8 +759,9 @@ min_year = plot_data.year.min() max_year = plot_data.year.max() ``` -The time series for all three countries start and stop in different years. We will add a year mask to the data to -improve clarity in the chart including the different end years associated with each countries time series. +The time series for all three countries start and stop in different years. + +We will add a year mask to the data to improve clarity in the chart including the different end years associated with each country's time series. ```{code-cell} ipython3 labels = [1979, 1986, 1991, 1995, 2000, 2020, 2021, 2022] + \ @@ -807,7 +788,7 @@ fig.show() This figure is built using `plotly` and is {ref}` available on the website ` ``` -This plot shows that all three Western economies GDP per capita has grown over +This plot shows that all three Western economies' GDP per capita has grown over time with some fluctuations in the Gini coefficient. From the early 80's the United Kingdom and the US economies both saw increases @@ -821,7 +802,6 @@ the US exhibits persistent but stable levels around a Gini coefficient of 40. Another popular measure of inequality is the top shares. - In this section we show how to compute top shares. @@ -908,7 +888,7 @@ ax.plot(years, df_topshares["topshare_n_wealth"], ax.plot(years, df_topshares["topshare_t_income"], marker='o', label="total income") ax.set_xlabel("year") -ax.set_ylabel("top $10\%$ share") +ax.set_ylabel(r"top $10\%$ share") ax.legend() plt.show() ``` @@ -1077,3 +1057,90 @@ plt.show() ```{solution-end} ``` + +```{exercise} +:label: inequality_ex3 + +The {ref}`code to compute the Gini coefficient is listed in the lecture above `. + +This code uses loops to calculate the coefficient based on income or wealth data. + +This function can be re-written using vectorization which will greatly improve the computational efficiency when using `python`. + +Re-write the function `gini_coefficient` using `numpy` and vectorized code. + +You can compare the output of this new function with the one above, and note the speed differences. +``` + +```{solution-start} inequality_ex3 +:class: dropdown +``` + +Let's take a look at some raw data for the US that is stored in `df_income_wealth` + +```{code-cell} ipython3 +df_income_wealth.describe() +``` + +```{code-cell} ipython3 +df_income_wealth.head(n=4) +``` + +We will focus on wealth variable `n_wealth` to compute a Gini coefficient for the year 2016. + +```{code-cell} ipython3 +data = df_income_wealth[df_income_wealth.year == 2016].sample(3000, random_state=1) +``` + +```{code-cell} ipython3 +data.head(n=2) +``` + +We can first compute the Gini coefficient using the function defined in the lecture above. + +```{code-cell} ipython3 +gini_coefficient(data.n_wealth.values) +``` + +Now we can write a vectorized version using `numpy` + +```{code-cell} ipython3 +def gini(y): + n = len(y) + y_1 = np.reshape(y, (n, 1)) + y_2 = np.reshape(y, (1, n)) + g_sum = np.sum(np.abs(y_1 - y_2)) + return g_sum / (2 * n * np.sum(y)) +``` +```{code-cell} ipython3 +gini(data.n_wealth.values) +``` +Let's simulate five populations by drawing from a lognormal distribution as before + +```{code-cell} ipython3 +k = 5 +σ_vals = np.linspace(0.2, 4, k) +n = 2_000 +σ_vals = σ_vals.reshape((k,1)) +μ_vals = -σ_vals**2/2 +y_vals = np.exp(μ_vals + σ_vals*np.random.randn(n)) +``` +We can compute the Gini coefficient for these five populations using the vectorized function, the computation time is shown below: + +```{code-cell} ipython3 +%%time +gini_coefficients =[] +for i in range(k): + gini_coefficients.append(gini(y_vals[i])) +``` +This shows the vectorized function is much faster. +This gives us the Gini coefficients for these five households. + +```{code-cell} ipython3 +gini_coefficients +``` +```{solution-end} +``` + + + diff --git a/lectures/inflation_history.md b/lectures/inflation_history.md index 5f840b4a4..5c5d07400 100644 --- a/lectures/inflation_history.md +++ b/lectures/inflation_history.md @@ -20,9 +20,23 @@ Let's start by installing the necessary Python packages. The `xlrd` package is used by `pandas` to perform operations on Excel files. ```{code-cell} ipython3 +:tags: [hide-output] + !pip install xlrd ``` + + +```{code-cell} ipython3 +:tags: [hide-cell] + +from importlib.metadata import version +from packaging.version import Version + +if Version(version("pandas")) < Version('2.1.4'): + !pip install "pandas>=2.1.4" +``` + We can then import the Python modules we will use. ```{code-cell} ipython3 @@ -88,16 +102,16 @@ mystnb: caption: Long run time series of the price level name: lrpl --- -df_fig5_bef1914 = df_fig5[df_fig5.index <= 1915] +df_fig5_befe1914 = df_fig5[df_fig5.index <= 1914] # Create plot cols = ['UK', 'US', 'France', 'Castile'] -fig, ax = plt.subplots(dpi=200) +fig, ax = plt.subplots(figsize=(10,6)) for col in cols: - ax.plot(df_fig5_bef1914.index, - df_fig5_bef1914[col], label=col, lw=2) + ax.plot(df_fig5_befe1914.index, + df_fig5_befe1914[col], label=col, lw=2) ax.legend() ax.set_ylabel('Index 1913 = 100') @@ -117,6 +131,10 @@ By staring at {numref}`lrpl` carefully, you might be able to guess when these te During these episodes, the gold/silver standard was temporarily abandoned when a government printed paper money to pay for war expenditures. +```{note} +This quantecon lecture {doc}`french_rev` describes circumstances leading up to and during the big inflation that occurred during the French Revolution. +``` + Despite these temporary lapses, a striking thing about the figure is that price levels were roughly constant over three centuries. In the early century, two other features of this data attracted the attention of [Irving Fisher](https://en.wikipedia.org/wiki/Irving_Fisher) of Yale University and [John Maynard Keynes](https://en.wikipedia.org/wiki/John_Maynard_Keynes) of Cambridge University. @@ -315,11 +333,6 @@ def pr_plot(p_seq, index, ax): # Calculate the difference of log p_seq log_diff_p = np.diff(np.log(p_seq)) - # Graph for the difference of log p_seq - ax.scatter(index[1:], log_diff_p, - label='Monthly inflation rate', - color='tab:grey') - # Calculate and plot moving average diff_smooth = pd.DataFrame(log_diff_p).rolling(3, center=True).mean() ax.plot(index[1:], diff_smooth, label='Moving average (3 period)', alpha=0.5, lw=2) @@ -333,7 +346,7 @@ def pr_plot(p_seq, index, ax): for label in ax.get_xticklabels(): label.set_rotation(45) - ax.legend(loc='upper left') + ax.legend() return ax ``` @@ -407,7 +420,7 @@ p_seq = df_aus['Retail price index, 52 commodities'] e_seq = df_aus['Exchange Rate'] lab = ['Retail price index', - '1/cents per Austrian Krone (Crown)'] + 'Austrian Krones (Crowns) per US cent'] # Create plot fig, ax = plt.subplots(dpi=200) @@ -451,12 +464,11 @@ mystnb: caption: Price index and exchange rate (Hungary) name: pi_xrate_hungary --- -m_seq = df_hun['Notes in circulation'] p_seq = df_hun['Hungarian index of prices'] e_seq = 1 / df_hun['Cents per crown in New York'] lab = ['Hungarian index of prices', - '1/cents per Hungarian Korona (Crown)'] + 'Hungarian Koronas (Crowns) per US cent'] # Create plot fig, ax = plt.subplots(dpi=200) @@ -525,7 +537,7 @@ e_seq[e_seq.index > '05-01-1924'] = np.nan ```{code-cell} ipython3 lab = ['Wholesale price index', - '1/cents per polish mark'] + 'Polish marks per US cent'] # Create plot fig, ax = plt.subplots(dpi=200) @@ -567,7 +579,7 @@ p_seq = df_deu['Price index (on basis of marks before July 1924,' e_seq = 1/df_deu['Cents per mark'] lab = ['Price index', - '1/cents per mark'] + 'Marks per US cent'] # Create plot fig, ax = plt.subplots(dpi=200) @@ -594,7 +606,7 @@ e_seq[e_seq.index > '12-01-1923'] = e_seq[e_seq.index > '12-01-1923'] * 1e12 lab = ['Price index (marks or converted to marks)', - '1/cents per mark (or reichsmark converted to mark)'] + 'Marks per US cent(or reichsmark converted to mark)'] # Create plot fig, ax = plt.subplots(dpi=200) @@ -641,7 +653,7 @@ The US government stood ready to convert a dollar into a specified amount of gol Immediately after World War I, Hungary, Austria, Poland, and Germany were not on the gold standard. -Their currencies were “fiat” or "unbacked", meaning that they were not backed by credible government promises to convert them into gold or silver coins on demand. +Their currencies were "fiat" or "unbacked", meaning that they were not backed by credible government promises to convert them into gold or silver coins on demand. The governments printed new paper notes to pay for goods and services. @@ -657,6 +669,6 @@ Chapter 3 of {cite}`sargent2002big` described deliberate changes in policy that Each government stopped printing money to pay for goods and services once again and made its currency convertible to the US dollar or the UK pound. -The story told in {cite}`sargent2002big` is grounded in a "monetarist theory of the price level" described in {doc}`cagan_ree` and {doc}`cagan_adaptive`. +The story told in {cite}`sargent2002big` is grounded in a *monetarist theory of the price level* described in {doc}`cagan_ree` and {doc}`cagan_adaptive`. Those lectures discuss theories about what owners of those rapidly depreciating currencies were thinking and how their beliefs shaped responses of inflation to government monetary and fiscal policies. diff --git a/lectures/input_output.md b/lectures/input_output.md index 8d6d649b6..6c768cea1 100644 --- a/lectures/input_output.md +++ b/lectures/input_output.md @@ -120,7 +120,7 @@ A basic framework for their analysis is After introducing the input-output model, we describe some of its connections to {doc}`linear programming lecture `. -## Input output analysis +## Input-output analysis Let @@ -184,7 +184,7 @@ plt.text(1.6, -0.5, r'$d_{2}$') plt.show() ``` -**Feasible allocations must satisfy** +*Feasible allocations must satisfy* $$ \begin{aligned} @@ -210,9 +210,9 @@ ax.plot(np.linspace(55, 380, 100), (50-0.9*np.linspace(55, 380, 100))/(-1.46), c ax.plot(np.linspace(-1, 400, 100), (60+0.16*np.linspace(-1, 400, 100))/0.83, color="r") ax.plot(np.linspace(250, 395, 100), (62-0.04*np.linspace(250, 395, 100))/0.33, color="b") -ax.text(130, 38, "$(1-a_{11})x_1 + a_{12}x_2 \geq d_1$", size=10) -ax.text(10, 105, "$-a_{21}x_1 + (1-a_{22})x_2 \geq d_2$", size=10) -ax.text(150, 150, "$a_{01}x_1 +a_{02}x_2 \leq x_0$", size=10) +ax.text(130, 38, r"$(1-a_{11})x_1 + a_{12}x_2 \geq d_1$", size=10) +ax.text(10, 105, r"$-a_{21}x_1 + (1-a_{22})x_2 \geq d_2$", size=10) +ax.text(150, 150, r"$a_{01}x_1 +a_{02}x_2 \leq x_0$", size=10) # Draw the feasible region feasible_set = Polygon(np.array([[301, 151], @@ -263,8 +263,10 @@ $$ $$ +```{prf:example} +:label: io_ex_tg -For example a two good economy described by +For example a two-good economy described by $$ A = @@ -279,6 +281,7 @@ d = 2 \end{bmatrix} $$ (eq:inout_ex) +``` ```{code-cell} ipython3 A = np.array([[0.1, 40], @@ -336,6 +339,9 @@ $$ Equation {eq}`eq:inout_frontier` sweeps out a **production possibility frontier** of final consumption bundles $d$ that can be produced with exogenous labor input $x_0$. +```{prf:example} +:label: io_ex_ppf + Consider the example in {eq}`eq:inout_ex`. Suppose we are now given @@ -345,6 +351,7 @@ a_0^\top = \begin{bmatrix} 4 & 100 \end{bmatrix} $$ +``` Then we can find $A_0^\top$ by @@ -459,8 +466,8 @@ ax.vlines(0, -1, 250) ax.plot(np.linspace(4.75, 49, 100), (4-0.9*np.linspace(4.75, 49, 100))/(-0.16), color="r") ax.plot(np.linspace(0, 50, 100), (33+1.46*np.linspace(0, 50, 100))/0.83, color="r") -ax.text(15, 175, "$(1-a_{11})p_1 - a_{21}p_2 \leq a_{01}w$", size=10) -ax.text(30, 85, "$-a_{12}p_1 + (1-a_{22})p_2 \leq a_{02}w$", size=10) +ax.text(15, 175, r"$(1-a_{11})p_1 - a_{21}p_2 \leq a_{01}w$", size=10) +ax.text(30, 85, r"$-a_{12}p_1 + (1-a_{22})p_2 \leq a_{02}w$", size=10) # Draw the feasible region feasible_set = Polygon(np.array([[17, 69], @@ -507,9 +514,9 @@ This illustrates that an element $l_{ij}$ of $L$ shows the total impact on secto ## Applications of graph theory -We can further study input output networks through applications of {doc}`graph theory `. +We can further study input-output networks through applications of {doc}`graph theory `. -An input output network can be represented by a weighted directed graph induced by the adjacency matrix $A$. +An input-output network can be represented by a weighted directed graph induced by the adjacency matrix $A$. The set of nodes $V = [n]$ is the list of sectors and the set of edges is given by @@ -550,7 +557,7 @@ The above figure indicates that manufacturing is the most dominant sector in the ### Output multipliers -Another way to rank sectors in input output networks is via output multipliers. +Another way to rank sectors in input-output networks is via output multipliers. The **output multiplier** of sector $j$ denoted by $\mu_j$ is usually defined as the total sector-wide impact of a unit change of demand in sector $j$. diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index baacb8217..575a4ccc1 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -33,7 +33,7 @@ Exports were regarded as good because they brought in bullion (gold flowed into Imports were regarded as bad because bullion was required to pay for them (gold flowed out). -This [zero-sum](https://en.wikipedia.org/wiki/Zero-sum_game) view of economics was eventually overturned by the work of the classical economists such as [Adam Smith](https://en.wikipedia.org/wiki/Adam_Smith) and [David Ricado](https://en.wikipedia.org/wiki/David_Ricardo), who showed how freeing domestic and international trade can enhance welfare. +This [zero-sum](https://en.wikipedia.org/wiki/Zero-sum_game) view of economics was eventually overturned by the work of the classical economists such as [Adam Smith](https://en.wikipedia.org/wiki/Adam_Smith) and [David Ricardo](https://en.wikipedia.org/wiki/David_Ricardo), who showed how freeing domestic and international trade can enhance welfare. There are many different expressions of this idea in economics. @@ -68,6 +68,9 @@ Before we look at the model of supply and demand, it will be helpful to have som ### A discrete example +```{prf:example} +:label: isd_ex_cs + Regarding consumer surplus, suppose that we have a single good and 10 consumers. These 10 consumers have different preferences; in particular, the amount they would be willing to pay for one unit of the good differs. @@ -79,6 +82,7 @@ Suppose that the willingness to pay for each of the 10 consumers is as follows: | willing to pay | 98 | 72 | 41 | 38 | 29 | 21 | 17 | 12 | 11 | 10 | (We have ordered consumers by willingness to pay, in descending order.) +``` If $p$ is the price of the good and $w_i$ is the amount that consumer $i$ is willing to pay, then $i$ buys when $w_i \geq p$. @@ -253,6 +257,9 @@ Let $v_i$ be the price at which producer $i$ is willing to sell the good. When the price is $p$, producer surplus for producer $i$ is $\max\{p - v_i, 0\}$. +```{prf:example} +:label: isd_ex_dc + For example, a producer willing to sell at \$10 and selling at price \$20 makes a surplus of \$10. Total producer surplus is given by @@ -273,6 +280,7 @@ p = 2 q^2 $$ The shaded area is the total producer surplus in this continuous model. +``` ```{code-cell} ipython3 --- @@ -340,7 +348,7 @@ ab_grid = np.linspace(a, b, 400) fig, ax = plt.subplots() ax.plot(x_grid, f(x_grid), label="$f$", color="k") ax.fill_between(ab_grid, [0] * len(ab_grid), f(ab_grid), - label="$\int_a^b f(x) dx$") + label=r"$\int_a^b f(x) dx$") ax.legend() plt.show() ``` @@ -351,7 +359,7 @@ Many of these rules relate to one of the most beautiful and powerful results in We will not try to cover these ideas here, partly because the subject is too big, and partly because you only need to know one rule for this lecture, stated below. -If $f(x) = c + \mathrm{d} x$, then +If $f(x) = c + dx$, then $$ \int_a^b f(x) \mathrm{d} x = c (b - a) + \frac{d}{2}(b^2 - a^2) @@ -670,7 +678,7 @@ This is the competitive equilibrium quantity. Observe that the equilibrium quantity equals the same $q$ given by equation {eq}`eq:old1`. The outcome that the quantity determined by equation {eq}`eq:old1` equates -supply to demand brings us a **key finding:** +supply to demand brings us a *key finding*: * a competitive equilibrium quantity maximizes our welfare criterion @@ -689,11 +697,11 @@ Our generalizations will extend the preceding analysis of a market for a single In addition -* we'll derive **demand curves** from a consumer problem that maximizes a - **utility function** subject to a **budget constraint**. +* we'll derive *demand curves* from a consumer problem that maximizes a + *utility function* subject to a *budget constraint*. -* we'll derive **supply curves** from the problem of a producer who is price - taker and maximizes his profits minus total costs that are described by a **cost function**. +* we'll derive *supply curves* from the problem of a producer who is price + taker and maximizes his profits minus total costs that are described by a *cost function*. ## Exercises diff --git a/lectures/laffer_adaptive.md b/lectures/laffer_adaptive.md index fd7b7f37f..b91240d90 100644 --- a/lectures/laffer_adaptive.md +++ b/lectures/laffer_adaptive.md @@ -33,7 +33,7 @@ that we adopted in lectures {doc}`money_inflation` and lectures {doc}`money_infl We shall discover that changing our hypothesis about expectations formation in this way will change some our findings and leave others intact. In particular, we shall discover that * replacing rational expectations with adaptive expectations leaves the two stationary inflation rates unchanged, but that $\ldots$ -* it reverse the perverse dynamics by making the **lower** stationary inflation rate the one to which the system typically converges +* it reverses the perverse dynamics by making the **lower** stationary inflation rate the one to which the system typically converges * a more plausible comparative dynamic outcome emerges in which now inflation can be **reduced** by running **lower** government deficits These more plausible comparative dynamics underlie the "old time religion" that states that @@ -50,7 +50,7 @@ by dropping rational expectations and instead assuming that people form expecta {cite}`marcet2003recurrent` and {cite}`sargent2009conquest` extended that work and applied it to study recurrent high-inflation episodes in Latin America. ``` -## The Model +## The model Let @@ -88,9 +88,9 @@ $$ (eq:adaptex) where $\delta \in (0,1)$ -## Computing An Equilibrium Sequence +## Computing an equilibrium sequence -Equation the expressions for $m_{t+1}$ promided by {eq}`eq:ada_mdemand` and {eq}`eq:ada_msupply2` and use equation {eq}`eq:adaptex` to eliminate $\pi_t^*$ to obtain +Equation the expressions for $m_{t+1}$ provided by {eq}`eq:ada_mdemand` and {eq}`eq:ada_msupply2` and use equation {eq}`eq:adaptex` to eliminate $\pi_t^*$ to obtain the following equation for $p_t$: $$ @@ -99,7 +99,7 @@ $$ (eq:pequation) **Pseudo-code** -Here is pseudo code for our algorithm. +Here is the pseudo-code for our algorithm. Starting at time $0$ with initial conditions $(m_0, \pi_{-1}^*, p_{-1})$, for each $t \geq 0$ deploy the following steps in order: @@ -111,14 +111,14 @@ deploy the following steps in order: This completes the algorithm. -## Claims or Conjectures +## Claims or conjectures It will turn out that * if they exist, limiting values $\overline \pi$ and $\overline \mu$ will be equal -* if limiting values exists, there are two possible limiting values, one high, one low +* if limiting values exist, there are two possible limiting values, one high, one low * unlike the outcome in lecture {doc}`money_inflation_nonlinear`, for almost all initial log price levels and expected inflation rates $p_0, \pi_{t}^*$, the limiting $\overline \pi = \overline \mu$ is the **lower** steady state value @@ -128,7 +128,7 @@ It will turn out that * the preceding equation for $p_0$ comes from $m_1 - p_0 = - \alpha \bar \pi$ -## Limiting Values of Inflation Rate +## Limiting values of inflation rate As in our earlier lecture {doc}`money_inflation_nonlinear`, we can compute the two prospective limiting values for $\bar \pi$ by studying the steady-state Laffer curve. @@ -213,15 +213,15 @@ print(f'The two steady state of π are: {π_l, π_u}') We find two steady state $\bar \pi$ values -## Steady State Laffer Curve +## Steady-state Laffer curve -The following figure plots the steady state Laffer curve together with the two stationary inflation rates. +The following figure plots the steady-state Laffer curve together with the two stationary inflation rates. ```{code-cell} ipython3 --- mystnb: figure: - caption: Seigniorage as function of steady state inflation. The dashed brown lines + caption: Seigniorage as function of steady-state inflation. The dashed brown lines indicate $\pi_l$ and $\pi_u$. name: laffer_curve_adaptive width: 500px @@ -258,11 +258,11 @@ def plot_laffer(model, πs): plot_laffer(model, (π_l, π_u)) ``` -## Associated Initial Price Levels +## Associated initial price levels Now that we have our hands on the two possible steady states, we can compute two initial log price levels $p_{-1}$, which as initial conditions, imply that $\pi_t = \bar \pi $ for all $t \geq 0$. -In particular, to initiate a fixed point of the dynamic Laffer curve dynamics we set +In particular, to initiate a fixed point of the dynamic Laffer curve dynamics, we set $$ p_{-1} = m_0 + \alpha \pi^* @@ -348,7 +348,7 @@ eq_g = lambda x: np.exp(-model.α * x) - np.exp(-(1 + model.α) * x) print('eq_g == g:', np.isclose(eq_g(m_seq[-1] - m_seq[-2]), model.g)) ``` -## Slippery Side of Laffer Curve Dynamics +## Slippery side of Laffer curve dynamics We are now equipped to compute time series starting from different $p_{-1}, \pi_{-1}^*$ settings, analogous to those in this lecture {doc}`money_inflation` and this lecture {doc}`money_inflation_nonlinear`. @@ -379,15 +379,15 @@ def draw_iterations(π0s, model, line_params, π_bars, num_steps): axes[2].axhline(y=π_bars[0], color='grey', linestyle='--', lw=1.5, alpha=0.6) axes[2].axhline(y=π_bars[1], color='grey', linestyle='--', lw=1.5, alpha=0.6) - axes[2].text(num_steps * 1.07, π_bars[0], '$\pi_l$', verticalalignment='center', + axes[2].text(num_steps * 1.07, π_bars[0], r'$\pi_l$', verticalalignment='center', color='grey', size=10) - axes[2].text(num_steps * 1.07, π_bars[1], '$\pi_u$', verticalalignment='center', + axes[2].text(num_steps * 1.07, π_bars[1], r'$\pi_u$', verticalalignment='center', color='grey', size=10) axes[0].set_ylabel('$m_t$') axes[1].set_ylabel('$p_t$') - axes[2].set_ylabel('$\pi_t$') - axes[3].set_ylabel('$\mu_t$') + axes[2].set_ylabel(r'$\pi_t$') + axes[3].set_ylabel(r'$\mu_t$') axes[3].set_xlabel('timestep') axes[3].xaxis.set_major_locator(MaxNLocator(integer=True)) diff --git a/lectures/lake_model.md b/lectures/lake_model.md index ba11f07fe..f70da94f4 100644 --- a/lectures/lake_model.md +++ b/lectures/lake_model.md @@ -36,7 +36,7 @@ The "flows" between the two lakes are as follows: 3. employed workers separate from their jobs at rate $\alpha$. 4. unemployed workers find jobs at rate $\lambda$. -The below graph illustrates the lake model. +The graph below illustrates the lake model. ```{figure} /_static/lecture_specific/lake_model/lake_model_worker.png :name: lake_model_graphviz @@ -216,7 +216,7 @@ Moreover, the times series of unemployment and employment seems to grow at some Since by intuition if we consider unemployment pool and employment pool as a closed system, the growth should be similar to the labor force. -We next ask whether the long run growth rates of $e_t$ and $u_t$ +We next ask whether the long-run growth rates of $e_t$ and $u_t$ also dominated by $1+b-d$ as labor force. The answer will be clearer if we appeal to {ref}`Perron-Frobenius theorem`. diff --git a/lectures/linear_equations.md b/lectures/linear_equations.md index 5f3646828..4b9ccb0fb 100644 --- a/lectures/linear_equations.md +++ b/lectures/linear_equations.md @@ -141,10 +141,12 @@ column vectors. The set of all $n$-vectors is denoted by $\mathbb R^n$. -For example, +```{prf:example} +:label: le_ex_dim * $\mathbb R^2$ is the plane --- the set of pairs $(x_1, x_2)$. * $\mathbb R^3$ is 3 dimensional space --- the set of vectors $(x_1, x_2, x_3)$. +``` Often vectors are represented visually as arrows from the origin to the point. @@ -185,7 +187,8 @@ multiplication, which we now describe. When we add two vectors, we add them element-by-element. -For example, +```{prf:example} +:label: le_ex_add $$ \begin{bmatrix} @@ -208,6 +211,7 @@ $$ 1 \end{bmatrix}. $$ +``` In general, @@ -273,7 +277,8 @@ plt.show() Scalar multiplication is an operation that multiplies a vector $x$ with a scalar elementwise. -For example, +```{prf:example} +:label: le_ex_mul $$ -2 @@ -292,6 +297,7 @@ $$ 14 \end{bmatrix}. $$ +``` More generally, it takes a number $\gamma$ and a vector $x$ and produces @@ -429,7 +435,8 @@ matrices. Scalar multiplication and addition are generalizations of the vector case: -Here is an example of scalar multiplication +```{prf:example} +:label: le_ex_asm $$ 3 @@ -443,6 +450,7 @@ $$ 0 & 15 \end{bmatrix}. $$ +``` In general for a number $\gamma$ and any matrix $A$, @@ -461,6 +469,9 @@ $$ \end{bmatrix}. $$ +```{prf:example} +:label: le_ex_ma + Consider this example of matrix addition, $$ @@ -479,6 +490,7 @@ $$ 7 & 12 \end{bmatrix}. $$ +``` In general, @@ -518,6 +530,9 @@ $j$-th column of $B$. If $A$ is $n \times k$ and $B$ is $j \times m$, then to multiply $A$ and $B$ we require $k = j$, and the resulting matrix $A B$ is $n \times m$. +```{prf:example} +:label: le_ex_2dmul + Here's an example of a $2 \times 2$ matrix multiplied by a $2 \times 1$ vector. $$ @@ -536,6 +551,7 @@ Ax = a_{21}x_1 + a_{22}x_2 \end{bmatrix} $$ +``` As an important special case, consider multiplying $n \times k$ matrix $A$ and $k \times 1$ column vector $x$. @@ -774,7 +790,7 @@ In general, we can write the demand equation as $q^d = Dp + h$, where Similarly, we can write the supply equation as $q^s = Cp + e$, where -* $q^d$ is an $n \times 1$ vector of supply quantities for the same goods. +* $q^s$ is an $n \times 1$ vector of supply quantities for the same goods. * $C$ is an $n \times n$ "coefficient" matrix. * $e$ is an $n \times 1$ vector of constant values. @@ -839,6 +855,8 @@ In matrix form, the system {eq}`la_se` becomes \end{bmatrix}. ``` +```{prf:example} +:label: le_ex_gls For example, {eq}`n_eq_sys_la` has this form with $$ @@ -848,7 +866,7 @@ $$ \quad \text{and} \quad x = p. $$ - +``` When considering problems such as {eq}`la_gf`, we need to ask at least some of the following questions diff --git a/lectures/lln_clt.md b/lectures/lln_clt.md index 7e7676cef..476a55482 100644 --- a/lectures/lln_clt.md +++ b/lectures/lln_clt.md @@ -51,6 +51,9 @@ will converge to their population means. Let's see an example of the LLN in action before we go further. +```{prf:example} +:label: lln_ex_ber + Consider a [Bernoulli random variable](https://en.wikipedia.org/wiki/Bernoulli_distribution) $X$ with parameter $p$. This means that $X$ takes values in $\{0,1\}$ and $\mathbb P\{X=1\} = p$. @@ -68,6 +71,7 @@ $$ \mathbb E X = 0 \cdot \mathbb P\{X=0\} + 1 \cdot \mathbb P\{X=1\} = \mathbb P\{X=1\} = p $$ +``` We can generate a draw of $X$ with `scipy.stats` (imported as `st`) as follows: @@ -167,6 +171,7 @@ $$ The next theorem is called Kolmogorov's strong law of large numbers. +(iid-theorem)= ````{prf:theorem} If $X_1, \ldots, X_n$ are IID and $\mathbb E |X|$ is finite, then @@ -368,7 +373,8 @@ The LLN fails to hold here because the assumption $\mathbb E|X| < \infty$ is vio The LLN can also fail to hold when the IID assumption is violated. -For example, suppose that +```{prf:example} +:label: lln_ex_fail $$ X_0 \sim N(0,1) @@ -383,6 +389,7 @@ $$ $$ Therefore, the distribution of $\bar X_n$ is $N(0,1)$ for all $n$! +``` Does this contradict the LLN, which says that the distribution of $\bar X_n$ collapses to the single point $\mu$? @@ -438,9 +445,9 @@ n \to \infty Here $\stackrel { d } {\to} N(0, \sigma^2)$ indicates [convergence in distribution](https://en.wikipedia.org/wiki/Convergence_of_random_variables#Convergence_in_distribution) to a centered (i.e., zero mean) normal with standard deviation $\sigma$. -The striking implication of the CLT is that for **any** distribution with +The striking implication of the CLT is that for any distribution with finite [second moment](https://en.wikipedia.org/wiki/Moment_(mathematics)), the simple operation of adding independent -copies **always** leads to a Gaussian(Normal) curve. +copies always leads to a Gaussian(Normal) curve. @@ -484,7 +491,7 @@ ax.set_xlim(xmin, xmax) ax.hist(Y, bins=60, alpha=0.4, density=True) xgrid = np.linspace(xmin, xmax, 200) ax.plot(xgrid, st.norm.pdf(xgrid, scale=σ), - 'k-', lw=2, label='$N(0, \sigma^2)$') + 'k-', lw=2, label=r'$N(0, \sigma^2)$') ax.set_xlabel(r"$Y_n$", size=12) ax.set_ylabel(r"$density$", size=12) @@ -536,7 +543,7 @@ ax.hist(Y, bins=60, alpha=0.4, density=True) ax.set_xlabel(r"$Y_n$", size=12) ax.set_ylabel(r"$density$", size=12) xgrid = np.linspace(xmin, xmax, 200) -ax.plot(xgrid, st.norm.pdf(xgrid, scale=σ), 'k-', lw=2, label='$N(0, \sigma^2)$') +ax.plot(xgrid, st.norm.pdf(xgrid, scale=σ), 'k-', lw=2, label=r'$N(0, \sigma^2)$') ax.legend() plt.show() @@ -598,7 +605,7 @@ $$ $$ where $\alpha, \beta, \sigma$ are constants and $\epsilon_1, \epsilon_2, -\ldots$ is IID and standard norma. +\ldots$ are IID and standard normal. Suppose that diff --git a/lectures/lp_intro.md b/lectures/lp_intro.md index 26896607f..102ad4fd9 100644 --- a/lectures/lp_intro.md +++ b/lectures/lp_intro.md @@ -12,12 +12,6 @@ kernelspec: (lp_intro)= # Linear Programming -```{admonition} Migrated lecture -:class: warning - -This lecture has moved from our [Intermediate Quantitative Economics with Python](https://python.quantecon.org/intro.html) lecture series and is now a part of [A First Course in Quantitative Economics](https://intro.quantecon.org/intro.html). -``` - In this lecture, we will need the following library. Install [ortools](https://developers.google.com/optimization) using `pip`. ```{code-cell} ipython3 @@ -38,15 +32,18 @@ Linear programs come in pairs: * an associated **dual** problem. -If a primal problem involves **maximization**, the dual problem involves **minimization**. +If a primal problem involves *maximization*, the dual problem involves *minimization*. -If a primal problem involves **minimization**, the dual problem involves **maximization**. +If a primal problem involves *minimization**, the dual problem involves **maximization*. We provide a standard form of a linear program and methods to transform other forms of linear programming problems into a standard form. We tell how to solve a linear programming problem using [SciPy](https://scipy.org/) and [Google OR-Tools](https://developers.google.com/optimization). -We describe the important concept of complementary slackness and how it relates to the dual problem. +```{seealso} +In another lecture, we will employ the linear programming method to solve the +{doc}`optimal transport problem `. +``` Let's start with some standard imports. @@ -56,14 +53,13 @@ from ortools.linear_solver import pywraplp from scipy.optimize import linprog import matplotlib.pyplot as plt from matplotlib.patches import Polygon -%matplotlib inline ``` Let's start with some examples of linear programming problem. -## Example 1: Production Problem +## Example 1: production problem This example was created by {cite}`bertsimas_tsitsiklis1997` @@ -85,7 +81,7 @@ Required per unit material and labor inputs and revenues are shown in table b A firm's problem is to construct a production plan that uses its 30 units of materials and 20 units of labor to maximize its revenue. -Let $x_i$ denote the quantity of Product $i$ that the firm produces. +Let $x_i$ denote the quantity of Product $i$ that the firm produces and $z$ denote the total revenue. This problem can be formulated as: @@ -100,60 +96,54 @@ $$ The following graph illustrates the firm's constraints and iso-revenue lines. +Iso-revenue lines show all the combinations of materials and labor that produce the same revenue. + ```{code-cell} ipython3 --- tags: [hide-input] --- fig, ax = plt.subplots() -ax.grid() - # Draw constraint lines -ax.hlines(0, -1, 17.5) -ax.vlines(0, -1, 12) -ax.plot(np.linspace(-1, 17.5, 100), 6-0.4*np.linspace(-1, 17.5, 100), color="r") -ax.plot(np.linspace(-1, 5.5, 100), 10-2*np.linspace(-1, 5.5, 100), color="r") -ax.text(1.5, 8, "$2x_1 + 5x_2 \leq 30$", size=12) -ax.text(10, 2.5, "$4x_1 + 2x_2 \leq 20$", size=12) -ax.text(-2, 2, "$x_2 \geq 0$", size=12) -ax.text(2.5, -0.7, "$x_1 \geq 0$", size=12) +ax.set_xlim(0,15) +ax.set_ylim(0,10) +x1 = np.linspace(0, 15) +ax.plot(x1, 6-0.4*x1, label="$2x_1 + 5x_2=30$") +ax.plot(x1, 10-2*x1, label="$4x_1 + 2x_2=20$") + # Draw the feasible region -feasible_set = Polygon(np.array([[0, 0], - [0, 6], - [2.5, 5], - [5, 0]]), - color="cyan") +feasible_set = Polygon(np.array([[0, 0],[0, 6],[2.5, 5],[5, 0]]), alpha=0.1) ax.add_patch(feasible_set) # Draw the objective function -ax.plot(np.linspace(-1, 5.5, 100), 3.875-0.75*np.linspace(-1, 5.5, 100), color="orange") -ax.plot(np.linspace(-1, 5.5, 100), 5.375-0.75*np.linspace(-1, 5.5, 100), color="orange") -ax.plot(np.linspace(-1, 5.5, 100), 6.875-0.75*np.linspace(-1, 5.5, 100), color="orange") -ax.arrow(-1.6, 5, 0, 2, width = 0.05, head_width=0.2, head_length=0.5, color="orange") -ax.text(5.7, 1, "$z = 3x_1 + 4x_2$", size=12) +ax.plot(x1, 3.875-0.75*x1, label="iso-revenue lines",color='k',linewidth=0.75) +ax.plot(x1, 5.375-0.75*x1, color='k',linewidth=0.75) +ax.plot(x1, 6.875-0.75*x1, color='k',linewidth=0.75) # Draw the optimal solution -ax.plot(2.5, 5, "*", color="black") -ax.text(2.7, 5.2, "Optimal Solution", size=12) +ax.plot(2.5, 5, ".", label="optimal solution") +ax.set_xlabel("$x_1$") +ax.set_ylabel("$x_2$") +ax.legend() plt.show() ``` The blue region is the feasible set within which all constraints are satisfied. -Parallel orange lines are iso-revenue lines. +Parallel black lines are iso-revenue lines. -The firm's objective is to find the parallel orange lines to the upper boundary of the feasible set. +The firm's objective is to find the parallel black lines to the upper boundary of the feasible set. -The intersection of the feasible set and the highest orange line delineates the optimal set. +The intersection of the feasible set and the highest black line delineates the optimal set. In this example, the optimal set is the point $(2.5, 5)$. -### Computation: Using OR-Tools +### Computation: using OR-Tools -Let's try to solve the same problem using the package *ortools.linear_solver* +Let's try to solve the same problem using the package `ortools.linear_solver`. @@ -164,7 +154,7 @@ The following cell instantiates a solver and creates two variables specifying th solver = pywraplp.Solver.CreateSolver('GLOP') ``` -Let's us create two variables $x_1$ and $x_2$ such that they can only have nonnegative values. +Let's create two variables $x_1$ and $x_2$ such that they can only have nonnegative values. ```{code-cell} ipython3 # Create the two variables and let them take on any non-negative value. @@ -189,7 +179,7 @@ Let's specify the objective function. We use `solver.Maximize` method in the cas solver.Maximize(3 * x1 + 4 * x2) ``` -Once we solve the problem, we can check whether the solver was successful in solving the problem using it's status. If it's successful, then the status will be equal to `pywraplp.Solver.OPTIMAL`. +Once we solve the problem, we can check whether the solver was successful in solving the problem using its status. If it's successful, then the status will be equal to `pywraplp.Solver.OPTIMAL`. ```{code-cell} ipython3 # Solve the system. @@ -197,26 +187,24 @@ status = solver.Solve() if status == pywraplp.Solver.OPTIMAL: print('Objective value =', solver.Objective().Value()) - x1_sol = round(x1.solution_value(), 2) - x2_sol = round(x2.solution_value(), 2) - print(f'(x1, x2): ({x1_sol}, {x2_sol})') + print(f'(x1, x2): ({x1.solution_value():.2}, {x2.solution_value():.2})') else: print('The problem does not have an optimal solution.') ``` -## Example 2: Investment Problem +## Example 2: investment problem We now consider a problem posed and solved by {cite}`hu_guo2018`. -A mutual fund has $ \$ 100,000$ to be invested over a three year horizon. +A mutual fund has $ \$ 100,000$ to be invested over a three-year horizon. Three investment options are available: -1. **Annuity:** the fund can pay a same amount of new capital at the beginning of each of three years and receive a payoff of 130\% of **total capital** invested at the end of the third year. Once the mutual fund decides to invest in this annuity, it has to keep investing in all subsequent years in the three year horizon. +1. Annuity: the fund can pay a same amount of new capital at the beginning of each of three years and receive a payoff of 130\% of total capital invested at the end of the third year. Once the mutual fund decides to invest in this annuity, it has to keep investing in all subsequent years in the three year horizon. -2. **Bank account:** the fund can deposit any amount into a bank at the beginning of each year and receive its capital plus 6\% interest at the end of that year. In addition, the mutual fund is permitted to borrow no more than $20,000 at the beginning of each year and is asked to pay back the amount borrowed plus 6\% interest at the end of the year. The mutual fund can choose whether to deposit or borrow at the beginning of each year. +2. Bank account: the fund can deposit any amount into a bank at the beginning of each year and receive its capital plus 6\% interest at the end of that year. In addition, the mutual fund is permitted to borrow no more than $20,000 at the beginning of each year and is asked to pay back the amount borrowed plus 6\% interest at the end of the year. The mutual fund can choose whether to deposit or borrow at the beginning of each year. -3. **Corporate bond:** At the beginning of the second year, a corporate bond becomes available. +3. Corporate bond: At the beginning of the second year, a corporate bond becomes available. The fund can buy an amount that is no more than $ \$ $50,000 of this bond at the beginning of the second year and at the end of the third year receive a payout of 130\% of the amount invested in the bond. @@ -286,9 +274,9 @@ $$ -### Computation: Using OR-Tools +### Computation: using OR-Tools -Let's try to solve the above problem using the package *ortools.linear_solver*. +Let's try to solve the above problem using the package `ortools.linear_solver`. The following cell instantiates a solver and creates two variables specifying the range of values that they can have. @@ -297,7 +285,7 @@ The following cell instantiates a solver and creates two variables specifying th solver = pywraplp.Solver.CreateSolver('GLOP') ``` -Let's us create five variables $x_1, x_2, x_3, x_4,$ and $x_5$ such that they can only have the values defined in the above constraints. +Let's create five variables $x_1, x_2, x_3, x_4,$ and $x_5$ such that they can only have the values defined in the above constraints. ```{code-cell} ipython3 # Create the variables using the ranges available from constraints @@ -354,7 +342,7 @@ OR-Tools tells us that the best investment strategy is: 3. At the beginning of the third year, the bank balance should be $ \$75,072.245 $. -4. At the end of the third year, the mutual fund will get payouts from the annuity and corporate bond and repay its loan from the bank. At the end it will own $ \$141018.24 $, so that it's total net rate of return over the three periods is $ 41.02\%$. +4. At the end of the third year, the mutual fund will get payouts from the annuity and corporate bond and repay its loan from the bank. At the end it will own $ \$141,018.24 $, so that it's total net rate of return over the three periods is $ 41.02\%$. @@ -395,7 +383,7 @@ c = \begin{bmatrix} c_1 \\ c_2 \\ \vdots \\ c_n \\ \end{bmatrix}, \quad x = \begin{bmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \\ \end{bmatrix}. \quad $$ -The standard form LP problem can be expressed concisely as: +The standard form linear programming problem can be expressed concisely as: $$ \begin{aligned} @@ -415,15 +403,15 @@ It is useful to know how to transform a problem that initially is not stated in By deploying the following steps, any linear programming problem can be transformed into an equivalent standard form linear programming problem. -1. **Objective Function:** If a problem is originally a constrained **maximization** problem, we can construct a new objective function that is the additive inverse of the original objective function. The transformed problem is then a **minimization** problem. +1. Objective function: If a problem is originally a constrained *maximization* problem, we can construct a new objective function that is the additive inverse of the original objective function. The transformed problem is then a *minimization* problem. -2. **Decision Variables:** Given a variable $x_j$ satisfying $x_j \le 0$, we can introduce a new variable $x_j' = - x_j$ and substitute it into original problem. Given a free variable $x_i$ with no restriction on its sign, we can introduce two new variables $x_j^+$ and $x_j^-$ satisfying $x_j^+, x_j^- \ge 0$ and replace $x_j$ by $x_j^+ - x_j^-$. +2. Decision variables: Given a variable $x_j$ satisfying $x_j \le 0$, we can introduce a new variable $x_j' = - x_j$ and substitute it into original problem. Given a free variable $x_i$ with no restriction on its sign, we can introduce two new variables $x_j^+$ and $x_j^-$ satisfying $x_j^+, x_j^- \ge 0$ and replace $x_j$ by $x_j^+ - x_j^-$. -3. **Inequality constraints:** Given an inequality constraint $\sum_{j=1}^n a_{ij}x_j \le 0$, we can introduce a new variable $s_i$, called a **slack variable** that satisfies $s_i \ge 0$ and replace the original constraint by $\sum_{j=1}^n a_{ij}x_j + s_i = 0$. +3. Inequality constraints: Given an inequality constraint $\sum_{j=1}^n a_{ij}x_j \le 0$, we can introduce a new variable $s_i$, called a **slack variable** that satisfies $s_i \ge 0$ and replace the original constraint by $\sum_{j=1}^n a_{ij}x_j + s_i = 0$. Let's apply the above steps to the two examples described above. -### Example 1: Production Problem +### Example 1: production problem The original problem is: @@ -449,9 +437,9 @@ $$ -### Computation: Using SciPy +### Computation: using SciPy -The package *scipy.optimize* provides a function ***linprog*** to solve linear programming problems with a form below: +The package `scipy.optimize` provides a function `linprog` to solve linear programming problems with a form below: $$ \begin{aligned} @@ -462,8 +450,10 @@ $$ \end{aligned} $$ +$A_{eq}, b_{eq}$ denote the equality constraint matrix and vector, and $A_{ub}, b_{ub}$ denote the inequality constraint matrix and vector. + ```{note} -By default $l = 0$ and $u = \text{None}$ unless explicitly specified with the argument 'bounds'. +By default $l = 0$ and $u = \text{None}$ unless explicitly specified with the argument `bounds`. ``` Let's now try to solve the Problem 1 using SciPy. @@ -495,7 +485,7 @@ else: The optimal plan tells the factory to produce $2.5$ units of Product 1 and $5$ units of Product 2; that generates a maximizing value of revenue of $27.5$. -We are using the *linprog* function as a **black box**. +We are using the `linprog` function as a *black box*. Inside it, Python first transforms the problem into standard form. @@ -506,12 +496,12 @@ Here the vector of slack variables is a two-dimensional NumPy array that equals See the [official documentation](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.linprog.html#scipy.optimize.linprog) for more details. ```{note} -This problem is to maximize the objective, so that we need to put a minus sign in front of parameter vector c. +This problem is to maximize the objective, so that we need to put a minus sign in front of parameter vector $c$. ``` -### Example 2: Investment Problem +### Example 2: investment problem The original problem is: @@ -559,14 +549,14 @@ c_ex2 = np.array([1.30*3, 0, 0, 1.06, 1.30]) A_ex2 = np.array([[1, 1, 0, 0, 0], [1, -rate, 1, 0, 1], [1, 0, -rate, 1, 0]]) -b_ex2 = np.array([100000, 0, 0]) +b_ex2 = np.array([100_000, 0, 0]) # Bounds on decision variables bounds_ex2 = [( 0, None), - (-20000, None), - (-20000, None), - (-20000, None), - ( 0, 50000)] + (-20_000, None), + (-20_000, None), + (-20_000, None), + ( 0, 50_000)] ``` Let's solve the problem and check the status using `success` attribute. @@ -598,7 +588,7 @@ SciPy tells us that the best investment strategy is: 3. At the beginning of the third year, the mutual fund should borrow $ \$20,000$ from the bank and invest in the annuity. -4. At the end of the third year, the mutual fund will get payouts from the annuity and corporate bond and repay its loan from the bank. At the end it will own $ \$141018.24 $, so that it's total net rate of return over the three periods is $ 41.02\% $. +4. At the end of the third year, the mutual fund will get payouts from the annuity and corporate bond and repay its loan from the bank. At the end it will own $ \$141,018.24 $, so that it's total net rate of return over the three periods is $ 41.02\% $. @@ -717,7 +707,7 @@ $$ # Instantiate a GLOP(Google Linear Optimization Package) solver solver = pywraplp.Solver.CreateSolver('GLOP') ``` -Let's us create two variables $x_1$ and $x_2$ such that they can only have nonnegative values. +Let's create two variables $x_1$ and $x_2$ such that they can only have nonnegative values. ```{code-cell} ipython3 # Create the two variables and let them take on any non-negative value. diff --git a/lectures/markov_chains_I.md b/lectures/markov_chains_I.md index 6b6ee9241..631dd70fb 100644 --- a/lectures/markov_chains_I.md +++ b/lectures/markov_chains_I.md @@ -58,6 +58,11 @@ import numpy as np import networkx as nx from matplotlib import cm import matplotlib as mpl +from mpl_toolkits.mplot3d import Axes3D +from matplotlib.animation import FuncAnimation +from IPython.display import HTML +from matplotlib.patches import Polygon +from mpl_toolkits.mplot3d.art3d import Poly3DCollection ``` ## Definitions and examples @@ -82,16 +87,15 @@ In other words, If $P$ is a stochastic matrix, then so is the $k$-th power $P^k$ for all $k \in \mathbb N$. -Checking this in {ref}`the first exercises ` below. +You are asked to check this in {ref}`an exercise ` below. ### Markov chains + Now we can introduce Markov chains. Before defining a Markov chain rigorously, we'll give some examples. -(Among other things, defining a Markov chain will clarify a connection between **stochastic matrices** and **Markov chains**.) - (mc_eg2)= #### Example 1 @@ -110,7 +114,7 @@ Here there are three **states** * "mr" represents mild recession * "sr" represents severe recession -The arrows represent **transition probabilities** over one month. +The arrows represent transition probabilities over one month. For example, the arrow from mild recession to normal growth has 0.145 next to it. @@ -120,7 +124,7 @@ The arrow from normal growth back to normal growth tells us that there is a 97% probability of transitioning from normal growth to normal growth (staying in the same state). -Note that these are *conditional* probabilities --- the probability of +Note that these are conditional probabilities --- the probability of transitioning from one state to another (or staying at the same one) conditional on the current state. @@ -258,14 +262,12 @@ Here is a visualization, with darker colors indicating higher probability. :tags: [hide-input] G = nx.MultiDiGraph() -edge_ls = [] -label_dict = {} for start_idx, node_start in enumerate(nodes): for end_idx, node_end in enumerate(nodes): value = P[start_idx][end_idx] if value != 0: - G.add_edge(node_start,node_end, weight=value, len=100) + G.add_edge(node_start,node_end, weight=value) pos = nx.spring_layout(G, seed=10) fig, ax = plt.subplots() @@ -273,7 +275,7 @@ nx.draw_networkx_nodes(G, pos, node_size=600, edgecolors='black', node_color='wh nx.draw_networkx_labels(G, pos) arc_rad = 0.2 -curved_edges = [edge for edge in G.edges()] + edges = nx.draw_networkx_edges(G, pos, ax=ax, connectionstyle=f'arc3, rad = {arc_rad}', edge_cmap=cm.Blues, width=2, edge_color=[G[nodes[0]][nodes[1]][0]['weight'] for nodes in G.edges]) @@ -317,7 +319,7 @@ This means that, for any date $t$ and any state $y \in S$, = \mathbb P \{ X_{t+1} = y \,|\, X_t, X_{t-1}, \ldots \} ``` -This means that once we know the current state $X_t$, adding knowledge of earlier states $X_{t-1}, X_{t-2}$ provides no additional information about probabilities of **future** states. +This means that once we know the current state $X_t$, adding knowledge of earlier states $X_{t-1}, X_{t-2}$ provides no additional information about probabilities of *future* states. Thus, the dynamics of a Markov chain are fully determined by the set of **conditional probabilities** @@ -356,7 +358,7 @@ By construction, the resulting process satisfies {eq}`mpp`. ```{index} single: Markov Chains; Simulation ``` -A good way to study a Markov chains is to simulate it. +A good way to study Markov chains is to simulate them. Let's start by doing this ourselves and then look at libraries that can help us. @@ -434,7 +436,7 @@ P = [[0.4, 0.6], Here's a short time series. ```{code-cell} ipython3 -mc_sample_path(P, ψ_0=[1.0, 0.0], ts_length=10) +mc_sample_path(P, ψ_0=(1.0, 0.0), ts_length=10) ``` It can be shown that for a long series drawn from `P`, the fraction of the @@ -448,7 +450,7 @@ $X_0$ is drawn. The following code illustrates this ```{code-cell} ipython3 -X = mc_sample_path(P, ψ_0=[0.1, 0.9], ts_length=1_000_000) +X = mc_sample_path(P, ψ_0=(0.1, 0.9), ts_length=1_000_000) np.mean(X == 0) ``` @@ -488,11 +490,11 @@ The following code illustrates ```{code-cell} ipython3 mc = qe.MarkovChain(P, state_values=('unemployed', 'employed')) -mc.simulate(ts_length=4, init='employed') +mc.simulate(ts_length=4, init='employed') # Start at employed initial state ``` ```{code-cell} ipython3 -mc.simulate(ts_length=4, init='unemployed') +mc.simulate(ts_length=4, init='unemployed') # Start at unemployed initial state ``` ```{code-cell} ipython3 @@ -570,7 +572,7 @@ This is very important, so let's repeat it X_0 \sim \psi_0 \quad \implies \quad X_m \sim \psi_0 P^m ``` -The general rule is that post-multiplying a distribution by $P^m$ shifts it forward $m$ units of time. +The general rule is that postmultiplying a distribution by $P^m$ shifts it forward $m$ units of time. Hence the following is also valid. @@ -625,12 +627,12 @@ $$ (mc_eg1-1)= -### Example 2: Cross-sectional distributions +### Example 2: cross-sectional distributions The distributions we have been studying can be viewed either 1. as probabilities or -1. as cross-sectional frequencies that the Law of Large Numbers leads us to anticipate for large samples. +1. as cross-sectional frequencies that the law of large numbers leads us to anticipate for large samples. To illustrate, recall our model of employment/unemployment dynamics for a given worker {ref}`discussed above `. @@ -641,9 +643,9 @@ workers' processes. Let $\psi_t$ be the current *cross-sectional* distribution over $\{ 0, 1 \}$. -The cross-sectional distribution records fractions of workers employed and unemployed at a given moment t. +The cross-sectional distribution records fractions of workers employed and unemployed at a given moment $t$. -* For example, $\psi_t(0)$ is the unemployment rate. +* For example, $\psi_t(0)$ is the unemployment rate at time $t$. What will the cross-sectional distribution be in 10 periods hence? @@ -651,11 +653,11 @@ The answer is $\psi_t P^{10}$, where $P$ is the stochastic matrix in {eq}`p_unempemp`. This is because each worker's state evolves according to $P$, so -$\psi_t P^{10}$ is a marginal distribution for a single randomly selected +$\psi_t P^{10}$ is a [marginal distribution](https://en.wikipedia.org/wiki/Marginal_distribution) for a single randomly selected worker. -But when the sample is large, outcomes and probabilities are roughly equal (by an application of the Law -of Large Numbers). +But when the sample is large, outcomes and probabilities are roughly equal (by an application of the law +of large numbers). So for a very large (tending to infinite) population, $\psi_t P^{10}$ also represents fractions of workers in @@ -688,11 +690,11 @@ Such distributions are called **stationary** or **invariant**. (mc_stat_dd)= Formally, a distribution $\psi^*$ on $S$ is called **stationary** for $P$ if $\psi^* P = \psi^* $. -Notice that, post-multiplying by $P$, we have $\psi^* P^2 = \psi^* P = \psi^*$. +Notice that, postmultiplying by $P$, we have $\psi^* P^2 = \psi^* P = \psi^*$. -Continuing in the same way leads to $\psi^* = \psi^* P^t$ for all $t$. +Continuing in the same way leads to $\psi^* = \psi^* P^t$ for all $t \ge 0$. -This tells us an important fact: If the distribution of $\psi_0$ is a stationary distribution, then $\psi_t$ will have this same distribution for all $t$. +This tells us an important fact: If the distribution of $\psi_0$ is a stationary distribution, then $\psi_t$ will have this same distribution for all $t \ge 0$. The following theorem is proved in Chapter 4 of {cite}`sargent2023economic` and numerous other sources. @@ -743,6 +745,11 @@ This is, in some sense, a steady state probability of unemployment. Not surprisingly it tends to zero as $\beta \to 0$, and to one as $\alpha \to 0$. + + + + + ### Calculating stationary distributions A stable algorithm for computing stationary distributions is implemented in [QuantEcon.py](http://quantecon.org/quantecon-py). @@ -757,6 +764,11 @@ mc = qe.MarkovChain(P) mc.stationary_distributions # Show all stationary distributions ``` + + + + + ### Asymptotic stationarity Consider an everywhere positive stochastic matrix with unique stationary distribution $\psi^*$. @@ -767,17 +779,24 @@ For example, we have the following result (strict_stationary)= ```{prf:theorem} -Theorem: If there exists an integer $m$ such that all entries of $P^m$ are -strictly positive, with unique stationary distribution $\psi^*$, then +:label: mc_gs_thm + +If there exists an integer $m$ such that all entries of $P^m$ are +strictly positive, then $$ \psi_0 P^t \to \psi^* \quad \text{ as } t \to \infty $$ + +where $\psi^*$ is the unique stationary distribution. ``` +This situation is often referred to as **asymptotic stationarity** or **global stability**. + +A proof of the theorem can be found in Chapter 4 of {cite}`sargent2023economic`, as well as many other sources. + -See, for example, {cite}`sargent2023economic` Chapter 4. @@ -793,7 +812,7 @@ P = np.array([[0.971, 0.029, 0.000], P @ P ``` -Let's pick an initial distribution $\psi_0$ and trace out the sequence of distributions $\psi_0 P^t$ for $t = 0, 1, 2, \ldots$ +Let's pick an initial distribution $\psi_1, \psi_2, \psi_3$ and trace out the sequence of distributions $\psi_i P^t$ for $t = 0, 1, 2, \ldots$, for $i=1, 2, 3$. First, we write a function to iterate the sequence of distributions for `ts_length` period @@ -801,149 +820,165 @@ First, we write a function to iterate the sequence of distributions for `ts_leng def iterate_ψ(ψ_0, P, ts_length): n = len(P) ψ_t = np.empty((ts_length, n)) - ψ = ψ_0 - for t in range(ts_length): - ψ_t[t] = ψ - ψ = ψ @ P - return np.array(ψ_t) + ψ_t[0 ]= ψ_0 + for t in range(1, ts_length): + ψ_t[t] = ψ_t[t-1] @ P + return ψ_t ``` Now we plot the sequence ```{code-cell} ipython3 -ψ_0 = (0.0, 0.2, 0.8) # Initial condition - -fig = plt.figure() -ax = fig.add_subplot(111, projection='3d') +:tags: [hide-input] -ax.set(xlim=(0, 1), ylim=(0, 1), zlim=(0, 1), - xticks=(0.25, 0.5, 0.75), - yticks=(0.25, 0.5, 0.75), - zticks=(0.25, 0.5, 0.75)) +ψ_1 = (0.0, 0.0, 1.0) +ψ_2 = (1.0, 0.0, 0.0) +ψ_3 = (0.0, 1.0, 0.0) # Three initial conditions +colors = ['blue','red', 'green'] # Different colors for each initial point -ψ_t = iterate_ψ(ψ_0, P, 20) +# Define the vertices of the unit simplex +v = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 0, 0]]) -ax.scatter(ψ_t[:,0], ψ_t[:,1], ψ_t[:,2], c='r', s=60) -ax.view_init(30, 210) +# Define the faces of the unit simplex +faces = [ + [v[0], v[1], v[2]], + [v[0], v[1], v[3]], + [v[0], v[2], v[3]], + [v[1], v[2], v[3]] +] -mc = qe.MarkovChain(P) -ψ_star = mc.stationary_distributions[0] -ax.scatter(ψ_star[0], ψ_star[1], ψ_star[2], c='k', s=60) +fig = plt.figure() +ax = fig.add_subplot(projection='3d') + +def update(n): + ax.clear() + ax.set_xlim([0, 1]) + ax.set_ylim([0, 1]) + ax.set_zlim([0, 1]) + ax.view_init(45, 45) + + simplex = Poly3DCollection(faces, alpha=0.03) + ax.add_collection3d(simplex) + + for idx, ψ_0 in enumerate([ψ_1, ψ_2, ψ_3]): + ψ_t = iterate_ψ(ψ_0, P, n+1) + + for i, point in enumerate(ψ_t): + ax.scatter(point[0], point[1], point[2], color=colors[idx], s=60, alpha=(i+1)/len(ψ_t)) + + mc = qe.MarkovChain(P) + ψ_star = mc.stationary_distributions[0] + ax.scatter(ψ_star[0], ψ_star[1], ψ_star[2], c='yellow', s=60) + + return fig, -plt.show() +anim = FuncAnimation(fig, update, frames=range(20), blit=False, repeat=False) +plt.close() +HTML(anim.to_jshtml()) ``` Here * $P$ is the stochastic matrix for recession and growth {ref}`considered above `. -* The highest red dot is an arbitrarily chosen initial marginal probability distribution $\psi_0$, represented as a vector in $\mathbb R^3$. -* The other red dots are the marginal distributions $\psi_0 P^t$ for $t = 1, 2, \ldots$. -* The black dot is $\psi^*$. +* The red, blue and green dots are initial marginal probability distributions $\psi_1, \psi_2, \psi_3$, each of which is represented as a vector in $\mathbb R^3$. +* The transparent dots are the marginal distributions $\psi_i P^t$ for $t = 1, 2, \ldots$, for $i=1,2,3.$. +* The yellow dot is $\psi^*$. You might like to try experimenting with different initial conditions. -#### An alternative illustration -We can show this in a slightly different way by focusing on the probability that $\psi_t$ puts on each state. -First, we write a function to draw initial distributions $\psi_0$ of size `num_distributions` +#### Example: failure of convergence -```{code-cell} ipython3 -def generate_initial_values(num_distributions): - n = len(P) - ψ_0s = np.empty((num_distributions, n)) - for i in range(num_distributions): - draws = np.random.randint(1, 10_000_000, size=n) +Consider the periodic chain with stochastic matrix - # Scale them so that they add up into 1 - ψ_0s[i,:] = np.array(draws/sum(draws)) - - return ψ_0s -``` - -We then write a function to plot the dynamics of $(\psi_0 P^t)(i)$ as $t$ gets large, for each state $i$ with different initial distributions +$$ +P = +\begin{bmatrix} + 0 & 1 \\ + 1 & 0 \\ +\end{bmatrix} +$$ -```{code-cell} ipython3 -def plot_distribution(P, ts_length, num_distributions): +This matrix does not satisfy the conditions of +{ref}`strict_stationary` because, as you can readily check, - # Get parameters of transition matrix - n = len(P) - mc = qe.MarkovChain(P) - ψ_star = mc.stationary_distributions[0] +* $P^m = P$ when $m$ is odd and +* $P^m = I$, the identity matrix, when $m$ is even. - ## Draw the plot - fig, axes = plt.subplots(nrows=1, ncols=n, figsize=[11, 5]) - plt.subplots_adjust(wspace=0.35) +Hence there is no $m$ such that all elements of $P^m$ are strictly positive. - ψ_0s = generate_initial_values(num_distributions) +Moreover, we can see that global stability does not hold. - # Get the path for each starting value - for ψ_0 in ψ_0s: - ψ_t = iterate_ψ(ψ_0, P, ts_length) +For instance, if we start at $\psi_0 = (1,0)$, then $\psi_m = \psi_0 P^m$ is $(1, 0)$ when $m$ is even and $(0,1)$ when $m$ is odd. - # Obtain and plot distributions at each state - for i in range(n): - axes[i].plot(range(0, ts_length), ψ_t[:,i], alpha=0.3) +We can see similar phenomena in higher dimensions. - # Add labels - for i in range(n): - axes[i].axhline(ψ_star[i], linestyle='dashed', lw=2, color = 'black', - label = fr'$\psi^*({i})$') - axes[i].set_xlabel('t') - axes[i].set_ylabel(fr'$\psi_t({i})$') - axes[i].legend() - - plt.show() -``` - -The following figure shows +The next figure illustrates this for a periodic Markov chain with three states. ```{code-cell} ipython3 -# Define the number of iterations -# and initial distributions -ts_length = 50 -num_distributions = 25 - -P = np.array([[0.971, 0.029, 0.000], - [0.145, 0.778, 0.077], - [0.000, 0.508, 0.492]]) - -plot_distribution(P, ts_length, num_distributions) -``` - -The convergence to $\psi^*$ holds for different initial distributions. - - - -#### Example: Failure of convergence +:tags: [hide-input] +ψ_1 = (0.0, 0.0, 1.0) +ψ_2 = (0.5, 0.5, 0.0) +ψ_3 = (0.25, 0.25, 0.5) +ψ_4 = (1/3, 1/3, 1/3) -In the case of a periodic chain, with +P = np.array([[0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [1.0, 0.0, 0.0]]) -$$ -P = -\begin{bmatrix} - 0 & 1 \\ - 1 & 0 \\ -\end{bmatrix} -$$ - -we find the distribution oscillates +fig = plt.figure() +ax = fig.add_subplot(projection='3d') +colors = ['red','yellow', 'green', 'blue'] # Different colors for each initial point + +# Define the vertices of the unit simplex +v = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 0, 0]]) + +# Define the faces of the unit simplex +faces = [ + [v[0], v[1], v[2]], + [v[0], v[1], v[3]], + [v[0], v[2], v[3]], + [v[1], v[2], v[3]] +] + +def update(n): + ax.clear() + ax.set_xlim([0, 1]) + ax.set_ylim([0, 1]) + ax.set_zlim([0, 1]) + ax.view_init(45, 45) + + # Plot the 3D unit simplex as planes + simplex = Poly3DCollection(faces,alpha=0.05) + ax.add_collection3d(simplex) + + for idx, ψ_0 in enumerate([ψ_1, ψ_2, ψ_3, ψ_4]): + ψ_t = iterate_ψ(ψ_0, P, n+1) + + point = ψ_t[-1] + ax.scatter(point[0], point[1], point[2], color=colors[idx], s=60) + points = np.array(ψ_t) + ax.plot(points[:, 0], points[:, 1], points[:, 2], color=colors[idx],linewidth=0.75) + + return fig, + +anim = FuncAnimation(fig, update, frames=range(20), blit=False, repeat=False) +plt.close() +HTML(anim.to_jshtml()) +``` +This animation demonstrates the behavior of an irreducible and periodic stochastic matrix. -```{code-cell} ipython3 -P = np.array([[0, 1], - [1, 0]]) +The red, yellow, and green dots represent different initial probability distributions. -ts_length = 20 -num_distributions = 30 +The blue dot represents the unique stationary distribution. -plot_distribution(P, ts_length, num_distributions) -``` +Unlike Hamilton’s Markov chain, these initial distributions do not converge to the unique stationary distribution. -Indeed, this $P$ fails our asymptotic stationarity condition, since, as you can -verify, $P^t$ is not everywhere positive for any $t$. +Instead, they cycle periodically around the probability simplex, illustrating that asymptotic stability fails. (finite_mc_expec)= @@ -1077,7 +1112,7 @@ Solution 1: ``` -Since the matrix is everywhere positive, there is a unique stationary distribution. +Since the matrix is everywhere positive, there is a unique stationary distribution $\psi^*$ such that $\psi_t\to \psi^*$ as $t\to \infty$. Solution 2: @@ -1104,42 +1139,6 @@ mc = qe.MarkovChain(P) ψ_star ``` -Solution 3: - -We find the distribution $\psi$ converges to the stationary distribution more quickly compared to the {ref}`hamilton's chain `. - -```{code-cell} ipython3 -ts_length = 10 -num_distributions = 25 -plot_distribution(P, ts_length, num_distributions) -``` - -In fact, the rate of convergence is governed by {ref}`eigenvalues` {cite}`sargent2023economic`. - -```{code-cell} ipython3 -P_eigenvals = np.linalg.eigvals(P) -P_eigenvals -``` - -```{code-cell} ipython3 -P_hamilton = np.array([[0.971, 0.029, 0.000], - [0.145, 0.778, 0.077], - [0.000, 0.508, 0.492]]) - -hamilton_eigenvals = np.linalg.eigvals(P_hamilton) -hamilton_eigenvals -``` - -More specifically, it is governed by the spectral gap, the difference between the largest and the second largest eigenvalue. - -```{code-cell} ipython3 -sp_gap_P = P_eigenvals[0] - np.diff(P_eigenvals)[0] -sp_gap_hamilton = hamilton_eigenvals[0] - np.diff(hamilton_eigenvals)[0] - -sp_gap_P > sp_gap_hamilton -``` - -We will come back to this when we discuss {ref}`spectral theory`. ```{solution-end} ``` diff --git a/lectures/markov_chains_II.md b/lectures/markov_chains_II.md index 67def2d75..e6da714ea 100644 --- a/lectures/markov_chains_II.md +++ b/lectures/markov_chains_II.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.14.4 + jupytext_version: 1.16.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -58,14 +58,9 @@ import numpy as np To explain irreducibility, let's take $P$ to be a fixed stochastic matrix. -Two states $x$ and $y$ are said to **communicate** with each other if -there exist positive integers $j$ and $k$ such that +State $y$ is called **accessible** (or **reachable**) from state $x$ if $P^t(x,y)>0$ for some integer $t\ge 0$. -$$ -P^j(x, y) > 0 -\quad \text{and} \quad -P^k(y, x) > 0 -$$ +Two states, $x$ and $y$, are said to **communicate** if $x$ and $y$ are accessible from each other. In view of our discussion {ref}`above `, this means precisely that @@ -76,6 +71,8 @@ that The stochastic matrix $P$ is called **irreducible** if all states communicate; that is, if $x$ and $y$ communicate for all $(x, y)$ in $S \times S$. +````{prf:example} +:label: mc2_ex_ir For example, consider the following transition probabilities for wealth of a fictitious set of households @@ -84,8 +81,6 @@ fictitious set of households :align: center ``` - - We can translate this into a stochastic matrix, putting zeros where there's no edge between nodes @@ -100,6 +95,7 @@ $$ It's clear from the graph that this stochastic matrix is irreducible: we can eventually reach any state from any other state. +```` We can also test this using [QuantEcon.py](http://quantecon.org/quantecon-py)'s MarkovChain class @@ -112,6 +108,9 @@ mc = qe.MarkovChain(P, ('poor', 'middle', 'rich')) mc.is_irreducible ``` +````{prf:example} +:label: mc2_ex_pf + Here's a more pessimistic scenario in which poor people remain poor forever ```{image} /_static/lecture_specific/markov_chains_II/Irre_2.png @@ -121,6 +120,7 @@ Here's a more pessimistic scenario in which poor people remain poor forever This stochastic matrix is not irreducible since, for example, rich is not accessible from poor. +```` Let's confirm this @@ -142,7 +142,7 @@ We'll come back to this a bit later. ### Irreducibility and stationarity -We discussed uniqueness of stationary distributions our {doc}`earlier lecture on Markov chains ` +We discussed uniqueness of stationary distributions in our earlier lecture {doc}`markov_chains_I`. There we {prf:ref}`stated ` that uniqueness holds when the transition matrix is everywhere positive. @@ -174,7 +174,7 @@ distribution, then, for all $x \in S$, ```{math} :label: llnfmc0 -\frac{1}{m} \sum_{t = 1}^m \mathbf{1}\{X_t = x\} \to \psi^*(x) +\frac{1}{m} \sum_{t = 1}^m \mathbb{1}\{X_t = x\} \to \psi^*(x) \quad \text{as } m \to \infty ``` @@ -182,8 +182,8 @@ distribution, then, for all $x \in S$, Here -* $\{X_t\}$ is a Markov chain with stochastic matrix $P$ and initial. - distribution $\psi_0$ +* $\{X_t\}$ is a Markov chain with stochastic matrix $P$ and initial distribution $\psi_0$ + * $\mathbb{1} \{X_t = x\} = 1$ if $X_t = x$ and zero otherwise. The result in [theorem 4.3](llnfmc0) is sometimes called **ergodicity**. @@ -196,16 +196,16 @@ This gives us another way to interpret the stationary distribution (provided irr Importantly, the result is valid for any choice of $\psi_0$. -The theorem is related to {doc}`the Law of Large Numbers `. +The theorem is related to {doc}`the law of large numbers `. It tells us that, in some settings, the law of large numbers sometimes holds even when the sequence of random variables is [not IID](iid_violation). (mc_eg1-2)= -### Example: Ergodicity and unemployment +### Example: ergodicity and unemployment -Recall our cross-sectional interpretation of the employment/unemployment model {ref}`discussed above `. +Recall our cross-sectional interpretation of the employment/unemployment model {ref}`discussed before `. Assume that $\alpha \in (0,1)$ and $\beta \in (0,1)$, so that irreducibility holds. @@ -235,7 +235,7 @@ Let's denote the fraction of time spent in state $x$ over the period $t=1, \ldots, n$ by $\hat p_n(x)$, so that $$ - \hat p_n(x) := \frac{1}{n} \sum_{t = 1}^n \mathbf{1}\{X_t = x\} + \hat p_n(x) := \frac{1}{n} \sum_{t = 1}^n \mathbb{1}\{X_t = x\} \qquad (x \in \{0, 1, 2\}) $$ @@ -248,8 +248,6 @@ Hence we expect that $\hat p_n(x) \approx \psi^*(x)$ when $n$ is large. The next figure shows convergence of $\hat p_n(x)$ to $\psi^*(x)$ when $x=1$ and $X_0$ is either $0, 1$ or $2$. - - ```{code-cell} ipython3 P = np.array([[0.971, 0.029, 0.000], [0.145, 0.778, 0.077], @@ -263,9 +261,9 @@ fig, ax = plt.subplots() ax.axhline(ψ_star[x], linestyle='dashed', color='black', label = fr'$\psi^*({x})$') # Compute the fraction of time spent in state 0, starting from different x_0s -for x0 in range(3): +for x0 in range(len(P)): X = mc.simulate(ts_length, init=x0) - p_hat = (X == x).cumsum() / (1 + np.arange(ts_length)) + p_hat = (X == x).cumsum() / np.arange(1, ts_length+1) ax.plot(p_hat, label=fr'$\hat p_n({x})$ when $X_0 = \, {x0}$') ax.set_xlabel('t') ax.set_ylabel(fr'$\hat p_n({x})$') @@ -279,6 +277,9 @@ In any of these cases, ergodicity will hold. ### Example: a periodic chain +````{prf:example} +:label: mc2_ex_pc + Let's look at the following example with states 0 and 1: $$ @@ -298,6 +299,7 @@ The transition graph shows that this model is irreducible. ``` Notice that there is a periodic cycle --- the state cycles between the two states in a regular way. +```` Not surprisingly, this property is called [periodicity](https://stats.libretexts.org/Bookshelves/Probability_Theory/Probability_Mathematical_Statistics_and_Stochastic_Processes_(Siegrist)/16%3A_Markov_Processes/16.05%3A_Periodicity_of_Discrete-Time_Chains). @@ -309,14 +311,13 @@ The following figure illustrates ```{code-cell} ipython3 P = np.array([[0, 1], [1, 0]]) -ts_length = 10_000 +ts_length = 100 mc = qe.MarkovChain(P) n = len(P) fig, axes = plt.subplots(nrows=1, ncols=n) ψ_star = mc.stationary_distributions[0] for i in range(n): - axes[i].set_ylim(0.45, 0.55) axes[i].axhline(ψ_star[i], linestyle='dashed', lw=2, color='black', label = fr'$\psi^*({i})$') axes[i].set_xlabel('t') @@ -326,10 +327,11 @@ for i in range(n): for x0 in range(n): # Generate time series starting at different x_0 X = mc.simulate(ts_length, init=x0) - p_hat = (X == i).cumsum() / (1 + np.arange(ts_length)) - axes[i].plot(p_hat, label=f'$x_0 = \, {x0} $') + p_hat = (X == i).cumsum() / np.arange(1, ts_length+1) + axes[i].plot(p_hat, label=fr'$x_0 = \, {x0} $') axes[i].legend() +plt.tight_layout() plt.show() ``` @@ -341,7 +343,7 @@ However, the distribution at each state does not. ### Example: political institutions -Let's go back to the political institutions mode with six states discussed {ref}`in a previous lecture ` and study ergodicity. +Let's go back to the political institutions model with six states discussed {ref}`in a previous lecture ` and study ergodicity. Here's the transition matrix. @@ -374,19 +376,18 @@ P = [[0.86, 0.11, 0.03, 0.00, 0.00, 0.00], [0.00, 0.00, 0.09, 0.11, 0.55, 0.25], [0.00, 0.00, 0.09, 0.15, 0.26, 0.50]] -ts_length = 10_000 +ts_length = 2500 mc = qe.MarkovChain(P) ψ_star = mc.stationary_distributions[0] -fig, ax = plt.subplots(figsize=(9, 6)) -X = mc.simulate(ts_length) +fig, ax = plt.subplots() +X = mc.simulate(ts_length, random_state=1) # Center the plot at 0 -ax.set_ylim(-0.25, 0.25) -ax.axhline(0, linestyle='dashed', lw=2, color='black', alpha=0.4) +ax.axhline(linestyle='dashed', lw=2, color='black') for x0 in range(len(P)): # Calculate the fraction of time for each state - p_hat = (X == x0).cumsum() / (1 + np.arange(ts_length)) + p_hat = (X == x0).cumsum() / np.arange(1, ts_length+1) ax.plot(p_hat - ψ_star[x0], label=f'$x = {x0+1} $') ax.set_xlabel('t') ax.set_ylabel(r'$\hat p_n(x) - \psi^* (x)$') @@ -395,37 +396,12 @@ ax.legend() plt.show() ``` - - -### Expectations of geometric sums - -Sometimes we want to compute the mathematical expectation of a geometric sum, such as -$\sum_t \beta^t h(X_t)$. - -In view of the preceding discussion, this is - -$$ -\mathbb{E} - \left[ - \sum_{j=0}^\infty \beta^j h(X_{t+j}) \mid X_t - = x - \right] - = x + \beta (Ph)(x) + \beta^2 (P^2 h)(x) + \cdots -$$ - -By the {ref}`Neumann series lemma `, this sum can be calculated using - -$$ - I + \beta P + \beta^2 P^2 + \cdots = (I - \beta P)^{-1} -$$ - - ## Exercises ````{exercise} :label: mc_ex1 -Benhabib el al. {cite}`benhabib_wealth_2019` estimated that the transition matrix for social mobility as the following +Benhabib et al. {cite}`benhabib_wealth_2019` estimated that the transition matrix for social mobility as the following $$ P:= @@ -508,14 +484,13 @@ Part 2: ```{code-cell} ipython3 ts_length = 1000 mc = qe.MarkovChain(P) -fig, ax = plt.subplots(figsize=(9, 6)) -X = mc.simulate(ts_length) -ax.set_ylim(-0.25, 0.25) -ax.axhline(0, linestyle='dashed', lw=2, color='black', alpha=0.4) +fig, ax = plt.subplots() +X = mc.simulate(ts_length, random_state=1) +ax.axhline(linestyle='dashed', lw=2, color='black') -for x0 in range(8): +for x0 in range(len(P)): # Calculate the fraction of time for each worker - p_hat = (X == x0).cumsum() / (1 + np.arange(ts_length)) + p_hat = (X == x0).cumsum() / np.arange(1, ts_length+1) ax.plot(p_hat - ψ_star[x0], label=f'$x = {x0+1} $') ax.set_xlabel('t') ax.set_ylabel(r'$\hat p_n(x) - \psi^* (x)$') @@ -555,7 +530,7 @@ In other words, if $\{X_t\}$ represents the Markov chain for employment, then $\bar X_m \to p$ as $m \to \infty$, where $$ -\bar X_m := \frac{1}{m} \sum_{t = 1}^m \mathbf{1}\{X_t = 0\} +\bar X_m := \frac{1}{m} \sum_{t = 1}^m \mathbb{1}\{X_t = 0\} $$ This exercise asks you to illustrate convergence by computing @@ -582,31 +557,27 @@ As $m$ gets large, both series converge to zero. ```{code-cell} ipython3 α = β = 0.1 -ts_length = 10000 +ts_length = 3000 p = β / (α + β) P = ((1 - α, α), # Careful: P and p are distinct ( β, 1 - β)) mc = qe.MarkovChain(P) -fig, ax = plt.subplots(figsize=(9, 6)) -ax.set_ylim(-0.25, 0.25) -ax.axhline(0, linestyle='dashed', lw=2, color='black', alpha=0.4) +fig, ax = plt.subplots() +ax.axhline(linestyle='dashed', lw=2, color='black') -for x0, col in ((0, 'blue'), (1, 'green')): +for x0 in range(len(P)): # Generate time series for worker that starts at x0 X = mc.simulate(ts_length, init=x0) # Compute fraction of time spent unemployed, for each n - X_bar = (X == 0).cumsum() / (1 + np.arange(ts_length)) + X_bar = (X == 0).cumsum() / np.arange(1, ts_length+1) # Plot - ax.fill_between(range(ts_length), np.zeros(ts_length), X_bar - p, color=col, alpha=0.1) - ax.plot(X_bar - p, color=col, label=f'$x_0 = \, {x0} $') - # Overlay in black--make lines clearer - ax.plot(X_bar - p, 'k-', alpha=0.6) + ax.plot(X_bar - p, label=f'$x_0 = \, {x0} $') ax.set_xlabel('t') ax.set_ylabel(r'$\bar X_m - \psi^* (x)$') -ax.legend(loc='upper right') +ax.legend() plt.show() ``` diff --git a/lectures/mle.md b/lectures/mle.md index ee00c3997..8a15d6ac1 100644 --- a/lectures/mle.md +++ b/lectures/mle.md @@ -39,6 +39,8 @@ $$ where $w$ is wealth. +```{prf:example} +:label: mle_ex_wt For example, if $a = 0.05$, $b = 0.1$, and $\bar w = 2.5$, this means @@ -46,7 +48,7 @@ For example, if $a = 0.05$, $b = 0.1$, and $\bar w = 2.5$, this means * a 10% tax on wealth in excess of 2.5. The unit is 100,000, so $w= 2.5$ means 250,000 dollars. - +``` Let's go ahead and define $h$: ```{code-cell} ipython3 @@ -242,7 +244,7 @@ num = (ln_sample - μ_hat)**2 σ_hat ``` -Let's plot the log-normal pdf using the estimated parameters against our sample data. +Let's plot the lognormal pdf using the estimated parameters against our sample data. ```{code-cell} ipython3 dist_lognorm = lognorm(σ_hat, scale = exp(μ_hat)) diff --git a/lectures/money_inflation.md b/lectures/money_inflation.md index 6fcf9ef75..420b237f0 100644 --- a/lectures/money_inflation.md +++ b/lectures/money_inflation.md @@ -32,10 +32,10 @@ The law of motion for the supply of money assumes that the government prints mon Our model equates the demand for money to the supply at each time $t \geq 0$. -Equality between those demands and supply gives in a **dynamic** model in which money supply -and price level **sequences** are simultaneously determined by a set of simultaneous linear equations. +Equality between those demands and supply gives a *dynamic* model in which money supply +and price level *sequences* are simultaneously determined by a set of simultaneous linear equations. -These equations take the form of what are often called vector linear **difference equations**. +These equations take the form of what is often called vector linear **difference equations**. In this lecture, we'll roll up our sleeves and solve those equations in two different ways. @@ -47,30 +47,30 @@ In this lecture we will encounter these concepts from macroeconomics: * an **inflation tax** that a government gathers by printing paper or electronic money * a dynamic **Laffer curve** in the inflation tax rate that has two stationary equilibria * perverse dynamics under rational expectations in which the system converges to the higher stationary inflation tax rate -* a peculiar comparative stationary-state outcome connected with that stationary inflation rate: it asserts that inflation can be **reduced** by running **higher** government deficits, i.e., by raising more resources by printing money. +* a peculiar comparative stationary-state outcome connected with that stationary inflation rate: it asserts that inflation can be *reduced* by running *higher* government deficits, i.e., by raising more resources by printing money. -The same qualitive outcomes prevail in this lecture {doc}`money_inflation_nonlinear` that studies a nonlinear version of the model in this lecture. +The same qualitative outcomes prevail in this lecture {doc}`money_inflation_nonlinear` that studies a nonlinear version of the model in this lecture. These outcomes set the stage for the analysis to be presented in this lecture {doc}`laffer_adaptive` that studies a nonlinear version of the present model; it assumes a version of "adaptive expectations" instead of rational expectations. That lecture will show that * replacing rational expectations with adaptive expectations leaves the two stationary inflation rates unchanged, but that $\ldots$ -* it reverse the pervese dynamics by making the **lower** stationary inflation rate the one to which the system typically converges -* a more plausible comparative dynamic outcome emerges in which now inflation can be **reduced** by running **lower** government deficits +* it reverses the perverse dynamics by making the *lower* stationary inflation rate the one to which the system typically converges +* a more plausible comparative dynamic outcome emerges in which now inflation can be *reduced* by running *lower* government deficits -This outcome will be used to justify a selection of a stationary inflation rate that underlies the analysis of unpleasant monetarist arithmetic to be studies in this lecture {doc}`unpleasant`. +This outcome will be used to justify a selection of a stationary inflation rate that underlies the analysis of unpleasant monetarist arithmetic to be studied in this lecture {doc}`unpleasant`. -We'll use theses tools from linear algebra: +We'll use these tools from linear algebra: * matrix multiplication * matrix inversion * eigenvalues and eigenvectors of a matrix -## Demand for and Supply of Money +## Demand for and supply of money -We say demand**s** and suppl**ies** (plurals) because there is one of each for each $t \geq 0$. +We say demand*s* and suppl*ies* (plurals) because there is one of each for each $t \geq 0$. Let @@ -82,7 +82,7 @@ Let * $b_t = \frac{m_{t+1}}{p_t}$ is real balances at the end of time $t$ * $R_t = \frac{p_t}{p_{t+1}} $ be the gross rate of return on currency held from time $t$ to time $t+1$ -It is often helpful to state units in which quantities are measured: +It is often helpful to state units in which quantities are measured: * $m_t$ and $m_t^d$ are measured in dollars * $g$ is measured in time $t$ goods @@ -96,8 +96,9 @@ Our job now is to specify demand and supply functions for money. We assume that the demand for currency satisfies the Cagan-like demand function $$ -m_{t+1}^d/p_t =\gamma_1 - \gamma_2 \frac{p_{t+1}}{p_t}, \quad t \geq 0 +\frac{m_{t+1}^d}{p_t}=\gamma_1 - \gamma_2 \frac{p_{t+1}}{p_t}, \quad t \geq 0 $$ (eq:demandmoney) +where $\gamma_1, \gamma_2$ are positive parameters. Now we turn to the supply of money. @@ -125,7 +126,7 @@ The demand for money at any time $t$ depends on the price level at time $t$ and The supply of money at time $t+1$ depends on the money supply at time $t$ and the price level at time $t$. -So the infinite sequence of equations {eq}`eq:syeqdemand` for $ t \geq 0$ imply that the **sequences** $\{p_t\}_{t=0}^\infty$ and $\{m_t\}_{t=0}^\infty$ are tied together and ultimately simulataneously determined. +So the infinite sequence of equations {eq}`eq:syeqdemand` for $ t \geq 0$ imply that the *sequences* $\{p_t\}_{t=0}^\infty$ and $\{m_t\}_{t=0}^\infty$ are tied together and ultimately simulataneously determined. ## Equilibrium price and money supply sequences @@ -144,11 +145,6 @@ $$ b_t - b_{t-1} R_{t-1} = g $$ (eq:bmotion) -where - -* $b_t = \frac{m_{t+1}}{p_t}$ is real balances at the end of period $t$ -* $R_{t-1} = \frac{p_{t-1}}{p_t}$ is the gross rate of return on real balances held from $t-1$ to $t$ - The demand for real balances is $$ @@ -174,17 +170,17 @@ We shall describe two distinct but closely related ways of computing a pair $\ But first it is instructive to describe a special type of equilibrium known as a **steady state**. -In a steady state equilibrium, a subset of key variables remain constant or **invariant** over time, while remaining variables can be expressed as functions of those constant variables. +In a steady-state equilibrium, a subset of key variables remain constant or **invariant** over time, while remaining variables can be expressed as functions of those constant variables. Finding such state variables is something of an art. -In many models, a good source of candidates for such invariant variables is a set of **ratios**. +In many models, a good source of candidates for such invariant variables is a set of *ratios*. This is true in the present model. -### Steady States +### Steady states -In a **steady state** equilibrium of the model we are studying, +In a steady-state equilibrium of the model we are studying, $$ \begin{aligned} @@ -195,9 +191,9 @@ $$ for $t \geq 0$. -Notice that both $R_t = \frac{p_t}{p_{t+1}}$ and $b_t = \frac{m_{t+1}}{p_t} $ are **ratios**. +Notice that both $R_t = \frac{p_t}{p_{t+1}}$ and $b_t = \frac{m_{t+1}}{p_t} $ are *ratios*. -To compute a steady state, we seek gross rates of return on currency $\bar R, \bar b$ that satisfy steady-state versions of both the government budget constraint and the demand function for real balances: +To compute a steady state, we seek gross rates of return on currency and real balances $\bar R, \bar b$ that satisfy steady-state versions of both the government budget constraint and the demand function for real balances: $$ \begin{aligned} @@ -213,7 +209,7 @@ $$ $$ (eq:seignsteady) -The left side is the steady-state amount of **seigniorage** or government revenues that the government gathers by paying a gross rate of return $\bar R < 1$ on currency. +The left side is the steady-state amount of **seigniorage** or government revenues that the government gathers by paying a gross rate of return $\bar R \le 1$ on currency. The right side is government expenditures. @@ -223,17 +219,17 @@ $$ S(\bar R) = (\gamma_1 + \gamma_2) - \frac{\gamma_2}{\bar R} - \gamma_1 \bar R $$ (eq:SSsigng) -Notice that $S(\bar R) \geq 0$ only when $\bar R \in [\frac{\gamma2}{\gamma1}, 1] +Notice that $S(\bar R) \geq 0$ only when $\bar R \in [\frac{\gamma_2}{\gamma_1}, 1] \equiv [\underline R, \overline R]$ and that $S(\bar R) = 0$ if $\bar R = \underline R$ or if $\bar R = \overline R$. We shall study equilibrium sequences that satisfy $$ -R_t \in \bar R = [\underline R, \overline R], \quad t \geq 0. +R_t \in [\underline R, \overline R], \quad t \geq 0. $$ -Maximizing steady state seigniorage {eq}`eq:SSsigng` with respect to $\bar R$, we find that the maximizing rate of return on currency is +Maximizing steady-state seigniorage {eq}`eq:SSsigng` with respect to $\bar R$, we find that the maximizing rate of return on currency is $$ \bar R_{\rm max} = \sqrt{\frac{\gamma_2}{\gamma_1}} @@ -255,7 +251,7 @@ A steady state gross rate of return $\bar R$ solves quadratic equation {eq}`eq: So two steady states typically exist. -## Some Code +## Some code Let's start with some imports: @@ -267,7 +263,7 @@ plt.rcParams['figure.dpi'] = 300 from collections import namedtuple ``` -Let's set some parameter values and compute possible steady state rates of return on currency $\bar R$, the seigniorage maximizing rate of return on currency, and an object that we'll discuss later, namely, an initial price level $p_0$ associated with the maximum steady state rate of return on currency. +Let's set some parameter values and compute possible steady-state rates of return on currency $\bar R$, the seigniorage maximizing rate of return on currency, and an object that we'll discuss later, namely, an initial price level $p_0$ associated with the maximum steady-state rate of return on currency. First, we create a `namedtuple` to store parameters so that we can reuse this `namedtuple` in our functions throughout this lecture @@ -308,10 +304,10 @@ print(f'R_max, g_max = {R_max:.4f}, {g_max:.4f}') Now let's plot seigniorage as a function of alternative potential steady-state values of $R$. -We'll see that there are two values of $R$ that attain seigniorage levels equal to $g$, -one that we'll denote $R_l$, another that we'll denote $R_u$. +We'll see that there are two steady-state values of $R$ that attain seigniorage levels equal to $g$, +one that we'll denote $R_\ell$, another that we'll denote $R_u$. -They satisfy $R_l < R_u$ and are affiliated with a higher inflation tax rate $(1-R_l)$ and a lower +They satisfy $R_\ell < R_u$ and are affiliated with a higher inflation tax rate $(1-R_\ell)$ and a lower inflation tax rate $1 - R_u$. ```{code-cell} ipython3 @@ -336,13 +332,12 @@ plt.xlabel('$R$') plt.ylabel('seigniorage') plt.legend() -plt.grid(True) plt.show() ``` Let's print the two steady-state rates of return $\bar R$ and the associated seigniorage revenues that the government collects. -(By construction, both steady state rates of return should raise the same amounts real revenue). +(By construction, both steady-state rates of return should raise the same amounts real revenue.) We hope that the following code will confirm this. @@ -354,9 +349,9 @@ g2 = seign(msm.R_l, msm) print(f'R_l, g_l = {msm.R_l:.4f}, {g2:.4f}') ``` -Now let's compute the maximum steady state amount of seigniorage that could be gathered by printing money and the state state rate of return on money that attains it. +Now let's compute the maximum steady-state amount of seigniorage that could be gathered by printing money and the state-state rate of return on money that attains it. -## Two Computation Strategies +## Two computation strategies We now proceed to compute equilibria, not necessarily steady states. @@ -373,7 +368,7 @@ $$ b_t & = b_{t-1} R_{t-1} + g \cr R_t^{-1} & = \frac{\gamma_1}{\gamma_2} - \gamma_2^{-1} b_t \end{aligned} -$$ +$$ (eq:rtbt) * Construct the associated equilibrium $p_0$ from @@ -390,13 +385,21 @@ m_t & = b_{t-1} p_t \end{aligned} $$ (eq:method1) -**Remark 1:** method 1 uses an indirect approach to computing an equilibrium by first computing an equilibrium $\{R_t, b_t\}_{t=0}^\infty$ sequence and then using it to back out an equilibrium $\{p_t, m_t\}_{t=0}^\infty$ sequence. - +```{prf:remark} +:label: method_1 +Method 1 uses an indirect approach to computing an equilibrium by first computing an equilibrium $\{R_t, b_t\}_{t=0}^\infty$ sequence and then using it to back out an equilibrium $\{p_t, m_t\}_{t=0}^\infty$ sequence. +``` -**Remark 2:** notice that method 1 starts by picking an **initial condition** $R_0$ from a set $[\frac{\gamma_2}{\gamma_1}, R_u]$. An equilibrium $\{p_t, m_t\}_{t=0}^\infty$ sequences are not unique. There is actually a continuum of equilibria indexed by a choice of $R_0$ from the set $[\frac{\gamma_2}{\gamma_1}, R_u]$. +```{prf:remark} +:label: initial_condition +Notice that method 1 starts by picking an **initial condition** $R_0$ from a set $[\frac{\gamma_2}{\gamma_1}, R_u]$. Equilibrium $\{p_t, m_t\}_{t=0}^\infty$ sequences are not unique. There is actually a continuum of equilibria indexed by a choice of $R_0$ from the set $[\frac{\gamma_2}{\gamma_1}, R_u]$. +``` -**Remark 3:** associated with each selection of $R_0$ there is a unique $p_0$ described by +```{prf:remark} +:label: unique_selection +Associated with each selection of $R_0$ there is a unique $p_0$ described by equation {eq}`eq:p0fromR0`. +``` ### Method 2 @@ -425,13 +428,13 @@ It is natural to take the initial stock of money $m_0 >0$ as an initial conditio But what about $p_0$? -Isn't it something that we want to be **determined** by our model? +Isn't it something that we want to be *determined* by our model? Yes, but sometimes we want too much, because there is actually a continuum of initial $p_0$ levels that are compatible with the existence of an equilibrium. As we shall see soon, selecting an initial $p_0$ in method 2 is intimately tied to selecting an initial rate of return on currency $R_0$ in method 1. -## Computation Method 1 +## Computation method 1 %We start from an arbitrary $R_0$ and $b_t = \frac{m_{t+1}}{p_t}$, we have @@ -439,7 +442,7 @@ As we shall see soon, selecting an initial $p_0$ in method 2 is intimately tied %b_0 = \gamma_1 - \gamma_0 R_0^{-1} %$$ -Remember that there exist two steady state equilibrium values $ R_l < R_u$ of the rate of return on currency $R_t$. +Remember that there exist two steady-state equilibrium values $ R_\ell < R_u$ of the rate of return on currency $R_t$. We proceed as follows. @@ -447,15 +450,8 @@ Start at $t=0$ * select a $R_0 \in [\frac{\gamma_2}{\gamma_1}, R_u]$ * compute $b_0 = \gamma_1 - \gamma_0 R_0^{-1} $ -Then for $t \geq 1$ construct $(b_t, R_t)$ by -iterating on the system - -$$ -\begin{aligned} -b_t & = b_{t-1} R_{t-1} + g \cr -R_t^{-1} & = \frac{\gamma_1}{\gamma_2} - \gamma_2^{-1} b_t -\end{aligned} -$$ +Then for $t \geq 1$ construct $b_t, R_t$ by +iterating on equation {eq}`eq:rtbt`. When we implement this part of method 1, we shall discover the following striking outcome: @@ -464,15 +460,15 @@ outcome: $\{R_t\}$ always converges to a limiting "steady state" value $\bar R$ that depends on the initial condition $R_0$. -* there are only two possible limit points $\{ R_l, R_u\}$. +* there are only two possible limit points $\{ R_\ell, R_u\}$. -* for almost every initial condition $R_0$, $\lim_{t \rightarrow +\infty} R_t = R_l$. +* for almost every initial condition $R_0$, $\lim_{t \rightarrow +\infty} R_t = R_\ell$. * if and only if $R_0 = R_u$, $\lim_{t \rightarrow +\infty} R_t = R_u$. The quantity $1 - R_t$ can be interpreted as an **inflation tax rate** that the government imposes on holders of its currency. -We shall soon see that the existence of two steady state rates of return on currency +We shall soon see that the existence of two steady-state rates of return on currency that serve to finance the government deficit of $g$ indicates the presence of a **Laffer curve** in the inflation tax rate. ```{note} @@ -501,7 +497,7 @@ def simulate_system(R0, model, num_steps): return b_values, R_values ``` -Let's write some code plot outcomes for several possible initial values $R_0$. +Let's write some code to plot outcomes for several possible initial values $R_0$. ```{code-cell} ipython3 :tags: [hide-cell] @@ -566,7 +562,7 @@ R0s = np.append(msm.R_l, R0s) draw_paths(R0s, msm, line_params, num_steps=20) ``` -Notice how sequences that start from $R_0$ in the half-open interval $[R_l, R_u)$ converge to the steady state associated with to $ R_l$. +Notice how sequences that start from $R_0$ in the half-open interval $[R_\ell, R_u)$ converge to the steady state associated with to $ R_\ell$. ## Computation method 2 @@ -617,7 +613,7 @@ H = H_1^{-1} H_2 $$ ```{code-cell} ipython3 -H = np.linalg.inv(H1) @ H2 +H = np.linalg.solve(H1, H2) print('H = \n', H) ``` @@ -659,11 +655,11 @@ where $\Lambda$ is a diagonal matrix of eigenvalues and the columns of $Q$ are e It turns out that $$ -\begin{bmatrix} {R_l}^{-1} & 0 \cr +\Lambda = \begin{bmatrix} {R_\ell}^{-1} & 0 \cr 0 & {R_u}^{-1} \end{bmatrix} $$ -where $R_l$ and $R_u$ are the lower and higher steady-state rates of return on currency that we computed above. +where $R_\ell$ and $R_u$ are the lower and higher steady-state rates of return on currency that we computed above. ```{code-cell} ipython3 Λ, Q = np.linalg.eig(H) @@ -711,7 +707,7 @@ $$ then $$ -\lim_{t\rightarrow + \infty} \frac{p_{t+1}}{p_t} = {R_l}^{-1}. +\lim_{t\rightarrow + \infty} \frac{p_{t+1}}{p_t} = {R_\ell}^{-1}. $$ Let's verify these claims step by step. @@ -740,7 +736,7 @@ def iterate_H(y_0, H, num_steps): return y ``` -For almost all initial vectors $y_0$, the gross rate of inflation $\frac{p_{t+1}}{p_t}$ eventually converges to the larger eigenvalue ${R_l}^{-1}$. +For almost all initial vectors $y_0$, the gross rate of inflation $\frac{p_{t+1}}{p_t}$ eventually converges to the larger eigenvalue ${R_\ell}^{-1}$. The only way to avoid this outcome is for $p_0$ to take the specific value described by {eq}`eq:magicp0`. @@ -758,8 +754,8 @@ y^*_{t+1} = \Lambda^t y^*_t . $$ (eq:stardynamics) This equation represents the dynamics of our system in a way that lets us isolate the -force that causes gross inflation to converge to the inverse of the lower steady state rate -of inflation $R_l$ that we discovered earlier. +force that causes gross inflation to converge to the inverse of the lower steady-state rate +of inflation $R_\ell$ that we discovered earlier. Staring at equation {eq}`eq:stardynamics` indicates that unless @@ -770,7 +766,7 @@ y^*_0 = \begin{bmatrix} y^*_{1,0} \cr 0 \end{bmatrix} ``` the path of $y^*_t$, and therefore the paths of both $m_t$ and $p_t$ given by -$y_t = Q y^*_t$ will eventually grow at gross rates ${R_l}^{-1}$ as +$y_t = Q y^*_t$ will eventually grow at gross rates ${R_\ell}^{-1}$ as $t \rightarrow +\infty$. Equation {eq}`equation_11` also leads us to conclude that there is a unique setting @@ -781,7 +777,7 @@ For this to occur, the required setting of $y_0$ must evidently have the propert that $$ -Q y_0 = y^*_0 = \begin{bmatrix} y^*_{1,0} \cr 0 \end{bmatrix} . +Q^{-1} y_0 = y^*_0 = \begin{bmatrix} y^*_{1,0} \cr 0 \end{bmatrix} . $$ But note that since @@ -793,7 +789,7 @@ is truly a **state** variable, $p_0$ is a **jump** variable that must adjust at $t=0$ in order to satisfy the equation. Thus, in a nutshell the unique value of the vector $y_0$ for which -the paths of $y_t$ **don't** eventually grow at rate ${R_l}^{-1}$ requires setting the second component +the paths of $y_t$ *don't* eventually grow at rate ${R_\ell}^{-1}$ requires setting the second component of $y^*_0$ equal to zero. The component $p_0$ of the initial vector @@ -905,7 +901,7 @@ def draw_iterations(p0s, model, line_params, num_steps): axes[1].plot(time_steps, P, **line_params) # Calculate R_t - R = np.insert(P[:-1] / P[1:], 0, np.NAN) + R = np.insert(P[:-1] / P[1:], 0, np.nan) axes[2].plot(time_steps, R, **line_params) # Add line and text annotations to the subgraph @@ -942,7 +938,7 @@ draw_iterations(p0s, msm, line_params, num_steps=20) Please notice that for $m_t$ and $p_t$, we have used log scales for the coordinate (i.e., vertical) axes. Using log scales allows us to spot distinct constant limiting gross rates of growth ${R_u}^{-1}$ and -${R_l}^{-1}$ by eye. +${R_\ell}^{-1}$ by eye. ## Peculiar stationary outcomes @@ -952,17 +948,17 @@ As promised at the start of this lecture, we have encountered these concepts fro * an **inflation tax** that a government gathers by printing paper or electronic money * a dynamic **Laffer curve** in the inflation tax rate that has two stationary equilibria -Staring at the paths of rates of return on the price level in figure {numref}`R0_path` and price levels in {numref}`p0_path` show indicate that almost all paths converge to the **higher** inflation tax rate displayed in the stationary state Laffer curve displayed in figure {numref}`infl_tax`. +Staring at the paths of rates of return on the price level in figure {numref}`R0_path` and price levels in {numref}`p0_path` show indicate that almost all paths converge to the *higher* inflation tax rate displayed in the stationary state Laffer curve displayed in figure {numref}`infl_tax`. Thus, we have indeed discovered what we earlier called "perverse" dynamics under rational expectations in which the system converges to the higher of two possible stationary inflation tax rates. Those dynamics are "perverse" not only in the sense that they imply that the monetary and fiscal authorities that have chosen to finance government expenditures eventually impose a higher inflation tax than required to finance government expenditures, but because of the following "counterintuitive" situation that we can deduce by staring at the stationary state Laffer curve displayed in figure {numref}`infl_tax`: -* the figure indicates that inflation can be **reduced** by running **higher** government deficits, i.e., by raising more resources through printing money. +* the figure indicates that inflation can be *reduced* by running *higher* government deficits, i.e., by raising more resources through printing money. ```{note} -The same qualitive outcomes prevail in this lecture {doc}`money_inflation_nonlinear` that studies a nonlinear version of the model in this lecture. +The same qualitative outcomes prevail in this lecture {doc}`money_inflation_nonlinear` that studies a nonlinear version of the model in this lecture. ``` @@ -976,7 +972,7 @@ Through application of our computational methods 1 and 2, we have learned that * for computational method 1, $R_0$ * for computational method 2, $p_0$ -To apply our model, we have somehow to **complete** it by **selecting** an equilibrium path from among the continuum of possible paths. +To apply our model, we have somehow to *complete* it by *selecting* an equilibrium path from among the continuum of possible paths. We discovered that diff --git a/lectures/money_inflation_nonlinear.md b/lectures/money_inflation_nonlinear.md index c533d1c66..bce94f096 100644 --- a/lectures/money_inflation_nonlinear.md +++ b/lectures/money_inflation_nonlinear.md @@ -15,10 +15,10 @@ kernelspec: ## Overview -This lecture studies stationary and dynamic **Laffer curves** in the inflation tax rate in a non-linear version of the model studied in this lecture {doc}`money_inflation`. +We study stationary and dynamic *Laffer curves* in the inflation tax rate in a non-linear version of the model studied in {doc}`money_inflation`. -This lecture uses the log-linear version of the demand function for money that {cite}`Cagan` -used in his classic paper in place of the linear demand function used in this lecture {doc}`money_inflation`. +We use the log-linear version of the demand function for money that {cite}`Cagan` +used in his classic paper in place of the linear demand function used in {doc}`money_inflation`. That change requires that we modify parts of our analysis. @@ -26,7 +26,7 @@ In particular, our dynamic system is no longer linear in state variables. Nevertheless, the economic logic underlying an analysis based on what we called ''method 2'' remains unchanged. -in this lecture we shall discover qualitatively similar outcomes to those that we studied in the lecture {doc}`money_inflation`. +We shall discover qualitatively similar outcomes to those that we studied in {doc}`money_inflation`. That lecture presented a linear version of the model in this lecture. @@ -35,15 +35,15 @@ As in that lecture, we discussed these topics: * an **inflation tax** that a government gathers by printing paper or electronic money * a dynamic **Laffer curve** in the inflation tax rate that has two stationary equilibria * perverse dynamics under rational expectations in which the system converges to the higher stationary inflation tax rate -* a peculiar comparative stationary-state analysis connected with that stationary inflation rate that assert that inflation can be **reduced** by running **higher** government deficits +* a peculiar comparative stationary-state analysis connected with that stationary inflation rate that asserts that inflation can be *reduced* by running *higher* government deficits -These outcomes will set the stage for the analysis of this lecture {doc}`laffer_adaptive` that studies a version of the present model that uses a version of "adaptive expectations" instead of rational expectations. +These outcomes will set the stage for the analysis of {doc}`laffer_adaptive` that studies a version of the present model that uses a version of "adaptive expectations" instead of rational expectations. That lecture will show that * replacing rational expectations with adaptive expectations leaves the two stationary inflation rates unchanged, but that $\ldots$ -* it reverse the pervese dynamics by making the **lower** stationary inflation rate the one to which the system typically converges -* a more plausible comparative dynamic outcome emerges in which now inflation can be **reduced** by running **lower** government deficits +* it reverses the perverse dynamics by making the *lower* stationary inflation rate the one to which the system typically converges +* a more plausible comparative dynamic outcome emerges in which now inflation can be *reduced* by running *lower* government deficits ## The Model @@ -68,69 +68,18 @@ $$ (eq:msupply) where $g$ is the part of government expenditures financed by printing money. -**Remark:** Please notice that while equation {eq}`eq:mdemand` is linear in logs of the money supply and price level, equation {eq}`eq:msupply` is linear in levels. This will require adapting the equilibrium computation methods that we deployed in {doc}`money_inflation`. - -## Computing An Equilibrium Sequence - -We'll deploy a method similar to **Method 2** used in {doc}`money_inflation`. - -We'll take the time $t$ state vector to be $m_t, p_t$. - -* we'll treat $m_t$ as a ''natural state variable'' and $p_t$ as a ''jump'' variable. - -Let - -$$ -\lambda \equiv \frac{\alpha}{1+ \alpha} -$$ - -Let's rewrite equations {eq}`eq:msupply` and {eq}`eq:mdemand`, respectively, as - - -$$ -\exp(m_{t+1}) - \exp(m_t) = g \exp(p_t) -$$ (eq:msupply2) - -and - -$$ -p_t = (1-\lambda) m_{t+1} + \lambda p_{t+1} -$$ (eq:mdemand2) - -We'll summarize our algorithm with the following pseudo-code. - -**Pseudo-code** - -* start for $m_0, p_0$ at time $t =0$ - -* solve {eq}`eq:msupply2` for $m_{t+1}$ - -* solve {eq}`eq:mdemand2` for $p_{t+1} = \lambda^{-1} p_t + (1 - \lambda^{-1}) m_{t+1}$ - -* compute $\pi_t = p_{t+1} - p_t$ and $\mu_t = m_{t+1} - m_t $ - -* iterate on $t$ to convergence of $\pi_t \rightarrow \overline \pi$ and $\mu_t \rightarrow \overline \mu$ - -It will turn out that - -* if they exist, limiting values $\overline \pi$ and $\overline \mu$ will be equal - -* if limiting values exists, there are two possible limiting values, one high, one low - -* for almost all initial log price levels $p_0$, the limiting $\overline \pi = \overline \mu$ is -the higher value +```{prf:remark} +:label: linear_log +Please notice that while equation {eq}`eq:mdemand` is linear in logs of the money supply and price level, equation {eq}`eq:msupply` is linear in levels. This will require adapting the equilibrium computation methods that we deployed in {doc}`money_inflation`. +``` -* for each of the two possible limiting values $\bar \pi$ ,there is a unique initial log price level $p_0$ that implies that $\pi_t = \mu_t = \bar \mu$ for all $t \geq 0$ - * this unique initial log price level solves $\log(\exp(m_0) + g \exp(p_0)) - p_0 = - \alpha \bar \pi $ - - * the preceding equation for $p_0$ comes from $m_1 - p_0 = - \alpha \bar \pi$ ## Limiting Values of Inflation Rate -We can compute the two prospective limiting values for $\bar \pi$ by studying the steady-state Laffer curve. +We can compute the two prospective limiting values for $\overline \pi$ by studying the steady-state Laffer curve. -Thus, in a **steady state** +Thus, in a *steady state* $$ m_{t+1} - m_t = p_{t+1} - p_t = x \quad \forall t , @@ -147,7 +96,7 @@ $$ (eq:steadypi) where we require that $$ -g \leq \max_{x: x \geq 0} \exp(-\alpha x) - \exp(-(1 + \alpha) x) , +g \leq \max_{x \geq 0} \{\exp(-\alpha x) - \exp(-(1 + \alpha) x) \}, $$ (eq:revmax) so that it is feasible to finance $g$ by printing money. @@ -159,7 +108,7 @@ The right side of {eq}`eq:steadypi` is the quantity of time $t$ goods that the Soon we'll plot the left and right sides of equation {eq}`eq:steadypi`. But first we'll write code that computes a steady-state -$\bar \pi$. +$\overline \pi$. Let's start by importing some libraries @@ -182,7 +131,7 @@ CaganLaffer = namedtuple('CaganLaffer', "λ", "g" ]) -# Create a CaganLaffer model +# Create a Cagan Laffer model def create_model(α=0.5, m0=np.log(100), g=0.35): return CaganLaffer(α=α, m0=m0, λ=α/(1+α), g=g) @@ -191,7 +140,7 @@ model = create_model() +++ {"user_expressions": []} -Now we write code that computes steady-state $\bar \pi$s. +Now we write code that computes steady-state $\overline \pi$s. ```{code-cell} ipython3 # Define formula for π_bar @@ -208,9 +157,9 @@ def solve_π_bar(model, x0): print(f'The two steady state of π are: {π_l, π_u}') ``` -We find two steady state $\bar \pi$ values +We find two steady state $\overline \pi$ values. -## Steady State Laffer Curve +## Steady State Laffer curve The following figure plots the steady state Laffer curve together with the two stationary inflation rates. @@ -237,27 +186,33 @@ def plot_laffer(model, πs): # Plot the function plt.plot(x_values, y_values, - label=f'$exp((-{α})x) - exp(- (1- {α}) x)$') - for π, label in zip(πs, ['$\pi_l$', '$\pi_u$']): + label=f'Laffer curve') + for π, label in zip(πs, [r'$\pi_l$', r'$\pi_u$']): plt.text(π, plt.gca().get_ylim()[0]*2, label, horizontalalignment='center', color='brown', size=10) plt.axvline(π, color='brown', linestyle='--') plt.axhline(g, color='red', linewidth=0.5, linestyle='--', label='g') - plt.xlabel('$\pi$') + plt.xlabel(r'$\pi$') plt.ylabel('seigniorage') plt.legend() - plt.grid(True) plt.show() # Steady state Laffer curve plot_laffer(model, (π_l, π_u)) ``` -## Associated Initial Price Levels +## Initial Price Levels + +Now that we have our hands on the two possible steady states, we can compute two functions $\underline p(m_0)$ and +$\overline p(m_0)$, which as initial conditions for $p_t$ at time $t$, imply that $\pi_t = \overline \pi $ for all $t \geq 0$. + +The function $\underline p(m_0)$ will be associated with $\pi_l$ the lower steady-state inflation rate. + +The function $\overline p(m_0)$ will be associated with $\pi_u$ the lower steady-state inflation rate. + -Now that we have our hands on the two possible steady states, we can compute two initial log price levels $p_0$, which as initial conditions, imply that $\pi_t = \bar \pi $ for all $t \geq 0$. ```{code-cell} ipython3 def solve_p0(p0, m0, α, g, π): @@ -320,9 +275,70 @@ eq_g = lambda x: np.exp(-model.α * x) - np.exp(-(1 + model.α) * x) print('eq_g == g:', np.isclose(eq_g(m_seq[-1] - m_seq[-2]), model.g)) ``` +## Computing an Equilibrium Sequence + +We'll deploy a method similar to *Method 2* used in {doc}`money_inflation`. + +We'll take the time $t$ state vector to be the pair $(m_t, p_t)$. + +We'll treat $m_t$ as a ``natural state variable`` and $p_t$ as a ``jump`` variable. + +Let + +$$ +\lambda \equiv \frac{\alpha}{1+ \alpha} +$$ + +Let's rewrite equation {eq}`eq:mdemand` as + +$$ +p_t = (1-\lambda) m_{t+1} + \lambda p_{t+1} +$$ (eq:mdemand2) + +We'll summarize our algorithm with the following pseudo-code. + +**Pseudo-code** + +The heart of the pseudo-code iterates on the following mapping from state vector $(m_t, p_t)$ at time $t$ +to state vector $(m_{t+1}, p_{t+1})$ at time $t+1$. + + +* starting from a given pair $(m_t, p_t)$ at time $t \geq 0$ + + * solve {eq}`eq:msupply` for $m_{t+1}$ + + * solve {eq}`eq:mdemand2` for $p_{t+1} = \lambda^{-1} p_t + (1 - \lambda^{-1}) m_{t+1}$ + + * compute the inflation rate $\pi_t = p_{t+1} - p_t$ and growth of money supply $\mu_t = m_{t+1} - m_t $ + +Next, compute the two functions $\underline p(m_0)$ and $\overline p(m_0)$ described above + +Now initiate the algorithm as follows. + + * set $m_0 >0$ + * set a value of $p_0 \in [\underline p(m_0), \overline p(m_0)]$ and form the pair $(m_0, p_0)$ at time $t =0$ + +Starting from $(m_0, p_0)$ iterate on $t$ to convergence of $\pi_t \rightarrow \overline \pi$ and $\mu_t \rightarrow \overline \mu$ + +It will turn out that + +* if they exist, limiting values $\overline \pi$ and $\overline \mu$ will be equal + +* if limiting values exist, there are two possible limiting values, one high, one low + +* for almost all initial log price levels $p_0$, the limiting $\overline \pi = \overline \mu$ is +the higher value + +* for each of the two possible limiting values $\overline \pi$ ,there is a unique initial log price level $p_0$ that implies that $\pi_t = \mu_t = \overline \mu$ for all $t \geq 0$ + + * this unique initial log price level solves $\log(\exp(m_0) + g \exp(p_0)) - p_0 = - \alpha \overline \pi $ + + * the preceding equation for $p_0$ comes from $m_1 - p_0 = - \alpha \overline \pi$ + + ## Slippery Side of Laffer Curve Dynamics -We are now equipped to compute time series starting from different $p_0$ settings, like those in this lecture {doc}`money_inflation`. +We are now equipped to compute time series starting from different $p_0$ settings, like those in {doc}`money_inflation`. ```{code-cell} ipython3 :tags: [hide-cell] @@ -357,8 +373,8 @@ def draw_iterations(p0s, model, line_params, p0_bars, num_steps): # Draw labels axes[0].set_ylabel('$m_t$') axes[1].set_ylabel('$p_t$') - axes[2].set_ylabel('$\pi_t$') - axes[3].set_ylabel('$\mu_t$') + axes[2].set_ylabel(r'$\pi_t$') + axes[3].set_ylabel(r'$\mu_t$') axes[3].set_xlabel('timestep') for p_0, label in [(p0_bars[0], '$p_0=p_l$'), (p0_bars[1], '$p_0=p_u$')]: @@ -398,16 +414,16 @@ p0_bars = (p0_l, p0_u) draw_iterations(p0s, model, line_params, p0_bars, num_steps=20) ``` -Staring at the paths of price levels in {numref}`p0_path_nonlin` reveals that almost all paths converge to the **higher** inflation tax rate displayed in the stationary state Laffer curve. displayed in figure {numref}`laffer_curve_nonlinear`. +Staring at the paths of price levels in {numref}`p0_path_nonlin` reveals that almost all paths converge to the *higher* inflation tax rate displayed in the stationary state Laffer curve. displayed in figure {numref}`laffer_curve_nonlinear`. Thus, we have reconfirmed what we have called the "perverse" dynamics under rational expectations in which the system converges to the higher of two possible stationary inflation tax rates. Those dynamics are "perverse" not only in the sense that they imply that the monetary and fiscal authorities that have chosen to finance government expenditures eventually impose a higher inflation tax than required to finance government expenditures, but because of the following "counterintuitive" situation that we can deduce by staring at the stationary state Laffer curve displayed in figure {numref}`laffer_curve_nonlinear`: -* the figure indicates that inflation can be **reduced** by running **higher** government deficits, i.e., by raising more resources through printing money. +* the figure indicates that inflation can be *reduced* by running *higher* government deficits, i.e., by raising more resources through printing money. ```{note} -The same qualitive outcomes prevail in this lecture {doc}`money_inflation` that studies a linear version of the model in this lecture`. +The same qualitative outcomes prevail in {doc}`money_inflation` that studies a linear version of the model in this lecture. ``` We discovered that @@ -415,9 +431,9 @@ We discovered that * all but one of the equilibrium paths converge to limits in which the higher of two possible stationary inflation tax prevails * there is a unique equilibrium path associated with "plausible" statements about how reductions in government deficits affect a stationary inflation rate -As in this lecture {doc}`money_inflation`, +As in {doc}`money_inflation`, on grounds of plausibility, we again recommend selecting the unique equilibrium that converges to the lower stationary inflation tax rate. -As we shall see, we accepting this recommendation is a key ingredient of outcomes of the "unpleasant arithmetic" that we describe in lecture {doc}`unpleasant`. +As we shall see, we accepting this recommendation is a key ingredient of outcomes of the "unpleasant arithmetic" that we describe in {doc}`unpleasant`. -In lecture, {doc}`laffer_adaptive`, we shall explore how {cite}`bruno1990seigniorage` and others justified our equilibrium selection in other ways. +In {doc}`laffer_adaptive`, we shall explore how {cite}`bruno1990seigniorage` and others justified our equilibrium selection in other ways. diff --git a/lectures/monte_carlo.md b/lectures/monte_carlo.md index eecbd0114..9f66c2296 100644 --- a/lectures/monte_carlo.md +++ b/lectures/monte_carlo.md @@ -12,7 +12,7 @@ kernelspec: --- - +(monte-carlo)= # Monte Carlo and Option Pricing ## Overview @@ -49,7 +49,6 @@ from numpy.random import randn ``` - ## An introduction to Monte Carlo In this section we describe how Monte Carlo can be used to compute diff --git a/lectures/olg.md b/lectures/olg.md index 23b97701e..0794b2ce5 100644 --- a/lectures/olg.md +++ b/lectures/olg.md @@ -18,7 +18,7 @@ is used by policy makers and researchers to examine * fiscal policy * monetary policy -* long run growth +* long-run growth and many other topics. @@ -57,7 +57,7 @@ prices, etc.) The OLG model takes up this challenge. We will present a simple version of the OLG model that clarifies the decision -problem of households and studies the implications for long run growth. +problem of households and studies the implications for long-run growth. Let's start with some imports. @@ -70,7 +70,7 @@ import matplotlib.pyplot as plt ## Environment -We assume that time is discrete, so that $t=0, 1, \ldots$, +We assume that time is discrete, so that $t=0, 1, \ldots$. An individual born at time $t$ lives for two periods, $t$ and $t + 1$. @@ -144,7 +144,7 @@ Here - $s_t$ is savings by an individual born at time $t$ - $w_t$ is the wage rate at time $t$ -- $R_{t+1}$ is the interest rate on savings invested at time $t$, paid at time $t+1$ +- $R_{t+1}$ is the gross interest rate on savings invested at time $t$, paid at time $t+1$ Since $u$ is strictly increasing, both of these constraints will hold as equalities at the maximum. @@ -155,7 +155,7 @@ The first-order condition for a maximum can be obtained by plugging $c_{t+1}$ into the objective function, taking the derivative with respect to $c_t$, and setting it to zero. -This leads to the **Euler equation** of the OLG model, which is +This leads to the **Euler equation** of the OLG model, which describes the optimal intertemporal consumption dynamics: ```{math} :label: euler_1_olg @@ -225,7 +225,7 @@ economy. ## Demand for capital -First we describe the firm problem and then we write down an equation +First we describe the firm's problem and then we write down an equation describing demand for capital given prices. @@ -246,7 +246,7 @@ The profit maximization problem of the firm is ```{math} :label: opt_profit_olg - \max_{k_t, \ell_t} \{ k^{\alpha}_t \ell_t^{1-\alpha} - R_t k_t - \ell_t w_t \} + \max_{k_t, \ell_t} \{ k^{\alpha}_t \ell_t^{1-\alpha} - R_t k_t -w_t \ell_t \} ``` The first-order conditions are obtained by taking the derivative of the @@ -303,24 +303,6 @@ The next figure plots the supply of capital, as in [](saving_log_2_olg), as well (For the special case of log utility, supply does not depend on the interest rate, so we have a constant function.) -```{code-cell} ipython3 -R_vals = np.linspace(0.3, 1) -α, β = 0.5, 0.9 -w = 2.0 - -fig, ax = plt.subplots() - -ax.plot(R_vals, capital_demand(R_vals, α), - label="aggregate demand") -ax.plot(R_vals, capital_supply(R_vals, β, w), - label="aggregate supply") - -ax.set_xlabel("$R_{t+1}$") -ax.set_ylabel("$k_{t+1}$") -ax.legend() -plt.show() -``` - ## Equilibrium In this section we derive equilibrium conditions and investigate an example. @@ -409,15 +391,7 @@ ax.plot(R_vals, capital_supply(R_vals, β, w), R_e = equilibrium_R_log_utility(α, β, w) k_e = (β / (1 + β)) * w -ax.plot(R_e, k_e, 'go', ms=6, alpha=0.6) - -ax.annotate(r'equilibrium', - xy=(R_e, k_e), - xycoords='data', - xytext=(0, 60), - textcoords='offset points', - fontsize=12, - arrowprops=dict(arrowstyle="->")) +ax.plot(R_e, k_e, 'o',label='equilibrium') ax.set_xlabel("$R_{t+1}$") ax.set_ylabel("$k_{t+1}$") @@ -447,7 +421,7 @@ In particular, since $w_t = (1-\alpha)k_t^\alpha$, we have If we iterate on this equation, we get a sequence for capital stock. -Let's plot the 45 degree diagram of these dynamics, which we write as +Let's plot the 45-degree diagram of these dynamics, which we write as $$ k_{t+1} = g(k_t) @@ -463,19 +437,16 @@ def k_update(k, α, β): ```{code-cell} ipython3 α, β = 0.5, 0.9 kmin, kmax = 0, 0.1 -x = 1000 -k_grid = np.linspace(kmin, kmax, x) -k_grid_next = np.empty_like(k_grid) - -for i in range(x): - k_grid_next[i] = k_update(k_grid[i], α, β) +n = 1000 +k_grid = np.linspace(kmin, kmax, n) +k_grid_next = k_update(k_grid,α,β) fig, ax = plt.subplots(figsize=(6, 6)) ymin, ymax = np.min(k_grid_next), np.max(k_grid_next) ax.plot(k_grid, k_grid_next, lw=2, alpha=0.6, label='$g$') -ax.plot(k_grid, k_grid, 'k-', lw=1, alpha=0.7, label='$45^{\circ}$') +ax.plot(k_grid, k_grid, 'k-', lw=1, alpha=0.7, label=r'$45^{\circ}$') ax.legend(loc='upper left', frameon=False, fontsize=12) @@ -520,7 +491,7 @@ R_star = (α/(1 - α)) * ((1 + β) / β) ### Time series -The 45 degree diagram above shows that time series of capital with positive initial conditions converge to this steady state. +The 45-degree diagram above shows that time series of capital with positive initial conditions converge to this steady state. Let's plot some time series that visualize this. @@ -554,6 +525,7 @@ fig, ax = plt.subplots() ax.plot(R_series, label="gross interest rate") ax.plot(range(ts_length), np.full(ts_length, R_star), 'k--', label="$R^*$") ax.set_ylim(0, 4) +ax.set_ylabel("gross interest rate") ax.set_xlabel("$t$") ax.legend() plt.show() @@ -567,7 +539,7 @@ The interest rate reflects the marginal product of capital, which is high when c Previously, in our examples, we looked at the case of log utility. -Log utility is a rather special case. +Log utility is a rather special case of CRRA utility with $\gamma \to 1$. In this section, we are going to assume that $u(c) = \frac{ c^{1- \gamma}-1}{1-\gamma}$, where $\gamma >0, \gamma\neq 1$. @@ -629,7 +601,6 @@ def savings_crra(w, R, model): ``` ```{code-cell} ipython3 -R_vals = np.linspace(0.3, 1) model = create_olg_model() w = 2.0 @@ -685,7 +656,7 @@ In the exercise below, you will be asked to solve these equations numerically. Solve for the dynamics of equilibrium capital stock in the CRRA case numerically using [](law_of_motion_capital_crra). -Visualize the dynamics using a 45 degree diagram. +Visualize the dynamics using a 45-degree diagram. ``` @@ -735,15 +706,15 @@ def k_update(k, model): return optimize.newton(lambda k_prime: f(k_prime, k, model), 0.1) ``` -Finally, here is the 45 degree diagram. +Finally, here is the 45-degree diagram. ```{code-cell} ipython3 kmin, kmax = 0, 0.5 -x = 1000 -k_grid = np.linspace(kmin, kmax, x) +n = 1000 +k_grid = np.linspace(kmin, kmax, n) k_grid_next = np.empty_like(k_grid) -for i in range(x): +for i in range(n): k_grid_next[i] = k_update(k_grid[i], model) fig, ax = plt.subplots(figsize=(6, 6)) @@ -751,7 +722,7 @@ fig, ax = plt.subplots(figsize=(6, 6)) ymin, ymax = np.min(k_grid_next), np.max(k_grid_next) ax.plot(k_grid, k_grid_next, lw=2, alpha=0.6, label='$g$') -ax.plot(k_grid, k_grid, 'k-', lw=1, alpha=0.7, label='$45^{\circ}$') +ax.plot(k_grid, k_grid, 'k-', lw=1, alpha=0.7, label=r'$45^{\circ}$') ax.legend(loc='upper left', frameon=False, fontsize=12) @@ -768,7 +739,7 @@ plt.show() ```{exercise} :label: olg_ex2 -The 45 degree diagram from the last exercise shows that there is a unique +The 45-degree diagram from the last exercise shows that there is a unique positive steady state. The positive steady state can be obtained by setting $k_{t+1} = k_t = k^*$ in [](law_of_motion_capital_crra), which yields diff --git a/lectures/prob_dist.md b/lectures/prob_dist.md index d8d04f7ee..9889b9196 100644 --- a/lectures/prob_dist.md +++ b/lectures/prob_dist.md @@ -4,14 +4,13 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.14.5 + jupytext_version: 1.16.6 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 --- - # Distributions and Probabilities ```{index} single: Distributions and Probabilities @@ -23,6 +22,7 @@ In this lecture we give a quick introduction to data and probability distributio ```{code-cell} ipython3 :tags: [hide-output] + !pip install --upgrade yfinance ``` @@ -35,7 +35,6 @@ import scipy.stats import seaborn as sns ``` - ## Common distributions In this section we recall the definitions of some well-known distributions and explore how to manipulate them with SciPy. @@ -46,18 +45,22 @@ Let's start with discrete distributions. A discrete distribution is defined by a set of numbers $S = \{x_1, \ldots, x_n\}$ and a **probability mass function** (PMF) on $S$, which is a function $p$ from $S$ to $[0,1]$ with the property -$$ \sum_{i=1}^n p(x_i) = 1 $$ +$$ +\sum_{i=1}^n p(x_i) = 1 +$$ We say that a random variable $X$ **has distribution** $p$ if $X$ takes value $x_i$ with probability $p(x_i)$. That is, -$$ \mathbb P\{X = x_i\} = p(x_i) \quad \text{for } i= 1, \ldots, n $$ +$$ +\mathbb P\{X = x_i\} = p(x_i) \quad \text{for } i= 1, \ldots, n +$$ The **mean** or **expected value** of a random variable $X$ with distribution $p$ is $$ - \mathbb{E}[X] = \sum_{i=1}^n x_i p(x_i) +\mathbb{E}[X] = \sum_{i=1}^n x_i p(x_i) $$ Expectation is also called the *first moment* of the distribution. @@ -67,7 +70,7 @@ We also refer to this number as the mean of the distribution (represented by) $p The **variance** of $X$ is defined as $$ - \mathbb{V}[X] = \sum_{i=1}^n (x_i - \mathbb{E}[X])^2 p(x_i) +\mathbb{V}[X] = \sum_{i=1}^n (x_i - \mathbb{E}[X])^2 p(x_i) $$ Variance is also called the *second central moment* of the distribution. @@ -75,8 +78,8 @@ Variance is also called the *second central moment* of the distribution. The **cumulative distribution function** (CDF) of $X$ is defined by $$ - F(x) = \mathbb{P}\{X \leq x\} - = \sum_{i=1}^n \mathbb 1\{x_i \leq x\} p(x_i) +F(x) = \mathbb{P}\{X \leq x\} + = \sum_{i=1}^n \mathbb 1\{x_i \leq x\} p(x_i) $$ Here $\mathbb 1\{ \textrm{statement} \} = 1$ if "statement" is true and zero otherwise. @@ -95,7 +98,6 @@ n = 10 u = scipy.stats.randint(1, n+1) ``` - Here's the mean and variance: ```{code-cell} ipython3 @@ -115,7 +117,6 @@ u.pmf(1) u.pmf(2) ``` - Here's a plot of the probability mass function: ```{code-cell} ipython3 @@ -124,10 +125,11 @@ S = np.arange(1, n+1) ax.plot(S, u.pmf(S), linestyle='', marker='o', alpha=0.8, ms=4) ax.vlines(S, 0, u.pmf(S), lw=0.2) ax.set_xticks(S) +ax.set_xlabel('S') +ax.set_ylabel('PMF') plt.show() ``` - Here's a plot of the CDF: ```{code-cell} ipython3 @@ -136,13 +138,13 @@ S = np.arange(1, n+1) ax.step(S, u.cdf(S)) ax.vlines(S, 0, u.cdf(S), lw=0.2) ax.set_xticks(S) +ax.set_xlabel('S') +ax.set_ylabel('CDF') plt.show() ``` - The CDF jumps up by $p(x_i)$ at $x_i$. - ```{exercise} :label: prob_ex1 @@ -158,55 +160,56 @@ Check that your answers agree with `u.mean()` and `u.var()`. Another useful distribution is the Bernoulli distribution on $S = \{0,1\}$, which has PMF: $$ -p(x_i)= -\begin{cases} -p & \text{if $x_i = 1$}\\ -1-p & \text{if $x_i = 0$} -\end{cases} +p(i) = \theta^i (1 - \theta)^{1-i} +\qquad (i = 0, 1) $$ -Here $x_i \in S$ is the outcome of the random variable. +Here $\theta \in [0,1]$ is a parameter. + +We can think of this distribution as modeling probabilities for a random trial with success probability $\theta$. + +* $p(1) = \theta$ means that the trial succeeds (takes value 1) with probability $\theta$ +* $p(0) = 1 - \theta$ means that the trial fails (takes value 0) with + probability $1-\theta$ + +The formula for the mean is $\theta$, and the formula for the variance is $\theta(1-\theta)$. We can import the Bernoulli distribution on $S = \{0,1\}$ from SciPy like so: ```{code-cell} ipython3 -p = 0.4 -u = scipy.stats.bernoulli(p) +θ = 0.4 +u = scipy.stats.bernoulli(θ) ``` - -Here's the mean and variance: +Here's the mean and variance at $\theta=0.4$ ```{code-cell} ipython3 u.mean(), u.var() ``` -The formula for the mean is $p$, and the formula for the variance is $p(1-p)$. - - -Now let's evaluate the PMF: +We can evaluate the PMF as follows ```{code-cell} ipython3 -u.pmf(0) -u.pmf(1) +u.pmf(0), u.pmf(1) ``` - #### Binomial distribution Another useful (and more interesting) distribution is the **binomial distribution** on $S=\{0, \ldots, n\}$, which has PMF: $$ - p(i) = \binom{n}{i} \theta^i (1-\theta)^{n-i} +p(i) = \binom{n}{i} \theta^i (1-\theta)^{n-i} $$ -Here $\theta \in [0,1]$ is a parameter. +Again, $\theta \in [0,1]$ is a parameter. The interpretation of $p(i)$ is: the probability of $i$ successes in $n$ independent trials with success probability $\theta$. For example, if $\theta=0.5$, then $p(i)$ is the probability of $i$ heads in $n$ flips of a fair coin. -The mean and variance are: +The formula for the mean is $n \theta$ and the formula for the variance is $n \theta (1-\theta)$. + +Let's investigate an example ```{code-cell} ipython3 n = 10 @@ -214,11 +217,17 @@ n = 10 u = scipy.stats.binom(n, θ) ``` +According to our formulas, the mean and variance are + ```{code-cell} ipython3 -u.mean(), u.var() +n * θ, n * θ * (1 - θ) ``` -The formula for the mean is $n \theta$ and the formula for the variance is $n \theta (1-\theta)$. +Let's see if SciPy gives us the same results: + +```{code-cell} ipython3 +u.mean(), u.var() +``` Here's the PMF: @@ -232,10 +241,11 @@ S = np.arange(1, n+1) ax.plot(S, u.pmf(S), linestyle='', marker='o', alpha=0.8, ms=4) ax.vlines(S, 0, u.pmf(S), lw=0.2) ax.set_xticks(S) +ax.set_xlabel('S') +ax.set_ylabel('PMF') plt.show() ``` - Here's the CDF: ```{code-cell} ipython3 @@ -244,10 +254,11 @@ S = np.arange(1, n+1) ax.step(S, u.cdf(S)) ax.vlines(S, 0, u.cdf(S), lw=0.2) ax.set_xticks(S) +ax.set_xlabel('S') +ax.set_ylabel('CDF') plt.show() ``` - ```{exercise} :label: prob_ex3 @@ -267,6 +278,8 @@ u_sum = np.cumsum(u.pmf(S)) ax.step(S, u_sum) ax.vlines(S, 0, u_sum, lw=0.2) ax.set_xticks(S) +ax.set_xlabel('S') +ax.set_ylabel('CDF') plt.show() ``` @@ -275,35 +288,68 @@ We can see that the output graph is the same as the one above. ```{solution-end} ``` -#### Poisson distribution +#### Geometric distribution -Poisson distribution on $S = \{0, 1, \ldots\}$ with parameter $\lambda > 0$ has PMF +The geometric distribution has infinite support $S = \{0, 1, 2, \ldots\}$ and its PMF is given by $$ - p(i) = \frac{\lambda^i}{i!} e^{-\lambda} +p(i) = (1 - \theta)^i \theta $$ -The interpretation of $p(i)$ is: the probability of $i$ events in a fixed time interval, where the events occur at a constant rate $\lambda$ and independently of each other. +where $\theta \in [0,1]$ is a parameter + +(A discrete distribution has infinite support if the set of points to which it assigns positive probability is infinite.) + +To understand the distribution, think of repeated independent random trials, each with success probability $\theta$. + +The interpretation of $p(i)$ is: the probability there are $i$ failures before the first success occurs. + +It can be shown that the mean of the distribution is $1/\theta$ and the variance is $(1-\theta)/\theta$. + +Here's an example. -The mean and variance are: ```{code-cell} ipython3 -λ = 2 -u = scipy.stats.poisson(λ) +θ = 0.1 +u = scipy.stats.geom(θ) +u.mean(), u.var() ``` - + +Here's part of the PMF: + ```{code-cell} ipython3 -u.mean(), u.var() +fig, ax = plt.subplots() +n = 20 +S = np.arange(n) +ax.plot(S, u.pmf(S), linestyle='', marker='o', alpha=0.8, ms=4) +ax.vlines(S, 0, u.pmf(S), lw=0.2) +ax.set_xticks(S) +ax.set_xlabel('S') +ax.set_ylabel('PMF') +plt.show() ``` -The the expectation of Poisson distribution is $\lambda$ and the variance is also $\lambda$. +#### Poisson distribution -Here's the PMF: +The Poisson distribution on $S = \{0, 1, \ldots\}$ with parameter $\lambda > 0$ has PMF + +$$ +p(i) = \frac{\lambda^i}{i!} e^{-\lambda} +$$ + +The interpretation of $p(i)$ is: the probability of $i$ events in a fixed time interval, where the events occur independently at a constant rate $\lambda$. + +It can be shown that the mean is $\lambda$ and the variance is also $\lambda$. + +Here's an example. ```{code-cell} ipython3 λ = 2 u = scipy.stats.poisson(λ) +u.mean(), u.var() ``` +Here's the PMF: + ```{code-cell} ipython3 u.pmf(1) ``` @@ -314,21 +360,24 @@ S = np.arange(1, n+1) ax.plot(S, u.pmf(S), linestyle='', marker='o', alpha=0.8, ms=4) ax.vlines(S, 0, u.pmf(S), lw=0.2) ax.set_xticks(S) +ax.set_xlabel('S') +ax.set_ylabel('PMF') plt.show() ``` - ### Continuous distributions -Continuous distributions are represented by a **probability density function**, which is a function $p$ over $\mathbb R$ (the set of all real numbers) such that $p(x) \geq 0$ for all $x$ and +A continuous distribution is represented by a **probability density function**, which is a function $p$ over $\mathbb R$ (the set of all real numbers) such that $p(x) \geq 0$ for all $x$ and -$$ \int_{-\infty}^\infty p(x) dx = 1 $$ +$$ +\int_{-\infty}^\infty p(x) dx = 1 +$$ We say that random variable $X$ has distribution $p$ if $$ - \mathbb P\{a < X < b\} = \int_a^b p(x) dx +\mathbb P\{a < X < b\} = \int_a^b p(x) dx $$ for all $a \leq b$. @@ -338,14 +387,14 @@ The definition of the mean and variance of a random variable $X$ with distributi For example, the mean of $X$ is $$ - \mathbb{E}[X] = \int_{-\infty}^\infty x p(x) dx +\mathbb{E}[X] = \int_{-\infty}^\infty x p(x) dx $$ The **cumulative distribution function** (CDF) of $X$ is defined by $$ - F(x) = \mathbb P\{X \leq x\} - = \int_{-\infty}^x p(x) dx +F(x) = \mathbb P\{X \leq x\} + = \int_{-\infty}^x p(x) dx $$ @@ -354,15 +403,15 @@ $$ Perhaps the most famous distribution is the **normal distribution**, which has density $$ - p(x) = \frac{1}{\sqrt{2\pi}\sigma} - \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right) +p(x) = \frac{1}{\sqrt{2\pi}\sigma} + \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right) $$ -This distribution has two parameters, $\mu$ and $\sigma$. +This distribution has two parameters, $\mu \in \mathbb R$ and $\sigma \in (0, \infty)$. -It can be shown that, for this distribution, the mean is $\mu$ and the variance is $\sigma^2$. +Using calculus, it can be shown that, for this distribution, the mean is $\mu$ and the variance is $\sigma^2$. -We can obtain the moments, PDF and CDF of the normal density as follows: +We can obtain the moments, PDF and CDF of the normal density via SciPy as follows: ```{code-cell} ipython3 μ, σ = 0.0, 1.0 @@ -385,13 +434,13 @@ for μ, σ in zip(μ_vals, σ_vals): u = scipy.stats.norm(μ, σ) ax.plot(x_grid, u.pdf(x_grid), alpha=0.5, lw=2, - label=f'$\mu={μ}, \sigma={σ}$') - + label=rf'$\mu={μ}, \sigma={σ}$') +ax.set_xlabel('x') +ax.set_ylabel('PDF') plt.legend() plt.show() ``` - Here's a plot of the CDF: ```{code-cell} ipython3 @@ -400,29 +449,31 @@ for μ, σ in zip(μ_vals, σ_vals): u = scipy.stats.norm(μ, σ) ax.plot(x_grid, u.cdf(x_grid), alpha=0.5, lw=2, - label=f'$\mu={μ}, \sigma={σ}$') + label=rf'$\mu={μ}, \sigma={σ}$') ax.set_ylim(0, 1) +ax.set_xlabel('x') +ax.set_ylabel('CDF') plt.legend() plt.show() ``` - #### Lognormal distribution The **lognormal distribution** is a distribution on $\left(0, \infty\right)$ with density $$ - p(x) = \frac{1}{\sigma x \sqrt{2\pi}} - \exp \left(- \frac{\left(\log x - \mu\right)^2}{2 \sigma^2} \right) +p(x) = \frac{1}{\sigma x \sqrt{2\pi}} + \exp \left(- \frac{\left(\log x - \mu\right)^2}{2 \sigma^2} \right) $$ This distribution has two parameters, $\mu$ and $\sigma$. It can be shown that, for this distribution, the mean is $\exp\left(\mu + \sigma^2/2\right)$ and the variance is $\left[\exp\left(\sigma^2\right) - 1\right] \exp\left(2\mu + \sigma^2\right)$. -It has a nice interpretation: if $X$ is lognormally distributed, then $\log X$ is normally distributed. +It can be proved that -It is often used to model variables that are "multiplicative" in nature, such as income or asset prices. +* if $X$ is lognormally distributed, then $\log X$ is normally distributed, and +* if $X$ is normally distributed, then $\exp X$ is lognormally distributed. We can obtain the moments, PDF, and CDF of the lognormal density as follows: @@ -445,8 +496,9 @@ for μ, σ in zip(μ_vals, σ_vals): u = scipy.stats.lognorm(σ, scale=np.exp(μ)) ax.plot(x_grid, u.pdf(x_grid), alpha=0.5, lw=2, - label=f'$\mu={μ}, \sigma={σ}$') - + label=fr'$\mu={μ}, \sigma={σ}$') +ax.set_xlabel('x') +ax.set_ylabel('PDF') plt.legend() plt.show() ``` @@ -458,24 +510,27 @@ for σ in σ_vals: u = scipy.stats.norm(μ, σ) ax.plot(x_grid, u.cdf(x_grid), alpha=0.5, lw=2, - label=f'$\mu={μ}, \sigma={σ}$') + label=rf'$\mu={μ}, \sigma={σ}$') ax.set_ylim(0, 1) ax.set_xlim(0, 3) +ax.set_xlabel('x') +ax.set_ylabel('CDF') plt.legend() plt.show() ``` #### Exponential distribution -The **exponential distribution** is a distribution on $\left(0, \infty\right)$ with density +The **exponential distribution** is a distribution supported on $\left(0, \infty\right)$ with density $$ - p(x) = \lambda \exp \left( - \lambda x \right) +p(x) = \lambda \exp \left( - \lambda x \right) +\qquad (x > 0) $$ -This distribution has one parameter, $\lambda$. +This distribution has one parameter $\lambda$. -It is related to the Poisson distribution as it describes the distribution of the length of the time interval between two consecutive events in a Poisson process. +The exponential distribution can be thought of as the continuous analog of the geometric distribution. It can be shown that, for this distribution, the mean is $1/\lambda$ and the variance is $1/\lambda^2$. @@ -499,7 +554,9 @@ for λ in λ_vals: u = scipy.stats.expon(scale=1/λ) ax.plot(x_grid, u.pdf(x_grid), alpha=0.5, lw=2, - label=f'$\lambda={λ}$') + label=rf'$\lambda={λ}$') +ax.set_xlabel('x') +ax.set_ylabel('PDF') plt.legend() plt.show() ``` @@ -510,8 +567,10 @@ for λ in λ_vals: u = scipy.stats.expon(scale=1/λ) ax.plot(x_grid, u.cdf(x_grid), alpha=0.5, lw=2, - label=f'$\lambda={λ}$') + label=rf'$\lambda={λ}$') ax.set_ylim(0, 1) +ax.set_xlabel('x') +ax.set_ylabel('CDF') plt.legend() plt.show() ``` @@ -521,8 +580,8 @@ plt.show() The **beta distribution** is a distribution on $(0, 1)$ with density $$ - p(x) = \frac{\Gamma(\alpha + \beta)}{\Gamma(\alpha) \Gamma(\beta)} - x^{\alpha - 1} (1 - x)^{\beta - 1} +p(x) = \frac{\Gamma(\alpha + \beta)}{\Gamma(\alpha) \Gamma(\beta)} + x^{\alpha - 1} (1 - x)^{\beta - 1} $$ where $\Gamma$ is the [gamma function](https://en.wikipedia.org/wiki/Gamma_function). @@ -556,7 +615,9 @@ for α, β in zip(α_vals, β_vals): u = scipy.stats.beta(α, β) ax.plot(x_grid, u.pdf(x_grid), alpha=0.5, lw=2, - label=fr'$\alpha={α}, \beta={β}$') + label=rf'$\alpha={α}, \beta={β}$') +ax.set_xlabel('x') +ax.set_ylabel('PDF') plt.legend() plt.show() ``` @@ -567,20 +628,21 @@ for α, β in zip(α_vals, β_vals): u = scipy.stats.beta(α, β) ax.plot(x_grid, u.cdf(x_grid), alpha=0.5, lw=2, - label=fr'$\alpha={α}, \beta={β}$') + label=rf'$\alpha={α}, \beta={β}$') ax.set_ylim(0, 1) +ax.set_xlabel('x') +ax.set_ylabel('CDF') plt.legend() plt.show() ``` - #### Gamma distribution The **gamma distribution** is a distribution on $\left(0, \infty\right)$ with density $$ - p(x) = \frac{\beta^\alpha}{\Gamma(\alpha)} - x^{\alpha - 1} \exp(-\beta x) +p(x) = \frac{\beta^\alpha}{\Gamma(\alpha)} + x^{\alpha - 1} \exp(-\beta x) $$ This distribution has two parameters, $\alpha > 0$ and $\beta > 0$. @@ -613,7 +675,9 @@ for α, β in zip(α_vals, β_vals): u = scipy.stats.gamma(α, scale=1/β) ax.plot(x_grid, u.pdf(x_grid), alpha=0.5, lw=2, - label=fr'$\alpha={α}, \beta={β}$') + label=rf'$\alpha={α}, \beta={β}$') +ax.set_xlabel('x') +ax.set_ylabel('PDF') plt.legend() plt.show() ``` @@ -624,8 +688,10 @@ for α, β in zip(α_vals, β_vals): u = scipy.stats.gamma(α, scale=1/β) ax.plot(x_grid, u.cdf(x_grid), alpha=0.5, lw=2, - label=fr'$\alpha={α}, \beta={β}$') + label=rf'$\alpha={α}, \beta={β}$') ax.set_ylim(0, 1) +ax.set_xlabel('x') +ax.set_ylabel('CDF') plt.legend() plt.show() ``` @@ -653,7 +719,6 @@ df = pd.DataFrame(data, columns=['name', 'income']) df ``` - In this situation, we might refer to the set of their incomes as the "income distribution." The terminology is confusing because this set is not a probability distribution @@ -672,32 +737,33 @@ Suppose we have an observed distribution with values $\{x_1, \ldots, x_n\}$ The **sample mean** of this distribution is defined as $$ - \bar x = \frac{1}{n} \sum_{i=1}^n x_i +\bar x = \frac{1}{n} \sum_{i=1}^n x_i $$ The **sample variance** is defined as $$ - \frac{1}{n} \sum_{i=1}^n (x_i - \bar x)^2 +\frac{1}{n} \sum_{i=1}^n (x_i - \bar x)^2 $$ For the income distribution given above, we can calculate these numbers via ```{code-cell} ipython3 -x = np.asarray(df['income']) -``` - -```{code-cell} ipython3 +x = df['income'] x.mean(), x.var() ``` - ```{exercise} :label: prob_ex4 -Check that the formulas given above produce the same numbers. +If you try to check that the formulas given above for the sample mean and sample +variance produce the same numbers, you will see that the variance isn't quite +right. This is because SciPy uses $1/(n-1)$ instead of $1/n$ as the term at the +front of the variance. (Some books define the sample variance this way.) +Confirm. ``` + ### Visualization Let's look at different ways that we can visualize one or more observed distributions. @@ -708,26 +774,22 @@ We will cover - kernel density estimates and - violin plots -+++ {"user_expressions": []} #### Histograms -+++ {"user_expressions": []} - We can histogram the income distribution we just constructed as follows ```{code-cell} ipython3 -x = df['income'] fig, ax = plt.subplots() ax.hist(x, bins=5, density=True, histtype='bar') +ax.set_xlabel('income') +ax.set_ylabel('density') plt.show() ``` -+++ {"user_expressions": []} - Let's look at a distribution from real data. -In particular, we will look at the monthly return on Amazon shares between 2000/1/1 and 2023/1/1. +In particular, we will look at the monthly return on Amazon shares between 2000/1/1 and 2024/1/1. The monthly return is calculated as the percent change in the share price over each month. @@ -735,45 +797,43 @@ So we will have one observation for each month. ```{code-cell} ipython3 :tags: [hide-output] -df = yf.download('AMZN', '2000-1-1', '2023-1-1', interval='1mo' ) -prices = df['Adj Close'] -data = prices.pct_change()[1:] * 100 -data.head() -``` -+++ {"user_expressions": []} +df = yf.download('AMZN', '2000-1-1', '2024-1-1', interval='1mo') +prices = df['Close'] +x_amazon = prices.pct_change()[1:] * 100 +x_amazon.head() +``` The first observation is the monthly return (percent change) over January 2000, which was ```{code-cell} ipython3 -data[0] +x_amazon.iloc[0] ``` -+++ {"user_expressions": []} - Let's turn the return observations into an array and histogram it. -```{code-cell} ipython3 -x_amazon = np.asarray(data) -``` - ```{code-cell} ipython3 fig, ax = plt.subplots() ax.hist(x_amazon, bins=20) +ax.set_xlabel('monthly return (percent change)') +ax.set_ylabel('density') plt.show() ``` -+++ {"user_expressions": []} - #### Kernel density estimates -Kernel density estimate (KDE) is a non-parametric way to estimate and visualize the PDF of a distribution. +Kernel density estimates (KDE) provide a simple way to estimate and visualize the density of a distribution. + +If you are not familiar with KDEs, you can think of them as a smoothed +histogram. -KDE will generate a smooth curve that approximates the PDF. +Let's have a look at a KDE formed from the Amazon return data. ```{code-cell} ipython3 fig, ax = plt.subplots() sns.kdeplot(x_amazon, ax=ax) +ax.set_xlabel('monthly return (percent change)') +ax.set_ylabel('KDE') plt.show() ``` @@ -784,6 +844,8 @@ fig, ax = plt.subplots() sns.kdeplot(x_amazon, ax=ax, bw_adjust=0.1, alpha=0.5, label="bw=0.1") sns.kdeplot(x_amazon, ax=ax, bw_adjust=0.5, alpha=0.5, label="bw=0.5") sns.kdeplot(x_amazon, ax=ax, bw_adjust=1, alpha=0.5, label="bw=1") +ax.set_xlabel('monthly return (percent change)') +ax.set_ylabel('KDE') plt.legend() plt.show() ``` @@ -795,51 +857,53 @@ A suitable bandwidth is not too smooth (underfitting) or too wiggly (overfitting #### Violin plots -+++ {"user_expressions": []} -Yet another way to display an observed distribution is via a violin plot. +Another way to display an observed distribution is via a violin plot. ```{code-cell} ipython3 fig, ax = plt.subplots() ax.violinplot(x_amazon) +ax.set_ylabel('monthly return (percent change)') +ax.set_xlabel('KDE') plt.show() ``` -+++ {"user_expressions": []} - Violin plots are particularly useful when we want to compare different distributions. -For example, let's compare the monthly returns on Amazon shares with the monthly return on Apple shares. +For example, let's compare the monthly returns on Amazon shares with the monthly return on Costco shares. ```{code-cell} ipython3 :tags: [hide-output] -df = yf.download('AAPL', '2000-1-1', '2023-1-1', interval='1mo' ) -prices = df['Adj Close'] -data = prices.pct_change()[1:] * 100 -x_apple = np.asarray(data) + +df = yf.download('COST', '2000-1-1', '2024-1-1', interval='1mo') +prices = df['Close'] +x_costco = prices.pct_change()[1:] * 100 ``` ```{code-cell} ipython3 fig, ax = plt.subplots() -ax.violinplot([x_amazon, x_apple]) +ax.violinplot([x_amazon['AMZN'], x_costco['COST']]) +ax.set_ylabel('monthly return (percent change)') +ax.set_xlabel('retailers') + +ax.set_xticks([1, 2]) +ax.set_xticklabels(['Amazon', 'Costco']) plt.show() ``` -+++ {"user_expressions": []} - ### Connection to probability distributions -+++ {"user_expressions": []} - Let's discuss the connection between observed distributions and probability distributions. Sometimes it's helpful to imagine that an observed distribution is generated by a particular probability distribution. For example, we might look at the returns from Amazon above and imagine that they were generated by a normal distribution. -Even though this is not true, it might be a helpful way to think about the data. +(Even though this is not true, it *might* be a helpful way to think about the data.) -Here we match a normal distribution to the Amazon monthly returns by setting the sample mean to the mean of the normal distribution and the sample variance equal to the variance. +Here we match a normal distribution to the Amazon monthly returns by setting the +sample mean to the mean of the normal distribution and the sample variance equal +to the variance. Then we plot the density and the histogram. @@ -855,17 +919,15 @@ x_grid = np.linspace(-50, 65, 200) fig, ax = plt.subplots() ax.plot(x_grid, u.pdf(x_grid)) ax.hist(x_amazon, density=True, bins=40) +ax.set_xlabel('monthly return (percent change)') +ax.set_ylabel('density') plt.show() ``` -+++ {"user_expressions": []} - -The match between the histogram and the density is not very bad but also not very good. +The match between the histogram and the density is not bad but also not very good. One reason is that the normal distribution is not really a good fit for this observed data --- we will discuss this point again when we talk about {ref}`heavy tailed distributions`. -+++ {"user_expressions": []} - Of course, if the data really *is* generated by the normal distribution, then the fit will be better. Let's see this in action @@ -882,12 +944,11 @@ x_grid = np.linspace(-4, 4, 200) fig, ax = plt.subplots() ax.plot(x_grid, u.pdf(x_grid)) ax.hist(x_draws, density=True, bins=40) +ax.set_xlabel('x') +ax.set_ylabel('density') plt.show() ``` -+++ {"user_expressions": []} - Note that if you keep increasing $N$, which is the number of observations, the fit will get better and better. This convergence is a version of the "law of large numbers", which we will discuss {ref}`later`. - diff --git a/lectures/pv.md b/lectures/pv.md index 595f749e0..da7d925d0 100644 --- a/lectures/pv.md +++ b/lectures/pv.md @@ -172,7 +172,7 @@ $$ 0 \\ 0 \\ \vdots \\ - p^*_{T+1} + \delta p^*_{T+1} \end{bmatrix} $$ @@ -454,11 +454,11 @@ $$ :label: pv_ex_a ``` -Give analytical expressions for an asset price $p_t$ under the +Assume that $g >1$ and that $\delta g \in (0,1)$. Give analytical expressions for an asset price $p_t$ under the following settings for $d$ and $p_{T+1}^*$: 1. $p_{T+1}^* = 0, d_t = g^t d_0$ (a modified version of the Gordon growth formula) -1. $p_{T+1}^* = g^{T+1} d_0, d_t = g^t d_0$ (the plain vanilla Gordon growth formula) +1. $p_{T+1}^* = \frac{g^{T+1} d_0}{1- \delta g}, d_t = g^t d_0$ (the plain vanilla Gordon growth formula) 1. $p_{T+1}^* = 0, d_t = 0$ (price of a worthless stock) 1. $p_{T+1}^* = c \delta^{-(T+1)}, d_t = 0$ (price of a pure bubble stock) @@ -470,12 +470,14 @@ following settings for $d$ and $p_{T+1}^*$: :class: dropdown ``` -Plugging each pair of the above $p_{T+1}^*, d_t$ into Equation {eq}`eq:ptpveq` yields: +Plugging each of the above $p_{T+1}^*, d_t$ pairs into Equation {eq}`eq:ptpveq` yields: -1. $p_t = \sum^T_{s=t} \delta^{s-t} g^s d_0$ -1. $p_t = \sum^T_{s=t} \delta^{s-t} g^s d_0 + \delta^{T+1-t} g^{T+1} d_0$ -1. $p_t = 0$ -1. $p_t = c \delta^{-t}$ +1. $ p_t = \sum^T_{s=t} \delta^{s-t} g^s d_0 = d_t \frac{1 - (\delta g)^{T+1-t}}{1 - \delta g}$ + + +2. $p_t = \sum^T_{s=t} \delta^{s-t} g^s d_0 + \frac{\delta^{T+1-t} g^{T+1} d_0}{1 - \delta g} = \frac{d_t}{1 - \delta g}$ +3. $p_t = 0$ +4. $p_t = c \delta^{-t}$ ```{solution-end} diff --git a/lectures/scalar_dynam.md b/lectures/scalar_dynam.md index d642dc6bb..5926a3f60 100644 --- a/lectures/scalar_dynam.md +++ b/lectures/scalar_dynam.md @@ -20,22 +20,31 @@ kernelspec: (scalar_dynam)= # Dynamics in One Dimension -```{admonition} Migrated lecture -:class: warning - -This lecture has moved from our [Intermediate Quantitative Economics with Python](https://python.quantecon.org/intro.html) lecture series and is now a part of [A First Course in Quantitative Economics](https://intro.quantecon.org/intro.html). -``` ## Overview -In this lecture we give a quick introduction to discrete time dynamics in one dimension. +In economics many variables depend on their past values + +For example, it seems reasonable to believe that inflation last year with affects inflation this year. + +(Perhaps high inflation last year will lead people to demand higher wages to +compensate, which will feed into higher prices this year.) + +Letting $\pi_t$ be inflation this year and $\pi_{t-1}$ be inflation last year, we +can write this relationship in a general form as + +$$ \pi_t = f(\pi_{t-1}) $$ -* In one-dimensional models, the state of the system is described by a single variable. -* The variable is a number (that is, a point in $\mathbb R$). +where $f$ is some function describing the relationship between the variables. -While most quantitative models have two or more state variables, the -one-dimensional setting is a good place to learn the foundations of dynamics -and understand key concepts. +This equation is an example of one-dimensional discrete time dynamic system. + +In this lecture we cover the foundations of one-dimensional discrete time +dynamics. + +(While most quantitative models have two or more state variables, the +one-dimensional setting is a good place to learn foundations +and understand key concepts.) Let's start with some standard imports: @@ -44,6 +53,7 @@ import matplotlib.pyplot as plt import numpy as np ``` + ## Some definitions This section sets out the objects of interest and the kinds of properties we study. @@ -148,7 +158,7 @@ Equation {eq}`sdsod` is sometimes called a **first order difference equation** ### Example: a linear model One simple example of a dynamic system is when $S=\mathbb R$ and $g(x)=ax + -b$, where $a, b$ are constants (sometimes they are referred as parameters). +b$, where $a, b$ are constants (sometimes called ``parameters''). This leads to the **linear difference equation** @@ -205,16 +215,17 @@ This made analysis of dynamics very easy. When models are nonlinear, however, the situation can be quite different. -For example, the law of motion for the Solow-Swan growth model, a simplified version of which is +For example, in a later lecture {doc}`solow`, we will study the Solow-Swan growth model, which has dynamics ```{math} :label: solow_lom2 -k_{t+1} = s z k_t^{\alpha} + (1 - \delta) k_t +k_{t+1} = s A k_t^{\alpha} + (1 - \delta) k_t ``` -Here $k$ is the per capita capital stock and $s, z, \alpha, \delta$ are positive -parameters with $0 < \alpha, \delta < 1$. +Here $k=K/L$ is the per capita capital stock, $s$ is the saving rate, $A$ is the total factor productivity, $\alpha$ is the capital share, and $\delta$ is the depreciation rate. + +All these parameter are positive and $0 < \alpha, \delta < 1$. If you try to iterate like we did in {eq}`sdslinmodpath`, you will find that the algebra gets messy quickly. @@ -231,6 +242,7 @@ Analyzing the dynamics of this model requires a different method (see below). Consider a dynamic system consisting of set $S \subset \mathbb R$ and $g$ mapping $S$ to $S$. +(scalar-dynam:steady-state)= ### Steady states A **steady state** of this system is a @@ -250,6 +262,7 @@ definition to check that +(scalar-dynam:global-stability)= ### Global stability A steady state $x^*$ of the dynamic system is called @@ -281,12 +294,17 @@ $$ Obviously every globally stable steady state is also locally stable. -We will see examples below where the converse is not true. - +Here is an example where the converse is not true. +```{prf:example} +Consider the self-map $g$ on $\mathbb{R}$ defined by $g(x)=x^2$. The fixed point $1$ is not stable. +For example, $g^t (x)\to\infty$ for any $x>1$. +However, $0$ is locally stable, because $-1 0$. + with $a, b, \rho > 0$. + +Here, $\alpha$ is the output elasticity of capital and $\rho$ is a parameter that determines the elasticity of substitution between capital and labor. We assume a closed economy, so aggregate domestic investment equals aggregate domestic saving. @@ -81,6 +83,7 @@ Setting $k_t := K_t / L$ and using homogeneity of degree one now yields $$ k_{t+1} + = s \frac{F(K_t, L)}{L} + (1 - \delta) \frac{K_t}{L} = s \frac{F(K_t, L)}{L} + (1 - \delta) k_t = s F(k_t, 1) + (1 - \delta) k_t $$ @@ -100,8 +103,7 @@ given an exogenous initial capital stock $k_0$. ## A graphical perspective -To understand the dynamics of the sequence $(k_t)_{t \geq 0}$ we use a 45 -degree diagram. +To understand the dynamics of the sequence $(k_t)_{t \geq 0}$ we use a 45-degree diagram. To do so, we first need to specify the functional form for $f$ and assign values to the parameters. @@ -109,8 +111,7 @@ need to specify the functional form for $f$ and assign values to the parameters. We choose the Cobb--Douglas specification $f(k) = A k^\alpha$ and set $A=2.0$, $\alpha=0.3$, $s=0.3$ and $\delta=0.4$. -The function $g$ from {eq}`solow` is then plotted, along with the 45 -degree line. +The function $g$ from {eq}`solow` is then plotted, along with the 45-degree line. Let's define the constants. @@ -128,7 +129,7 @@ def g(A, s, alpha, delta, k): return A * s * k**alpha + (1 - delta) * k ``` -Let's plot the 45 degree diagram of $g$. +Let's plot the 45-degree diagram of $g$. ```{code-cell} ipython3 def plot45(kstar=None): @@ -145,7 +146,7 @@ def plot45(kstar=None): lb = r'$g(k) = sAk^{\alpha} + (1 - \delta)k$' ax.plot(xgrid, g_values, lw=2, alpha=0.6, label=lb) - ax.plot(xgrid, xgrid, 'k-', lw=1, alpha=0.7, label='45') + ax.plot(xgrid, xgrid, 'k-', lw=1, alpha=0.7, label=r'$45^{\circ}$') if kstar: fps = (kstar,) @@ -175,7 +176,7 @@ def plot45(kstar=None): plot45() ``` -Suppose, at some $k_t$, the value $g(k_t)$ lies strictly above the 45 degree line. +Suppose, at some $k_t$, the value $g(k_t)$ lies strictly above the 45-degree line. Then we have $k_{t+1} = g(k_t) > k_t$ and capital per worker rises. @@ -183,7 +184,7 @@ If $g(k_t) < k_t$ then capital per worker falls. If $g(k_t) = k_t$, then we are at a **steady state** and $k_t$ remains constant. -(A steady state of the model is a [fixed point](https://en.wikipedia.org/wiki/Fixed_point_(mathematics)) of the mapping $g$.) +(A {ref}`steady state ` of the model is a [fixed point](https://en.wikipedia.org/wiki/Fixed_point_(mathematics)) of the mapping $g$.) From the shape of the function $g$ in the figure, we see that there is a unique steady state in $(0, \infty)$. @@ -198,7 +199,7 @@ If initial capital is below $k^*$, then capital increases over time. If initial capital is above this level, then the reverse is true. -Let's plot the 45 degree diagram to show the $k^*$ in the plot. +Let's plot the 45-degree diagram to show the $k^*$ in the plot. ```{code-cell} ipython3 kstar = ((s * A) / delta)**(1/(1 - alpha)) @@ -209,7 +210,7 @@ plot45(kstar) From our graphical analysis, it appears that $(k_t)$ converges to $k^*$, regardless of initial capital $k_0$. -This is a form of global stability. +This is a form of {ref}`global stability `. The next figure shows three time paths for capital, from @@ -387,7 +388,7 @@ linear differential equation x'_t = (1-\alpha) (sA - \delta x_t) ``` -This equation has the exact solution +This equation, which is a [linear ordinary differential equation](https://math.libretexts.org/Bookshelves/Calculus/Calculus_(Guichard)/17%3A_Differential_Equations/17.01%3A_First_Order_Differential_Equations), has the solution $$ x_t diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md new file mode 100644 index 000000000..0ba1095ff --- /dev/null +++ b/lectures/tax_smooth.md @@ -0,0 +1,659 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Tax Smoothing + +## Overview + + +This is a sister lecture to our lecture on {doc}`consumption-smoothing `. + + +By renaming variables, we obtain a version of a model "tax-smoothing model" that Robert Barro {cite}`Barro1979` used to explain why governments sometimes choose not to balance their budgets every period but instead use issue debt to smooth tax rates over time. + +The government chooses a tax collection path that minimizes the present value of its costs of raising revenue. + + +The government minimizes those costs by smoothing tax collections over time and by issuing government debt during temporary surges in government expenditures. + + +The present value of government expenditures is at the core of the tax-smoothing model, +so we'll again use formulas presented in {doc}`present value formulas`. + +We'll again use the matrix multiplication and matrix inversion tools that we used in {doc}`present value formulas `. + + + + + + +## Analysis + +As usual, we'll start by importing some Python modules. + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from collections import namedtuple +``` + +A government exists at times $t=0, 1, \ldots, S$ and faces an exogenous stream of expenditures $\{G_t\}_{t=0}^S$. + +It chooses chooses a stream of tax collections $\{T_t\}_{t=0}^S$. + +The model takes a government expenditure stream as an "exogenous" input that is somehow determined outside the model. + +The government faces a gross interest rate of $R >1$ that is constant over time. + +The government can borrow or lend at interest rate $R$, subject to some limits on the amount of debt that it can issue that we'll describe below. + +Let + + * $S \geq 2$ be a positive integer that constitutes a time-horizon. + * $G = \{G_t\}_{t=0}^S$ be a sequence of government expenditures. + * $B = \{B_t\}_{t=0}^{S+1}$ be a sequence of government debt. + * $T = \{T_t\}_{t=0}^S$ be a sequence of tax collections. + * $R \geq 1$ be a fixed gross one period interest rate. + * $\beta \in (0,1)$ be a fixed discount factor. + * $B_0$ be a given initial level of government debt + * $B_{S+1} \geq 0$ be a terminal condition. + +The sequence of government debt $B$ is to be determined by the model. + +We require it to satisfy two **boundary conditions**: + * it must equal an exogenous value $B_0$ at time $0$ + * it must equal or exceed an exogenous value $B_{S+1}$ at time $S+1$. + +The **terminal condition** $B_{S+1} \geq 0$ requires that the government not end up with negative assets. + +(This no-Ponzi condition ensures that the government ultimately pays off its debts -- it can't simply roll them over indefinitely.) + +The government faces a sequence of budget constraints that constrain sequences $(G, T, B)$ + +$$ +B_{t+1} = R (B_t + G_t - T_t), \quad t =0, 1, \ldots S +$$ (eq:B_t) + +Equations {eq}`eq:B_t` constitute $S+1$ such budget constraints, one for each $t=0, 1, \ldots, S$. + +Given a sequence $G$ of government expenditures, a large set of pairs $(B, T)$ of (government debt, tax collections) sequences satisfy the sequence of budget constraints {eq}`eq:B_t`. + +The model follows the following logical flow: + + * start with an exogenous government expenditure sequence $G$, an initial government debt $B_0$, and + a candidate tax collection path $T$. + + * use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $B$ of government debt + + * verify that $B_{S+1}$ satisfies the terminal debt constraint $B_{S+1} \geq 0$. + + * If it does, declare that the candidate path is **budget feasible**. + + * if the candidate tax path is not budget feasible, propose a different tax path and start over + +Below, we'll describe how to execute these steps using linear algebra -- matrix inversion and multiplication. + +The above procedure seems like a sensible way to find "budget-feasible" tax paths $T$, i.e., paths that are consistent with the exogenous government expenditure stream $G$, the initial debt level $B_0$, and the terminal debt level $B_{S+1}$. + +In general, there are **many** budget feasible tax paths $T$. + +Among all budget-feasible tax paths, which one should a government choose? + +To answer this question, we assess alternative budget feasible tax paths $T$ using the following cost functional: + +```{math} +:label: cost + +L = - \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) +``` + +where $g_1 > 0, g_2 > 0$. + + +This is called the "present value of revenue-raising costs" in {cite}`Barro1979`. + +The quadratic term $-\frac{g_2}{2} T_t^2$ captures increasing marginal costs of taxation, implying that tax distortions rise more than proportionally with tax rates. + +This creates an incentive for tax smoothing. + +Indeed, we shall see that when $\beta R = 1$, criterion {eq}`cost` leads to smoother tax paths. + +By **smoother** we mean tax rates that are as close as possible to being constant over time. + +The preference for smooth tax paths that is built into the model gives it the name "tax-smoothing model". + +Or equivalently, we can transform this into the same problem as in the {doc}`consumption-smoothing ` lecture by maximizing the welfare criterion: + +```{math} +:label: welfare_tax + +W = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) +``` + +Let's dive in and do some calculations that will help us understand how the model works. + +Here we use default parameters $R = 1.05$, $g_1 = 1$, $g_2 = 1/2$, and $S = 65$. + +We create a Python ``namedtuple`` to store these parameters with default values. + +```{code-cell} ipython3 +TaxSmoothing = namedtuple("TaxSmoothing", + ["R", "g1", "g2", "β_seq", "S"]) + +def create_tax_smoothing_model(R=1.01, g1=1, g2=1/2, S=65): + """ + Creates an instance of the tax smoothing model. + """ + β = 1/R + β_seq = np.array([β**i for i in range(S+1)]) + + return TaxSmoothing(R, g1, g2, β_seq, S) +``` + +## Barro tax-smoothing model + +A key object is the present value of government expenditures at time $0$: + +$$ +h_0 \equiv \sum_{t=0}^S R^{-t} G_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} +\begin{bmatrix} G_0 \cr G_1 \cr \vdots \cr G_S \end{bmatrix} +$$ + +This sum represents the present value of all future government expenditures that must be financed. + +Formally it resembles the present value calculations we saw in this QuantEcon lecture {doc}`present values `. + +This present value calculation is crucial for determining the government's total financing needs. + +By iterating on equation {eq}`eq:B_t` and imposing the terminal condition + +$$ +B_{S+1} = 0, +$$ + +it is possible to convert a sequence of budget constraints {eq}`eq:B_t` into a single intertemporal constraint + +$$ +\sum_{t=0}^S R^{-t} T_t = B_0 + h_0. +$$ (eq:budget_intertemp_tax) + +Equation {eq}`eq:budget_intertemp_tax` says that the present value of tax collections must equal the sum of initial debt and the present value of government expenditures. + +When $\beta R = 1$, it is optimal for a government to smooth taxes by setting + +$$ +T_t = T_0 \quad t =0, 1, \ldots, S +$$ + +(Later we'll present a "variational argument" that shows that this constant path minimizes +criterion {eq}`cost` and maximizes {eq}`welfare_tax` when $\beta R =1$.) + +In this case, we can use the intertemporal budget constraint to write + +$$ +T_t = T_0 = \left(\sum_{t=0}^S R^{-t}\right)^{-1} (B_0 + h_0), \quad t= 0, 1, \ldots, S. +$$ (eq:taxsmoothing) + +Equation {eq}`eq:taxsmoothing` is the tax-smoothing model in a nutshell. + +## Mechanics of tax-smoothing + +As promised, we'll provide step-by-step instructions on how to use linear algebra, readily implemented in Python, to compute all objects in play in the tax-smoothing model. + +In the calculations below, we'll set default values of $R > 1$, e.g., $R = 1.05$, and $\beta = R^{-1}$. + +### Step 1 + +For a $(S+1) \times 1$ vector $G$ of government expenditures, use matrix algebra to compute the present value + +$$ +h_0 = \sum_{t=0}^S R^{-t} G_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} +\begin{bmatrix} G_0 \cr G_1 \cr \vdots \cr G_S \end{bmatrix} +$$ + +### Step 2 + +Compute a constant tax rate $T_0$: + +$$ +T_t = T_0 = \left( \frac{1 - R^{-1}}{1 - R^{-(S+1)}} \right) (B_0 + \sum_{t=0}^S R^{-t} G_t ) , \quad t = 0, 1, \ldots, S +$$ + +### Step 3 + +Use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $B$ of government debt. + +To do this, we transform that system of difference equations into a single matrix equation as follows: + +$$ +\begin{bmatrix} +1 & 0 & 0 & \cdots & 0 & 0 & 0 \cr +-R & 1 & 0 & \cdots & 0 & 0 & 0 \cr +0 & -R & 1 & \cdots & 0 & 0 & 0 \cr +\vdots &\vdots & \vdots & \cdots & \vdots & \vdots & \vdots \cr +0 & 0 & 0 & \cdots & -R & 1 & 0 \cr +0 & 0 & 0 & \cdots & 0 & -R & 1 +\end{bmatrix} +\begin{bmatrix} B_1 \cr B_2 \cr B_3 \cr \vdots \cr B_S \cr B_{S+1} +\end{bmatrix} += R +\begin{bmatrix} G_0 + B_0 - T_0 \cr G_1 - T_0 \cr G_2 - T_0 \cr \vdots\cr G_{S-1} - T_0 \cr G_S - T_0 +\end{bmatrix} +$$ + +Multiply both sides by the inverse of the matrix on the left side to compute + +$$ + \begin{bmatrix} B_1 \cr B_2 \cr B_3 \cr \vdots \cr B_S \cr B_{S+1} \end{bmatrix} +$$ + +Because we have built into our calculations that the government must satisfy its intertemporal budget constraint and end with zero debt, just barely satisfying the +terminal condition that $B_{S+1} \geq 0$, it should turn out that + +$$ +B_{S+1} = 0. +$$ + +Let's verify this with Python code. + +First we implement the model with `compute_optimal` + +```{code-cell} ipython3 +def compute_optimal(model, B0, G_seq): + + R, S = model.R, model.S + + # present value of government expenditures + h0 = model.β_seq @ G_seq # since β = 1/R + + # optimal constant tax rate + T0 = (1 - 1/R) / (1 - (1/R)**(S+1)) * (B0 + h0) + T_seq = T0*np.ones(S+1) + + A = np.diag(-R*np.ones(S), k=-1) + np.eye(S+1) + b = G_seq - T_seq + b[0] = b[0] + B0 + B_seq = np.linalg.inv(A) @ b + B_seq = np.concatenate([[B0], B_seq]) + + return T_seq, B_seq, h0 +``` + +We use an example where the government starts with initial debt $B_0>0$. + +This represents the government's initial debt burden. + +The government expenditure process $\{G_t\}_{t=0}^{S}$ is constant and positive up to $t=45$ and then drops to zero afterward. + +The drop in government expenditures could reflect a change in spending requirements or demographic shifts. + +```{code-cell} ipython3 +# Initial debt +B0 = 2 # initial government debt + +# Government expenditure process +G_seq = np.concatenate([np.ones(46), 4*np.ones(5), np.ones(15)]) +tax_model = create_tax_smoothing_model() +T_seq, B_seq, h0 = compute_optimal(tax_model, B0, G_seq) + +print('check B_S+1=0:', + np.abs(B_seq[-1] - 0) <= 1e-8) +``` + +The graphs below show paths of government expenditures, tax collections, and government debt. + +```{code-cell} ipython3 +# Sequence length +S = tax_model.S + +fig, axes = plt.subplots(1, 2, figsize=(12,5)) + +axes[0].plot(range(S+1), G_seq, label='expenditures', lw=2) +axes[0].plot(range(S+1), T_seq, label='tax', lw=2) +axes[1].plot(range(S+2), B_seq, label='debt', color='green', lw=2) +axes[0].set_ylabel(r'$T_t,G_t$') +axes[1].set_ylabel(r'$B_t$') + +for ax in axes: + ax.plot(range(S+2), np.zeros(S+2), '--', lw=1, color='black') + ax.legend() + ax.set_xlabel(r'$t$') + +plt.show() +``` + +Note that $B_{S+1} = 0$, as anticipated. + +We can evaluate cost criterion {eq}`cost` which measures the total cost / welfare of taxation + +```{code-cell} ipython3 +def cost(model, T_seq): + β_seq, g1, g2 = model.β_seq, model.g1, model.g2 + cost_seq = g1 * T_seq - g2/2 * T_seq**2 + return - β_seq @ cost_seq + +print('Cost:', cost(tax_model, T_seq)) + +def welfare(model, T_seq): + return - cost(model, T_seq) + +print('Welfare:', welfare(tax_model, T_seq)) +``` + +### Experiments + +In this section we describe how a tax sequence would optimally respond to different sequences of government expenditures. + +First we create a function `plot_ts` that generates graphs for different instances of the tax-smoothing model `tax_model`. + +This will help us avoid rewriting code to plot outcomes for different government expenditure sequences. + +```{code-cell} ipython3 +def plot_ts(model, # tax-smoothing model + B0, # initial government debt + G_seq # government expenditure process + ): + + # Compute optimal tax path + T_seq, B_seq, h0 = compute_optimal(model, B0, G_seq) + + # Sequence length + S = tax_model.S + + fig, axes = plt.subplots(1, 2, figsize=(12,5)) + + axes[0].plot(range(S+1), G_seq, label='expenditures', lw=2) + axes[0].plot(range(S+1), T_seq, label='taxes', lw=2) + axes[1].plot(range(S+2), B_seq, label='debt', color='green', lw=2) + axes[0].set_ylabel(r'$T_t,G_t$') + axes[1].set_ylabel(r'$B_t$') + + for ax in axes: + ax.plot(range(S+2), np.zeros(S+2), '--', lw=1, color='black') + ax.legend() + ax.set_xlabel(r'$t$') + + + plt.show() +``` + +In the experiments below, please study how tax and government debt sequences vary across different sequences for government expenditures. + +#### Experiment 1: one-time spending shock + +We first assume a one-time spending shock of $W_0$ in year 21 of the expenditure sequence $G$. + +We'll make $W_0$ big - positive to indicate a spending surge (like a war or disaster), and negative to indicate a spending cut. + +```{code-cell} ipython3 +# Spending surge W_0 = 2.5 +G_seq_pos = np.concatenate([np.ones(21), np.array([2.5]), +np.ones(24), np.ones(20)]) + +plot_ts(tax_model, B0, G_seq_pos) +``` + +#### Experiment 2: permanent expenditure shift + +Now we assume a permanent increase in government expenditures of $L$ in year 21 of the $G$-sequence. + +Again we can study positive and negative cases + +```{code-cell} ipython3 +# Positive temporary expenditure shift L = 0.5 when t >= 21 +G_seq_pos = np.concatenate( + [np.ones(21), 1.5*np.ones(25), np.ones(20)]) + +plot_ts(tax_model, B0, G_seq_pos) +``` + +```{code-cell} ipython3 +# Negative temporary expenditure shift L = -0.5 when t >= 21 +G_seq_neg = np.concatenate( + [np.ones(21), .5*np.ones(25), np.ones(20)]) + +plot_ts(tax_model, B0, G_seq_neg) +``` + +#### Experiment 3: delayed spending surge + +Now we simulate a $G$ sequence in which government expenditures are zero for 46 years, and then rise to 1 for the last 20 years (perhaps due to demographic aging) + +```{code-cell} ipython3 +# Delayed spending +G_seq_late = np.concatenate( + [np.ones(46), 2*np.ones(20)]) + +plot_ts(tax_model, B0, G_seq_late) +``` + +#### Experiment 4: growing expenditures + +Now we simulate a geometric $G$ sequence in which government expenditures grow at rate $G_t = \lambda^t G_0$ in first 46 years. + +We first experiment with $\lambda = 1.05$ (growing expenditures) + +```{code-cell} ipython3 +# Geometric growth parameters where λ = 1.05 +λ = 1.05 +G_0 = 1 +t_max = 46 + +# Generate geometric G sequence +geo_seq = λ ** np.arange(t_max) * G_0 +G_seq_geo = np.concatenate( + [geo_seq, np.max(geo_seq)*np.ones(20)]) + +plot_ts(tax_model, B0, G_seq_geo) +``` + +Now we show the behavior when $\lambda = 0.95$ (declining expenditures) + +```{code-cell} ipython3 +λ = 0.95 +geo_seq = λ ** np.arange(t_max) * G_0 +G_seq_geo = np.concatenate( + [geo_seq, λ ** t_max * np.ones(20)]) + +plot_ts(tax_model, B0, G_seq_geo) +``` + +What happens with oscillating expenditures + +```{code-cell} ipython3 +λ = -0.95 +geo_seq = λ ** np.arange(t_max) * G_0 + 1 +G_seq_geo = np.concatenate( + [geo_seq, np.ones(20)]) + +plot_ts(tax_model, B0, G_seq_geo) +``` + +### Feasible Tax Variations + +We promised to justify our claim that a constant tax rate $T_t = T_0$ for all $t$ is optimal. + +Let's do that now. + +The approach we'll take is an elementary example of the "calculus of variations". + +Let's dive in and see what the key idea is. + +To explore what types of tax paths are cost-minimizing / welfare-improving, we shall create an **admissible tax path variation sequence** $\{v_t\}_{t=0}^S$ +that satisfies + +$$ +\sum_{t=0}^S R^{-t} v_t = 0. +$$ + +This equation says that the **present value** of admissible tax path variations must be zero. + +So once again, we encounter a formula for the present value: + + * we require that the present value of tax path variations be zero to maintain budget balance. + +Here we'll restrict ourselves to a two-parameter class of admissible tax path variations of the form + +$$ +v_t = \xi_1 \phi^t - \xi_0. +$$ + +We say two and not three-parameter class because $\xi_0$ will be a function of $(\phi, \xi_1; R)$ that guarantees that the variation sequence is feasible. + +Let's compute that function. + +We require + +$$ +\sum_{t=0}^S R^{-t}\left[ \xi_1 \phi^t - \xi_0 \right] = 0 +$$ + +which implies that + +$$ +\xi_1 \sum_{t=0}^S \phi_t R^{-t} - \xi_0 \sum_{t=0}^S R^{-t} = 0 +$$ + +which implies that + +$$ +\xi_1 \frac{1 - (\phi R^{-1})^{S+1}}{1 - \phi R^{-1}} - \xi_0 \frac{1 - R^{-(S+1)}}{1-R^{-1} } =0 +$$ + +which implies that + +$$ +\xi_0 = \xi_0(\phi, \xi_1; R) = \xi_1 \left(\frac{1 - R^{-1}}{1 - R^{-(S+1)}}\right) \left(\frac{1 - (\phi R^{-1})^{S+1}}{1 - \phi R^{-1}}\right) +$$ + +This is our formula for $\xi_0$. + +**Key Idea:** if $T^o$ is a budget-feasible tax path, then so is $T^o + v$, +where $v$ is a budget-feasible variation. + +Given $R$, we thus have a two parameter class of budget feasible variations $v$ that we can use +to compute alternative tax paths, then evaluate their welfare costs. + +Now let's compute and plot tax path variations + +```{code-cell} ipython3 +def compute_variation(model, ξ1, ϕ, B0, G_seq, verbose=1): + R, S, β_seq = model.R, model.S, model.β_seq + + ξ0 = ξ1*((1 - 1/R) / (1 - (1/R)**(S+1))) * ((1 - (ϕ/R)**(S+1)) / (1 - ϕ/R)) + v_seq = np.array([(ξ1*ϕ**t - ξ0) for t in range(S+1)]) + + if verbose == 1: + print('check feasible:', np.isclose(β_seq @ v_seq, 0)) + + T_opt, _, _ = compute_optimal(model, B0, G_seq) + Tvar_seq = T_opt + v_seq + + return Tvar_seq +``` + +We visualize variations for $\xi_1 \in \{.01, .05\}$ and $\phi \in \{.95, 1.02\}$ + +```{code-cell} ipython3 +fig, ax = plt.subplots() +ξ1s = [.01, .05] +ϕs= [.95, 1.02] +colors = {.01: 'tab:blue', .05: 'tab:green'} +params = np.array(np.meshgrid(ξ1s, ϕs)).T.reshape(-1, 2) +wel_opt = welfare(tax_model, T_seq) + +for i, param in enumerate(params): + ξ1, ϕ = param + print(f'variation {i}: ξ1={ξ1}, ϕ={ϕ}') + + Tvar_seq = compute_variation(model=tax_model, + ξ1=ξ1, ϕ=ϕ, B0=B0, + G_seq=G_seq) + print(f'welfare={welfare(tax_model, Tvar_seq)}') + print(f'welfare < optimal: {welfare(tax_model, Tvar_seq) < wel_opt}') + print('-'*64) + + if i % 2 == 0: + ls = '-.' + else: + ls = '-' + ax.plot(range(S+1), Tvar_seq, ls=ls, + color=colors[ξ1], + label=fr'$\xi_1 = {ξ1}, \phi = {ϕ}$') + +plt.plot(range(S+1), T_seq, + color='orange', label=r'Optimal $\vec{T}$ ') + +plt.legend() +plt.xlabel(r'$t$') +plt.ylabel(r'$T_t$') +plt.show() +``` + +We can even use the Python `np.gradient` command to compute derivatives of cost with respect to our two parameters. + +We are teaching the key idea beneath the **calculus of variations**. +First, we define the cost with respect to $\xi_1$ and $\phi$ + +```{code-cell} ipython3 +def cost_rel(ξ1, ϕ): + """ + Compute cost of variation sequence + for given ϕ, ξ1 with a tax-smoothing model + """ + + Tvar_seq = compute_variation(tax_model, ξ1=ξ1, + ϕ=ϕ, B0=B0, + G_seq=G_seq, + verbose=0) + return cost(tax_model, Tvar_seq) + +# Vectorize the function to allow array input +cost_vec = np.vectorize(cost_rel) +``` + +Then we can visualize the relationship between cost and $\xi_1$ and compute its derivatives + +```{code-cell} ipython3 +ξ1_arr = np.linspace(-0.5, 0.5, 20) + +plt.plot(ξ1_arr, cost_vec(ξ1_arr, 1.02)) +plt.ylabel('cost') +plt.xlabel(r'$\xi_1$') +plt.show() + +cost_grad = cost_vec(ξ1_arr, 1.02) +cost_grad = np.gradient(cost_grad) +plt.plot(ξ1_arr, cost_grad) +plt.ylabel('derivative of cost') +plt.xlabel(r'$\xi_1$') +plt.show() +``` + +The same can be done on $\phi$ + +```{code-cell} ipython3 +ϕ_arr = np.linspace(-0.5, 0.5, 20) + +plt.plot(ξ1_arr, cost_vec(0.05, ϕ_arr)) +plt.ylabel('cost') +plt.xlabel(r'$\phi$') +plt.show() + +cost_grad = cost_vec(0.05, ϕ_arr) +cost_grad = np.gradient(cost_grad) +plt.plot(ξ1_arr, cost_grad) +plt.ylabel('derivative of cost') +plt.xlabel(r'$\phi$') +plt.show() +``` \ No newline at end of file diff --git a/lectures/time_series_with_matrices.md b/lectures/time_series_with_matrices.md index d0134b4d9..e73566cea 100644 --- a/lectures/time_series_with_matrices.md +++ b/lectures/time_series_with_matrices.md @@ -3,14 +3,16 @@ jupytext: text_representation: extension: .md format_name: myst + format_version: 0.13 + jupytext_version: 1.16.1 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- (time_series_with_matrices)= -```{raw} html +```{raw} jupyter
QuantEcon @@ -26,13 +28,12 @@ This lecture uses matrices to solve some linear difference equations. As a running example, we’ll study a **second-order linear difference equation** that was the key technical tool in Paul Samuelson’s 1939 -article {cite}`Samuelson1939` that introduced the **multiplier-accelerator** model. +article {cite}`Samuelson1939` that introduced the *multiplier-accelerator model*. This model became the workhorse that powered early econometric versions of Keynesian macroeconomic models in the United States. -You can read about the details of that model in [this](https://python.quantecon.org/samuelson.html) -QuantEcon lecture. +You can read about the details of that model in {doc}`intermediate:samuelson`. (That lecture also describes some technicalities about second-order linear difference equations.) @@ -44,12 +45,16 @@ a "forward-looking" linear difference equation. We will use the following imports: -```{code-cell} ipython +```{code-cell} ipython3 import numpy as np -%matplotlib inline import matplotlib.pyplot as plt from matplotlib import cm -plt.rcParams["figure.figsize"] = (11, 5) #set default figure size + +# Custom figsize for this lecture +plt.rcParams["figure.figsize"] = (11, 5) + +# Set decimal printing to 3 decimal places +np.set_printoptions(precision=3, suppress=True) ``` ## Samuelson's model @@ -65,20 +70,20 @@ y_{t} = \alpha_{0} + \alpha_{1} y_{t-1} + \alpha_{2} y_{t-2} ``` where we assume that $y_0$ and $y_{-1}$ are given numbers -that we take as **initial conditions**. +that we take as *initial conditions*. In Samuelson's model, $y_t$ stood for **national income** or perhaps a different measure of aggregate activity called **gross domestic product** (GDP) at time $t$. -Equation {eq}`tswm_1` is called a **second-order linear difference equation**. +Equation {eq}`tswm_1` is called a *second-order linear difference equation*. It is called second order because it depends on two lags. But actually, it is a collection of $T$ simultaneous linear equations in the $T$ variables $y_1, y_2, \ldots, y_T$. ```{note} To be able to solve a second-order linear difference -equation, we require two **boundary conditions** that can take the form -either of two **initial conditions** or two **terminal conditions** or +equation, we require two *boundary conditions* that can take the form +either of two *initial conditions*, two *terminal conditions* or possibly one of each. ``` @@ -132,42 +137,42 @@ The vector $y$ is a complete time path $\{y_t\}_{t=1}^T$. Let’s put Python to work on an example that captures the flavor of Samuelson’s multiplier-accelerator model. -We'll set parameters equal to the same values we used in [this QuantEcon lecture](https://python.quantecon.org/samuelson.html). +We'll set parameters equal to the same values we used in {doc}`intermediate:samuelson`. -```{code-cell} python3 +```{code-cell} ipython3 T = 80 # parameters -𝛼0 = 10.0 -𝛼1 = 1.53 -𝛼2 = -.9 +α_0 = 10.0 +α_1 = 1.53 +α_2 = -.9 -y_1 = 28. # y_{-1} -y0 = 24. +y_neg1 = 28.0 # y_{-1} +y_0 = 24.0 ``` Now we construct $A$ and $b$. -```{code-cell} python3 +```{code-cell} ipython3 A = np.identity(T) # The T x T identity matrix for i in range(T): if i-1 >= 0: - A[i, i-1] = -𝛼1 + A[i, i-1] = -α_1 if i-2 >= 0: - A[i, i-2] = -𝛼2 + A[i, i-2] = -α_2 -b = np.full(T, 𝛼0) -b[0] = 𝛼0 + 𝛼1 * y0 + 𝛼2 * y_1 -b[1] = 𝛼0 + 𝛼2 * y0 +b = np.full(T, α_0) +b[0] = α_0 + α_1 * y_0 + α_2 * y_neg1 +b[1] = α_0 + α_2 * y_0 ``` Let’s look at the matrix $A$ and the vector $b$ for our example. -```{code-cell} python3 +```{code-cell} ipython3 A, b ``` @@ -176,28 +181,34 @@ Now let’s solve for the path of $y$. If $y_t$ is GNP at time $t$, then we have a version of Samuelson’s model of the dynamics for GNP. -To solve $y = A^{-1} b$ we can either invert $A$ directly, as in +To solve $y = A^{-1} b$ we can either invert $A$ directly, as in -```{code-cell} python3 +```{code-cell} ipython3 A_inv = np.linalg.inv(A) y = A_inv @ b ``` -or we can use `np.linalg.solve`: +or we can use `np.linalg.solve`: - -```{code-cell} python3 +```{code-cell} ipython3 y_second_method = np.linalg.solve(A, b) ``` Here make sure the two methods give the same result, at least up to floating point precision: -```{code-cell} python3 +```{code-cell} ipython3 np.allclose(y, y_second_method) ``` +$A$ is invertible as it is lower triangular and [its diagonal entries are non-zero](https://www.statlect.com/matrix-algebra/triangular-matrix) + +```{code-cell} ipython3 +# Check if A is lower triangular +np.allclose(A, np.tril(A)) +``` + ```{note} In general, `np.linalg.solve` is more numerically stable than using `np.linalg.inv` directly. @@ -208,7 +219,7 @@ it directly. Now we can plot. -```{code-cell} python3 +```{code-cell} ipython3 plt.plot(np.arange(T)+1, y) plt.xlabel('t') plt.ylabel('y') @@ -216,7 +227,7 @@ plt.ylabel('y') plt.show() ``` -The **steady state** value $y^*$ of $y_t$ is obtained by setting $y_t = y_{t-1} = +The {ref}`*steady state*` value $y^*$ of $y_t$ is obtained by setting $y_t = y_{t-1} = y_{t-2} = y^*$ in {eq}`tswm_1`, which yields $$ @@ -226,21 +237,21 @@ $$ If we set the initial values to $y_{0} = y_{-1} = y^*$, then $y_{t}$ will be constant: -```{code-cell} python3 -y_star = 𝛼0 / (1 - 𝛼1 - 𝛼2) -y_1_steady = y_star # y_{-1} -y0_steady = y_star +```{code-cell} ipython3 +y_star = α_0 / (1 - α_1 - α_2) +y_neg1_steady = y_star # y_{-1} +y_0_steady = y_star -b_steady = np.full(T, 𝛼0) -b_steady[0] = 𝛼0 + 𝛼1 * y0_steady + 𝛼2 * y_1_steady -b_steady[1] = 𝛼0 + 𝛼2 * y0_steady +b_steady = np.full(T, α_0) +b_steady[0] = α_0 + α_1 * y_0_steady + α_2 * y_neg1_steady +b_steady[1] = α_0 + α_2 * y_0_steady ``` -```{code-cell} python3 +```{code-cell} ipython3 y_steady = A_inv @ b_steady ``` -```{code-cell} python3 +```{code-cell} ipython3 plt.plot(np.arange(T)+1, y_steady) plt.xlabel('t') plt.ylabel('y') @@ -251,7 +262,7 @@ plt.show() ## Adding a random term To generate some excitement, we'll follow in the spirit of the great economists -Eugen Slutsky and Ragnar Frisch and replace our original second-order difference +[Eugen Slutsky](https://en.wikipedia.org/wiki/Eugen_Slutsky) and [Ragnar Frisch](https://en.wikipedia.org/wiki/Ragnar_Frisch) and replace our original second-order difference equation with the following **second-order stochastic linear difference equation**: @@ -261,8 +272,8 @@ equation**: y_{t} = \alpha_{0} + \alpha_{1} y_{t-1} + \alpha_{2} y_{t-2} + u_t ``` -where $u_{t} \sim N\left(0, \sigma_{u}^{2}\right)$ and is IID, -meaning **independent** and **identically** distributed. +where $u_{t} \sim N\left(0, \sigma_{u}^{2}\right)$ and is {ref}`IID `, +meaning independent and identically distributed. We’ll stack these $T$ equations into a system cast in terms of matrix algebra. @@ -293,16 +304,13 @@ $$ (eq:eqma) Let’s try it out in Python. -```{code-cell} python3 -𝜎u = 2. -``` - -```{code-cell} python3 -u = np.random.normal(0, 𝜎u, size=T) +```{code-cell} ipython3 +σ_u = 2. +u = np.random.normal(0, σ_u, size=T) y = A_inv @ (b + u) ``` -```{code-cell} python3 +```{code-cell} ipython3 plt.plot(np.arange(T)+1, y) plt.xlabel('t') plt.ylabel('y') @@ -315,12 +323,12 @@ number of advanced countries in recent decades. We can simulate $N$ paths. -```{code-cell} python3 +```{code-cell} ipython3 N = 100 for i in range(N): col = cm.viridis(np.random.rand()) # Choose a random color from viridis - u = np.random.normal(0, 𝜎u, size=T) + u = np.random.normal(0, σ_u, size=T) y = A_inv @ (b + u) plt.plot(np.arange(T)+1, y, lw=0.5, color=col) @@ -333,12 +341,12 @@ plt.show() Also consider the case when $y_{0}$ and $y_{-1}$ are at steady state. -```{code-cell} python3 +```{code-cell} ipython3 N = 100 for i in range(N): col = cm.viridis(np.random.rand()) # Choose a random color from viridis - u = np.random.normal(0, 𝜎u, size=T) + u = np.random.normal(0, σ_u, size=T) y_steady = A_inv @ (b_steady + u) plt.plot(np.arange(T)+1, y_steady, lw=0.5, color=col) @@ -348,8 +356,6 @@ plt.ylabel('y') plt.show() ``` - - ## Computing population moments @@ -390,44 +396,48 @@ $$ Let's write a Python class that computes the mean vector $\mu_y$ and covariance matrix $\Sigma_y$. - - ```{code-cell} ipython3 class population_moments: """ - Compute population moments mu_y, Sigma_y. + Compute population moments μ_y, Σ_y. --------- Parameters: - alpha0, alpha1, alpha2, T, y_1, y0 + α_0, α_1, α_2, T, y_neg1, y_0 """ - def __init__(self, alpha0, alpha1, alpha2, T, y_1, y0, sigma_u): + def __init__(self, α_0=10.0, + α_1=1.53, + α_2=-.9, + T=80, + y_neg1=28.0, + y_0=24.0, + σ_u=1): # compute A A = np.identity(T) for i in range(T): if i-1 >= 0: - A[i, i-1] = -alpha1 + A[i, i-1] = -α_1 if i-2 >= 0: - A[i, i-2] = -alpha2 + A[i, i-2] = -α_2 # compute b - b = np.full(T, alpha0) - b[0] = alpha0 + alpha1 * y0 + alpha2 * y_1 - b[1] = alpha0 + alpha2 * y0 + b = np.full(T, α_0) + b[0] = α_0 + α_1 * y_0 + α_2 * y_neg1 + b[1] = α_0 + α_2 * y_0 # compute A inverse A_inv = np.linalg.inv(A) - self.A, self.b, self.A_inv, self.sigma_u, self.T = A, b, A_inv, sigma_u, T + self.A, self.b, self.A_inv, self.σ_u, self.T = A, b, A_inv, σ_u, T def sample_y(self, n): """ Give a sample of size n of y. """ - A_inv, sigma_u, b, T = self.A_inv, self.sigma_u, self.b, self.T - us = np.random.normal(0, sigma_u, size=[n, T]) + A_inv, σ_u, b, T = self.A_inv, self.σ_u, self.b, self.T + us = np.random.normal(0, σ_u, size=[n, T]) ys = np.vstack([A_inv @ (b + u) for u in us]) return ys @@ -436,20 +446,19 @@ class population_moments: """ Compute the population moments of y. """ - A_inv, sigma_u, b = self.A_inv, self.sigma_u, self.b + A_inv, σ_u, b = self.A_inv, self.σ_u, self.b - # compute mu_y - self.mu_y = A_inv @ b - self.Sigma_y = sigma_u**2 * (A_inv @ A_inv.T) + # compute μ_y + self.μ_y = A_inv @ b + self.Σ_y = σ_u**2 * (A_inv @ A_inv.T) + + return self.μ_y, self.Σ_y - return self.mu_y, self.Sigma_y - -my_process = population_moments( - alpha0=10.0, alpha1=1.53, alpha2=-.9, T=80, y_1=28., y0=24., sigma_u=1) +series_process = population_moments() -mu_y, Sigma_y = my_process.get_moments() -A_inv = my_process.A_inv +μ_y, Σ_y = series_process.get_moments() +A_inv = series_process.A_inv ``` It is enlightening to study the $\mu_y, \Sigma_y$'s implied by various parameter values. @@ -459,14 +468,14 @@ Among other things, we can use the class to exhibit how **statistical stationar Let's begin by generating $N$ time realizations of $y$ plotting them together with population mean $\mu_y$ . ```{code-cell} ipython3 -# plot mean +# Plot mean N = 100 for i in range(N): col = cm.viridis(np.random.rand()) # Choose a random color from viridis - ys = my_process.sample_y(N) + ys = series_process.sample_y(N) plt.plot(ys[i,:], lw=0.5, color=col) - plt.plot(mu_y, color='red') + plt.plot(μ_y, color='red') plt.xlabel('t') plt.ylabel('y') @@ -479,41 +488,49 @@ Visually, notice how the variance across realizations of $y_t$ decreases as $t$ Let's plot the population variance of $y_t$ against $t$. ```{code-cell} ipython3 -# plot variance -plt.plot(Sigma_y.diagonal()) +# Plot variance +plt.plot(Σ_y.diagonal()) plt.show() ``` -Notice how the population variance increases and asymptotes +Notice how the population variance increases and asymptotes. +++ -Let's print out the covariance matrix $\Sigma_y$ for a time series $y$ +Let's print out the covariance matrix $\Sigma_y$ for a time series $y$. ```{code-cell} ipython3 -my_process = population_moments(alpha0=0, alpha1=.8, alpha2=0, T=6, y_1=0., y0=0., sigma_u=1) - -mu_y, Sigma_y = my_process.get_moments() -print("mu_y = ",mu_y) -print("Sigma_y = ", Sigma_y) +series_process = population_moments(α_0=0, + α_1=.8, + α_2=0, + T=6, + y_neg1=0., + y_0=0., + σ_u=1) + +μ_y, Σ_y = series_process.get_moments() +print("μ_y = ", μ_y) +print("Σ_y = \n", Σ_y) ``` -Notice that the covariance between $y_t$ and $y_{t-1}$ -- the elements on the superdiagonal -- are **not** identical. +Notice that the covariance between $y_t$ and $y_{t-1}$ -- the elements on the superdiagonal -- are *not* identical. -This is is an indication that the time series represented by our $y$ vector is not **stationary**. +This is an indication that the time series represented by our $y$ vector is not **stationary**. -To make it stationary, we'd have to alter our system so that our **initial conditions** $(y_1, y_0)$ are not fixed numbers but instead a jointly normally distributed random vector with a particular mean and covariance matrix. +To make it stationary, we'd have to alter our system so that our *initial conditions* $(y_0, y_{-1})$ are not fixed numbers but instead a jointly normally distributed random vector with a particular mean and covariance matrix. -We describe how to do that in another lecture in this lecture [Linear State Space Models](https://python.quantecon.org/linear_models.html). +We describe how to do that in [Linear State Space Models](https://python.quantecon.org/linear_models.html). But just to set the stage for that analysis, let's print out the bottom right corner of $\Sigma_y$. ```{code-cell} ipython3 -mu_y, Sigma_y = my_process.get_moments() -print("bottom right corner of Sigma_y = \n", Sigma_y[72:,72:]) +series_process = population_moments() +μ_y, Σ_y = series_process.get_moments() + +print("bottom right corner of Σ_y = \n", Σ_y[72:,72:]) ``` -Please notice how the sub diagonal and super diagonal elements seem to have converged. +Please notice how the subdiagonal and superdiagonal elements seem to have converged. This is an indication that our process is asymptotically stationary. @@ -523,7 +540,6 @@ There is a lot to be learned about the process by staring at the off diagonal el +++ - ## Moving average representation Let's print out $A^{-1}$ and stare at its structure @@ -532,36 +548,19 @@ Let's print out $A^{-1}$ and stare at its structure To study the structure of $A^{-1}$, we shall print just up to $3$ decimals. -Let's begin by printing out just the upper left hand corner of $A^{-1}$ +Let's begin by printing out just the upper left hand corner of $A^{-1}$. ```{code-cell} ipython3 -with np.printoptions(precision=3, suppress=True): - print(A_inv[0:7,0:7]) +print(A_inv[0:7,0:7]) ``` - - - Evidently, $A^{-1}$ is a lower triangular matrix. - -Let's print out the lower right hand corner of $A^{-1}$ and stare at it. - -```{code-cell} ipython3 -with np.printoptions(precision=3, suppress=True): - print(A_inv[72:,72:]) -``` - - Notice how every row ends with the previous row's pre-diagonal entries. - - - - Since $A^{-1}$ is lower triangular, each row represents $ y_t$ for a particular $t$ as the sum of - a time-dependent function $A^{-1} b$ of the initial conditions incorporated in $b$, and -- a weighted sum of current and past values of the IID shocks $\{u_t\}$ +- a weighted sum of current and past values of the IID shocks $\{u_t\}$. Thus, let $\tilde{A}=A^{-1}$. @@ -576,18 +575,15 @@ This is a **moving average** representation with time-varying coefficients. Just as system {eq}`eq:eqma` constitutes a **moving average** representation for $y$, system {eq}`eq:eqar` constitutes an **autoregressive** representation for $y$. - - - ## A forward looking model -Samuelson’s model is **backwards looking** in the sense that we give it **initial conditions** and let it +Samuelson’s model is *backward looking* in the sense that we give it *initial conditions* and let it run. -Let’s now turn to model that is **forward looking**. +Let’s now turn to model that is *forward looking*. -We apply similar linear algebra machinery to study a **perfect -foresight** model widely used as a benchmark in macroeconomics and +We apply similar linear algebra machinery to study a *perfect +foresight* model widely used as a benchmark in macroeconomics and finance. As an example, we suppose that $p_t$ is the price of a stock and @@ -600,7 +596,7 @@ $$ y = A^{-1} \left(b + u\right) $$ -Our **perfect foresight** model of stock prices is +Our *perfect foresight* model of stock prices is $$ p_{t} = \sum_{j=0}^{T-t} \beta^{j} y_{t+j}, \quad \beta \in (0,1) @@ -635,34 +631,34 @@ y_{T} \end{array}\right] $$ -```{code-cell} python3 -𝛽 = .96 +```{code-cell} ipython3 +β = .96 ``` -```{code-cell} python3 +```{code-cell} ipython3 # construct B B = np.zeros((T, T)) for i in range(T): - B[i, i:] = 𝛽 ** np.arange(0, T-i) + B[i, i:] = β ** np.arange(0, T-i) ``` -```{code-cell} python3 -B +```{code-cell} ipython3 +print(B) ``` -```{code-cell} python3 -𝜎u = 0. -u = np.random.normal(0, 𝜎u, size=T) +```{code-cell} ipython3 +σ_u = 0. +u = np.random.normal(0, σ_u, size=T) y = A_inv @ (b + u) y_steady = A_inv @ (b_steady + u) ``` -```{code-cell} python3 +```{code-cell} ipython3 p = B @ y ``` -```{code-cell} python3 +```{code-cell} ipython3 plt.plot(np.arange(0, T)+1, y, label='y') plt.plot(np.arange(0, T)+1, p, label='p') plt.xlabel('t') @@ -677,7 +673,7 @@ Can you explain why the trend of the price is downward over time? Also consider the case when $y_{0}$ and $y_{-1}$ are at the steady state. -```{code-cell} python3 +```{code-cell} ipython3 p_steady = B @ y_steady plt.plot(np.arange(0, T)+1, y_steady, label='y') @@ -688,4 +684,3 @@ plt.legend() plt.show() ``` - diff --git a/lectures/troubleshooting.md b/lectures/troubleshooting.md index 7bc907add..462301d83 100644 --- a/lectures/troubleshooting.md +++ b/lectures/troubleshooting.md @@ -65,7 +65,5 @@ One way to give feedback is to raise an issue through our [issue tracker](https: Please be as specific as possible. Tell us where the problem is and as much detail about your local set up as you can provide. -Another feedback option is to use our [discourse forum](https://discourse.quantecon.org/). - Finally, you can provide direct feedback to [contact@quantecon.org](mailto:contact@quantecon.org) diff --git a/lectures/unpleasant.md b/lectures/unpleasant.md index 3e57c1bfa..0891036c0 100644 --- a/lectures/unpleasant.md +++ b/lectures/unpleasant.md @@ -11,14 +11,14 @@ kernelspec: name: python3 --- -# Unpleasant Monetarist Arithmetic +# Some Unpleasant Monetarist Arithmetic ## Overview -This lecture builds on concepts and issues introduced in our lecture on **Money Supplies and Price Levels**. +This lecture builds on concepts and issues introduced in {doc}`money_inflation`. -That lecture describes stationary equilibria that reveal a **Laffer curve** in the inflation tax rate and the associated stationary rate of return +That lecture describes stationary equilibria that reveal a [*Laffer curve*](https://en.wikipedia.org/wiki/Laffer_curve) in the inflation tax rate and the associated stationary rate of return on currency. In this lecture we study a situation in which a stationary equilibrium prevails after date $T > 0$, but not before then. @@ -34,20 +34,18 @@ The critical **money-to-bonds** ratio stabilizes only at time $T$ and afterwards And the larger is $T$, the higher is the gross-of-interest government deficit that must be financed by printing money at times $t \geq T$. -These outcomes are the essential finding of Sargent and Wallace's **unpleasant monetarist arithmetic** {cite}`sargent1981`. - -**Reader's Guide:** Please read our lecture on Money Supplies and Price levels before diving into this lecture. +These outcomes are the essential finding of Sargent and Wallace's "unpleasant monetarist arithmetic" {cite}`sargent1981`. That lecture described supplies and demands for money that appear in lecture. It also characterized the steady state equilibrium from which we work backwards in this lecture. -In addition to learning about ''unpleasant monetarist arithmetic", in this lecture we'll learn how to implement a **fixed point** algorithm for computing an initial price level. +In addition to learning about "unpleasant monetarist arithmetic", in this lecture we'll learn how to implement a [*fixed point*](https://en.wikipedia.org/wiki/Fixed_point_(mathematics)) algorithm for computing an initial price level. ## Setup -Let's start with quick reminders of the model's components set out in our lecture on **Money Supplies and Price Levels**. +Let's start with quick reminders of the model's components set out in {doc}`money_inflation`. Please consult that lecture for more details and Python code that we'll also use in this lecture. @@ -75,9 +73,11 @@ $$ b_t = \gamma_1 - \gamma_2 R_t^{-1} . $$ (eq:up_bdemand) +where $\gamma_1 > \gamma_2 > 0$. + ## Monetary-Fiscal Policy -To the basic model of our lecture on **Money Supplies and Price Levels**, we add inflation-indexed one-period government bonds as an additional way for the government to finance government expenditures. +To the basic model of {doc}`money_inflation`, we add inflation-indexed one-period government bonds as an additional way for the government to finance government expenditures. Let $\widetilde R > 1$ be a time-invariant gross real rate of return on government one-period inflation-indexed bonds. @@ -91,13 +91,13 @@ $$ Just before the beginning of time $0$, the public owns $\check m_0$ units of currency (measured in dollars) and $\widetilde R \check B_{-1}$ units of one-period indexed bonds (measured in time $0$ goods); these two quantities are initial conditions set outside the model. -Notice that $\check m_0$ is a **nominal** quantity, being measured in dollar, while -$\widetilde R \check B_{-1}$ is a **real** quantity, being measured in time $0$ goods. +Notice that $\check m_0$ is a *nominal* quantity, being measured in dollars, while +$\widetilde R \check B_{-1}$ is a *real* quantity, being measured in time $0$ goods. ### Open market operations -At time $0$, government can rearrange its portolio of debts with subject to the following constraint (on open-market operations): +At time $0$, government can rearrange its portfolio of debts subject to the following constraint (on open-market operations): $$ \widetilde R B_{-1} + \frac{m_0}{p_0} = \widetilde R \check B_{-1} + \frac{\check m_0}{p_0} @@ -109,14 +109,14 @@ $$ B_{-1} - \check B_{-1} = \frac{1}{p_0 \widetilde R} \left( \check m_0 - m_0 \right) $$ (eq:openmarketconstraint) -This equation says that the government (e.g., the central bank) can **decrease** $m_0$ relative to -$\check m_0$ by **increasing** $B_{-1}$ relative to $\check B_{-1}$. +This equation says that the government (e.g., the central bank) can *decrease* $m_0$ relative to +$\check m_0$ by *increasing* $B_{-1}$ relative to $\check B_{-1}$. -This is a version of a standard constraint on a central bank's **open market operations** in which it expands the stock of money by buying government bonds from the public. +This is a version of a standard constraint on a central bank's [**open market operations**](https://www.federalreserve.gov/monetarypolicy/openmarket.htm) in which it expands the stock of money by buying government bonds from the public. ## An open market operation at $t=0$ -Following Sargent and Wallace (1981), we analyze consequences of a central bank policy that +Following Sargent and Wallace {cite}`sargent1981`, we analyze consequences of a central bank policy that uses an open market operation to lower the price level in the face of a persistent fiscal deficit that takes the form of a positive $g$. @@ -152,7 +152,7 @@ running monetary and fiscal policies. Here, by **fiscal policy** we mean the collection of actions that determine a sequence of net-of-interest government deficits $\{g_t\}_{t=0}^\infty$ that must be financed by issuing to the public either money or interest bearing bonds. -By **monetary policy** or **debt-management polcy**, we mean the collection of actions that determine how the government divides its portolio of debts to the public between interest-bearing parts (government bonds) and non-interest-bearing parts (money). +By **monetary policy** or **debt-management policy**, we mean the collection of actions that determine how the government divides its portfolio of debts to the public between interest-bearing parts (government bonds) and non-interest-bearing parts (money). By an **open market operation**, we mean a government monetary policy action in which the government (or its delegate, say, a central bank) either buys government bonds from the public for newly issued money, or sells bonds to the public and withdraws the money it receives from public circulation. @@ -160,7 +160,7 @@ By an **open market operation**, we mean a government monetary policy action in ## Algorithm (basic idea) -We work backwards from $t=T$ and first compute $p_T, R_u$ associated with the low-inflation, low-inflation-tax-rate stationary equilibrium of our lecture on the dynamic Laffer curve for the inflation tax. +We work backwards from $t=T$ and first compute $p_T, R_u$ associated with the low-inflation, low-inflation-tax-rate stationary equilibrium in {doc}`money_inflation_nonlinear`. To start our description of our algorithm, it is useful to recall that a stationary rate of return on currency $\bar R$ solves the quadratic equation @@ -171,7 +171,7 @@ $$ (eq:up_steadyquadratic) Quadratic equation {eq}`eq:up_steadyquadratic` has two roots, $R_l < R_u < 1$. -For reasons described at the end of **this lecture**, we select the larger root $R_u$. +For reasons described at the end of {doc}`money_inflation`, we select the larger root $R_u$. Next, we compute @@ -211,7 +211,7 @@ We want to compute $$ \begin{aligned} -p_0 & = \gamma_1^{-1} \left[ \sum_{j=0}^\infty \lambda^j m_{1+j} \right] \cr +p_0 & = \gamma_1^{-1} \left[ \sum_{j=0}^\infty \lambda^j m_{j} \right] \cr & = \gamma_1^{-1} \left[ \sum_{j=0}^{T-1} \lambda^j m_{0} + \sum_{j=T}^\infty \lambda^j m_{1+j} \right] \end{aligned} $$ @@ -240,21 +240,24 @@ $$ p_T = \frac{m_0}{\gamma_1 - \overline g - \gamma_2 R_u^{-1}} = \gamma_1^{-1} m_0 \left\{\frac{1}{R_u-\lambda} \right\} $$ (eq:pTformula) -**Remark:** +```{prf:remark} +:label: equivalence We can verify the equivalence of the two formulas on the right sides of {eq}`eq:pTformula` by recalling that $R_u$ is a root of the quadratic equation {eq}`eq:up_steadyquadratic` that determines steady state rates of return on currency. +``` ## Algorithm (pseudo code) Now let's describe a computational algorithm in more detail in the form of a description -that constitutes ''pseudo code'' because it approaches a set of instructions we could provide to a +that constitutes pseudo code because it approaches a set of instructions we could provide to a Python coder. To compute an equilibrium, we deploy the following algorithm. -Given **parameters** include $g, \check m_0, \check B_{-1}, \widetilde R >1, T $ +```{prf:algorithm} +Given *parameters* include $g, \check m_0, \check B_{-1}, \widetilde R >1, T $. -We define a mapping from $p_0$ to $p_0$ as follows. +We define a mapping from $p_0$ to $\widehat p_0$ as follows. * Set $m_0$ and then compute $B_{-1}$ to satisfy the constraint on time $0$ **open market operations** @@ -278,8 +281,7 @@ $$ * Compute $R_u, p_T$ from formulas {eq}`eq:up_steadyquadratic` and {eq}`eq:LafferTstationary` above -* Compute a new estimate of $p_0$, call it $\widehat p_0$, from equation {eq}`eq:allts` above - +* Compute a new estimate of $p_0$, call it $\widehat p_0$, from equation {eq}`eq:allts` above * Note that the preceding steps define a mapping @@ -296,12 +298,12 @@ p_{0,j+1} = (1-\theta) {\mathcal S}(p_{0,j}) + \theta p_{0,j}, $$ where $\theta \in [0,1)$ is a relaxation parameter. - +``` ## Example Calculations We'll set parameters of the model so that the steady state after time $T$ is initially the same -as in our lecture on "Money and Inflation". +as in {doc}`money_inflation_nonlinear` In particular, we set $\gamma_1=100, \gamma_2 =50, g=3.0$. We set $m_0 = 100$ in that lecture, but now the counterpart will be $M_T$, which is endogenous. @@ -314,9 +316,9 @@ These parameter settings mean that just before time $0$, the "central bank" sell That leaves the public with less currency but more government interest-bearing bonds. -Since the public has less currency (it's supply has diminished) it is plausible to anticipate that the price level at time $0$ will be driven downward. +Since the public has less currency (its supply has diminished) it is plausible to anticipate that the price level at time $0$ will be driven downward. -But that is not the end of the story, because this ''open market operation'' at time $0$ has consequences for future settings of $m_{t+1}$ and the gross-of-interest government deficit $\bar g_t$. +But that is not the end of the story, because this **open market operation** at time $0$ has consequences for future settings of $m_{t+1}$ and the gross-of-interest government deficit $\bar g_t$. Let's start with some imports: @@ -327,7 +329,7 @@ import matplotlib.pyplot as plt from collections import namedtuple ``` -Now let's dive in and implement our ''pseudo code'' in Python. +Now let's dive in and implement our pseudo code in Python. ```{code-cell} ipython3 # Create a namedtuple that contains parameters @@ -393,14 +395,15 @@ def compute_fixed_point(m0, p0_guess, model, θ=0.5, tol=1e-6): return p0 ``` + Let's look at how price level $p_0$ in the stationary $R_u$ equilibrium depends on the initial money supply $m_0$. Notice that the slope of $p_0$ as a function of $m_0$ is constant. -This outcome indicates that our model verifies a ''quantity theory of money'' outcome, +This outcome indicates that our model verifies a quantity theory of money outcome, something that Sargent and Wallace {cite}`sargent1981` purposefully built into their model to justify -the adjective **monetarist** in their title. +the adjective *monetarist* in their title. ```{code-cell} ipython3 @@ -416,7 +419,7 @@ plt.xlabel('$m_0$') plt.show() ``` -Now let's write and implement code that let's us experiment with the time $0$ open market operation described earlier. +Now let's write and implement code that lets us experiment with the time $0$ open market operation described earlier. ```{code-cell} ipython3 def simulate(m0, model, length=15, p0_guess=1): @@ -469,25 +472,16 @@ def simulate(m0, model, length=15, p0_guess=1): def plot_path(m0_arr, model, length=15): fig, axs = plt.subplots(2, 2, figsize=(8, 5)) - + titles = ['$p_t$', '$m_t$', '$b_t$', '$R_t$'] + for m0 in m0_arr: - paths = simulate(m0, msm, length=length) - - axs[0, 0].plot(paths[0]) - axs[0, 0].set_title('$p_t$') - - axs[0, 1].plot(paths[1]) - axs[0, 1].set_title('$m_t$') - - axs[1, 0].plot(paths[2]) - axs[1, 0].set_title('$b_t$') - - axs[1, 1].plot(paths[3]) - axs[1, 1].set_title('$R_t$') - - axs[0, 1].hlines(model.m0_check, 0, length, - color='r', linestyle='--') - axs[0, 1].text(length*0.8, model.m0_check*0.9, '$\check{m}_0$') + paths = simulate(m0, model, length=length) + for i, ax in enumerate(axs.flat): + ax.plot(paths[i]) + ax.set_title(titles[i]) + + axs[0, 1].hlines(model.m0_check, 0, length, color='r', linestyle='--') + axs[0, 1].text(length * 0.8, model.m0_check * 0.9, r'$\check{m}_0$') plt.show() ``` @@ -501,11 +495,12 @@ mystnb: plot_path([80, 100], msm) ``` -Figure {numref}`fig:unpl1` summarizes outcomes of two experiments that convey messages of -Sargent and Wallace's **unpleasant monetarist arithmetic** {cite}`sargent1981`. +{numref}`fig:unpl1` summarizes outcomes of two experiments that convey messages of Sargent and Wallace {cite}`sargent1981`. * An open market operation that reduces the supply of money at time $t=0$ reduces the price level at time $t=0$ * The lower is the post-open-market-operation money supply at time $0$, lower is the price level at time $0$. -* An open market operation that reduces the post-open-market-operation money supply at time $0$ also **lowers** the rate of return on money $R_u$ at times $t \geq T$ because it brings a higher gross-of-interest government deficit that must be financed by printing money (i.e., levying an inflation tax) at time $t \geq T$. +* An open market operation that reduces the post open market operation money supply at time $0$ also *lowers* the rate of return on money $R_u$ at times $t \geq T$ because it brings a higher gross of interest government deficit that must be financed by printing money (i.e., levying an inflation tax) at time $t \geq T$. + +* $R$ is important in the context of maintaining monetary stability and addressing the consequences of increased inflation due to government deficits. Thus, a larger $R$ might be chosen to mitigate the negative impacts on the real rate of return caused by inflation. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy