From 71a959708dcde53560a0f9750d7b1a2d77057db2 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Wed, 3 Jul 2024 10:41:10 -0500 Subject: [PATCH] feat: romer model --- aggieland.txt | 1 + compile_flags.txt | 1 + filename.txt | 5 + map.cc | 10 + posts/economics/models-of-production.html | 254 ++++++++++++++++++++- scripts/posts/models-of-production.js | 255 ++++++++++++++++++++-- styles/graph.css | 20 ++ 7 files changed, 515 insertions(+), 31 deletions(-) create mode 100644 aggieland.txt create mode 100644 compile_flags.txt create mode 100644 filename.txt create mode 100644 map.cc diff --git a/aggieland.txt b/aggieland.txt new file mode 100644 index 0000000..0611e34 --- /dev/null +++ b/aggieland.txt @@ -0,0 +1 @@ +the 12th man diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 0000000..e23b2ae --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1 @@ +-std=c++20 diff --git a/filename.txt b/filename.txt new file mode 100644 index 0000000..1475978 --- /dev/null +++ b/filename.txt @@ -0,0 +1,5 @@ +This is an example text file. +This file contains several words, some of which are repeated. +For example, the word "this" appears multiple times in this file. +We can use a shell command to find the most frequent words. +Let's see how many times each word appears in this example text file. diff --git a/map.cc b/map.cc new file mode 100644 index 0000000..06da4f2 --- /dev/null +++ b/map.cc @@ -0,0 +1,10 @@ +#include +#include + +int main() { + std::ifstream ifs{"aggieland.txt"}; + std::string read1; + int read2; + ifs >> read1 >> read2; + std::cout << read1 << read2; +} diff --git a/posts/economics/models-of-production.html b/posts/economics/models-of-production.html index 3bbc1ea..aaecbfb 100644 --- a/posts/economics/models-of-production.html +++ b/posts/economics/models-of-production.html @@ -147,7 +147,7 @@ type="range" id="sliderD" min="0.01" - max="1" + max="0.99" step="0.01" value="0.50" /> @@ -165,7 +165,7 @@ type="range" id="sliderS" min="0.01" - max="1" + max="0.99" step="0.01" value="0.50" /> @@ -179,7 +179,7 @@ type="range" id="sliderAlpha" min="0.01" - max="1" + max="0.99" step="0.01" value="0.33" /> @@ -213,8 +213,6 @@

analysis

-
-

Using both mathematical intuition and manipulating the visualization above, we find that: @@ -262,10 +260,250 @@ alter the most important predictor of output, TFP.

-

romer

- - + + +

romer

+

introduction

+
+

How, then, can we address these shortcomings?

+

+ The Romer Model provides an answer by both modeling ideas \(A_t\) + (analagous to TFP in the Solow model) endogenously and utilizing + them to provide a justification for sustained long-run growth. +

+

The Model divides the world into two parts:

+
    +
  • + Objects: finite resources, like capital and labor in the + Solow Model +
  • +
  • + Ideas: infinite, + non-rivalrous + items leveraged in production (note that ideas may be + excludable, though) +
  • +
+

+ The Romer Models' production function can be modelled as: + \[Y_t=F(A_t,L_{yt})=A_tL_{yt}\] With: +

+
    +
  • \(A_t\): the amount of ideas \(A\) in period \(t\)
  • +
  • + \(L_{yt}\): the population working on production-facing + (output-driving) tasks +
  • +
+

+ Assuming \(L_t=\bar{L}\) people work in the economy, a proportion + \(\bar{l}\) of the population focuses on making ideas: + \(L_{at}=\bar{l}\bar{L}\rightarrow L_{yt}=(1-\bar{l})\bar{L}\). +

+ +

+ Further, this economy garners ideas with time at rate + \(\bar{z}\): the "speed of ideas". Now, we can + describe the quantity of ideas tomorrow as function of those of + today: the Law of Ideal Motion (I made that up). + \[A_{t+1}=A_t+\bar{z}A_tL_{at}\leftrightarrow\Delta + A_{t+1}=\bar{z}A_tL_{at}\] +

+

+ Analagously to capital in the solow model, ideas begin in the + economy with some \(\bar{A}_0\gt0\) and grow at an + exponential rate. At its core, this is because ideas are + non-rivalrous; more ideas bring about more ideas. +

+

Finally, we have a model:

+
+
+
    +
  1. \(Y_t=A_tL_{yt}\)
  2. +
  3. \(\Delta A_{t+1} = \bar{z}A_tL_{at}\)
  4. +
+
+
+
    +
  1. \(L_{yt}+L_{at}=\bar{L}\)
  2. +
  3. \(L_{at}=\bar{l}\bar{L}\)
  4. +
+
+
+

+ A visualization of the Romer Model shows that the economy grows + exponentially—production knows no bounds (ceteris parbibus, of course). A graph of \(log_{10}(Y_t)\) can be seen below: +

+
+
+
+
+
+
    +
  • +
    + + 0.50 + +
    +
  • +
  • +
    + + 505 + +
    +
  • +
+
+
+
    +
  • +
    + + 0.50 + +
    +
  • +
  • +
    + + 5000 + +
    +
  • +
+
+
+

+ Playing with the sliders, this graph may seem underwhelming in + comparison to the Solow Model. However, on a logarithmic scale, + small changes in the parameters lead to massive changes in the + growth rate of ideas and economices: +

+
+ + + + + + + + +
+
+
+

solving the model

+
+

+ To find the output in terms of exogenous parameters, first note + that \[L_t=\bar{L}\rightarrow L_{yt}=(1-\bar{l})\bar{L}\] +

+

+ Now, all that remains is to find ideas \(A_t\). It is assumed that + ideas grow at some rate \(g_A\): \[A_t=A_0(1+g_A)^t\] +

+

+ Using the growth rate formula, we find: \[g_A=\frac{\Delta + A_{t+1}-A_t}{A_t}=\frac{A_t+\bar{z}A_tL_{at}-A_t}{A_t}=\bar{z}L_{at}=\bar{z}\bar{l}\bar{L}\] +

+

+ Thus, ideas \(A_t=A_0(1+\bar{z}\bar{l}\bar{L})^t\). Finally, + output can be solved the production function: \[Y_t=A_t + L_{yt}=A_0(1+\bar{z}\bar{l}\bar{L})(1-\bar{l})\bar{L}\] +

+ + + + +
+

analysis

+
+

+ We see the Romer model exhibits long-run growth because ideas have + non-diminishing returns due to their nonrival nature. In this + model, capital and income eventually slow but ideas continue to + yield increasing, unrestricted returns. +

+

+ Further, all economy continually and perpetually grow along a + "Balanced Growth Path" as previously defined by \(Y_t\) as a + function of the endogenous variables. This directly contrasts the + Solow model, in which an economy converges to a steady-state with + transition dynamics. +

+

+ Changes in the growth rate of ideas, then, alter the growth rate + of output itself—in this case, parameters \(\bar{l}, + \bar{z}\), and \(\bar{L}\). This is best exemplified by comparing + the growth rate before and and after a parameter changes. In the + below example, a larger \(\bar{l}\) initially drops output due to + less workers being allocated to production. Soon after, though, + output recovers along a "higher" Balanced Growth Path. +

+
+
+
+
+
+
    +
  • +
    + + 0.50 + +
    +
  • +
+
+
+

romer-solow

diff --git a/scripts/posts/models-of-production.js b/scripts/posts/models-of-production.js index 72df53f..5d8503d 100644 --- a/scripts/posts/models-of-production.js +++ b/scripts/posts/models-of-production.js @@ -11,10 +11,10 @@ function drawSolowGraph() { }; }); - const A = document.getElementById("outputA").textContent, - D = document.getElementById("outputD").textContent, - S = document.getElementById("outputS").textContent, - alpha = document.getElementById("outputAlpha").textContent; + const A = parseFloat(document.getElementById("outputA").textContent), + D = parseFloat(document.getElementById("outputD").textContent), + S = parseFloat(document.getElementById("outputS").textContent), + alpha = parseFloat(document.getElementById("outputAlpha").textContent); const solowOutput = (K) => A * Math.pow(K, alpha) * Math.pow(L, 1 - alpha); const solowDepreciation = (K) => D * K; const solowInvestment = (Y) => S * Y; @@ -34,12 +34,10 @@ function drawSolowGraph() { .attr("transform", `translate(${margin.left}, ${margin.top})`); const x = d3.scaleLinear().domain([0, K_MAX]).range([0, width]); - const xAxis = svg + svg .append("g") .attr("transform", `translate(0, ${height})`) - .call(d3.axisBottom(x)); - - xAxis + .call(d3.axisBottom(x)) .append("text") .attr("fill", "#000") .attr("x", width + 10) @@ -50,9 +48,9 @@ function drawSolowGraph() { const Y_MAX = solowOutput(K_MAX) + K_MAX / 10; const y = d3.scaleLinear().domain([0, Y_MAX]).range([height, 0]); - const yAxis = svg.append("g").call(d3.axisLeft(y)); - - yAxis + svg + .append("g") + .call(d3.axisLeft(y)) .append("text") .attr("fill", "#000") .attr("x", 0) @@ -87,9 +85,7 @@ function drawSolowGraph() { .append("xhtml:body") .style("font-size", "0.75em") .html(`
`); - katex.render("Y", document.querySelector(".solow-visualization-y"), { - throwOnError: false, - }); + katex.render("Y", document.querySelector(".solow-visualization-y")); const depreciationData = Array.from({ length: K_MAX }, (_, k) => ({ K: k, @@ -118,9 +114,7 @@ function drawSolowGraph() { .append("xhtml:body") .style("font-size", "0.75em") .html(`
`); - katex.render("\\bar{d}K", document.querySelector(".solow-visualization-d"), { - throwOnError: false, - }); + katex.render("\\bar{d}K", document.querySelector(".solow-visualization-d")); const investmentData = outputData.map((d) => ({ K: d.K, @@ -149,9 +143,7 @@ function drawSolowGraph() { .append("xhtml:body") .style("font-size", "0.75em") .html(`
`); - katex.render("I", document.querySelector(".solow-visualization-i"), { - throwOnError: false, - }); + katex.render("I", document.querySelector(".solow-visualization-i")); const k_star = L * Math.pow((S * A) / D, 1 / (1 - alpha)); svg @@ -177,13 +169,230 @@ function drawSolowGraph() { katex.render( `(K^*,Y^*)=(${k_star.toFixed(0)},${y_star.toFixed(0)})`, document.querySelector(".solow-visualization-eq"), - { - throwOnError: false, - }, ); } +const formatNumber = (num) => { + return `~${num.toExponential(0)}`; +}; + +const normalFont = `style="font-weight: normal"`; + +const updateRomerTable = (romerData) => { + const tableHeader = document.getElementById("romer-table-header"); + const rowA_t = document.getElementById("row-A_t"); + const rowY_t = document.getElementById("row-Y_t"); + + tableHeader.innerHTML = `
`; + katex.render(`t`, document.querySelector(".romer-table-time")); + rowA_t.innerHTML = ``; + rowY_t.innerHTML = ``; + katex.render("A_t", document.querySelector(".romer-table-at")); + katex.render("Y_t", document.querySelector(".romer-table-yt")); + + romerData.forEach((d) => { + if (d.year % 20 === 0 || d.year === 1) { + tableHeader.innerHTML += `${d.year}`; + rowA_t.innerHTML += `${formatNumber(d.A)}`; + rowY_t.innerHTML += `${formatNumber(d.Y)}`; + } + }); +}; + +function drawRomerGraph() { + const T_MAX = 100; + margin = { top: 20, right: 100, bottom: 20, left: 50 }; + + ["Z", "L", "l", "A0"].forEach((param) => { + const slider = document.getElementById(`slider${param}`); + slider.oninput = function () { + slider.previousElementSibling.innerText = this.value; + drawRomerGraph(); + }; + }); + + const z = parseFloat(document.getElementById("outputZ").textContent), + L = parseFloat(document.getElementById("outputL").textContent), + l = parseFloat(document.getElementById("outputl").textContent), + A0 = parseFloat(document.getElementById("outputA0").textContent); + + const container = document.getElementById("romer-visualization"); + const width = container.clientWidth - margin.left - margin.right; + const height = container.clientHeight - margin.top - margin.bottom; + + container.innerHTML = ""; + + const svg = d3 + .select("#romer-visualization") + .append("svg") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform", `translate(${margin.left}, ${margin.top})`); + + let A = A0; + const romerData = []; + + for (let t = 1; t <= T_MAX; ++t) { + const A_t = A * (1 + z * l * L); + const Y_t = A_t * (1 - l) * L; + romerData.push({ year: t, A: A_t, Y: Math.log10(Y_t) }); + A = A_t; + } + + const x = d3.scaleLinear().domain([1, T_MAX]).range([0, width]); + svg + .append("g") + .attr("transform", `translate(0, ${height})`) + .call(d3.axisBottom(x)) + .append("text") + .attr("fill", "#000") + .attr("x", width + 10) + .attr("y", -10) + .style("text-anchor", "end") + .style("font-size", "1.5em") + .text("t"); + + const y = d3 + .scaleLinear() + .domain([0, romerData[romerData.length - 1].Y]) + .range([height, 0]); + svg + .append("g") + .call(d3.axisLeft(y).ticks(10, d3.format(".1s"))) + .append("text") + .attr("fill", "#000") + .attr("x", 0) + .attr("y", -10) + .style("text-anchor", "start") + .style("font-size", "1.5em") + .text("log(Y)"); + + svg + .append("path") + .datum(romerData) + .attr("fill", "none") + .attr("stroke", getTopicColor(urlToTopic())) + .attr("stroke-width", 2) + .attr( + "d", + d3 + .line() + .x((d) => x(d.year)) + .y((d) => y(d.Y)), + ); + + svg + .append("foreignObject") + .attr("width", "4em") + .attr("height", "2em") + .attr("x", x(T_MAX)) + .attr("y", y(romerData[T_MAX - 1].Y)) + .append("xhtml:body") + .style("font-size", "0.75em") + .html(`
`); + katex.render("log_{10}Y", document.querySelector(".romer-visualization-y")); + + updateRomerTable(romerData); +} + +function drawRomerlGraph() { + const T_MAX = 100, + z = 0.01, + L = 50, + A0 = 50; + margin = { top: 20, right: 100, bottom: 20, left: 50 }; + + const slider = document.getElementById(`sliderlChange`); + slider.oninput = function () { + slider.previousElementSibling.innerText = this.value; + drawRomerlGraph(); + }; + + const l = parseFloat(document.getElementById("outputlChange").textContent); + + const container = document.getElementById("romer-lchange-visualization"); + const width = container.clientWidth - margin.left - margin.right; + const height = container.clientHeight - margin.top - margin.bottom; + + container.innerHTML = ""; + + const svg = d3 + .select("#romer-lchange-visualization") + .append("svg") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform", `translate(${margin.left}, ${margin.top})`); + + let A = A0, + l_ = 0.1; + const romerData = []; + + for (let t = 1; t <= Math.floor(T_MAX / 2) - 1; ++t) { + const A_t = A * (1 + z * l_ * L); + const Y_t = A_t * (1 - l_) * L; + romerData.push({ year: t, A: A_t, Y: Math.log10(Y_t) }); + A = A_t; + } + + for (let t = Math.floor(T_MAX / 2); t <= T_MAX; ++t) { + const A_t = A * (1 + z * l * L); + const Y_t = A_t * (1 - l) * L; + romerData.push({ year: t, A: A_t, Y: Math.log10(Y_t) }); + A = A_t; + } + + const x = d3.scaleLinear().domain([1, T_MAX]).range([0, width]); + svg + .append("g") + .attr("transform", `translate(0, ${height})`) + .call(d3.axisBottom(x)) + .append("text") + .attr("fill", "#000") + .attr("x", width + 10) + .attr("y", -10) + .style("text-anchor", "end") + .style("font-size", "1.5em") + .text("t"); + + const y = d3 + .scaleLinear() + .domain([0, romerData[romerData.length - 1].Y]) + .range([height, 0]); + svg + .append("g") + .call(d3.axisLeft(y).ticks(10, d3.format(".1s"))) + .append("text") + .attr("fill", "#000") + .attr("x", 0) + .attr("y", -10) + .style("text-anchor", "start") + .style("font-size", "1.5em") + .text("log(Y)"); + + svg + .append("path") + .datum(romerData) + .attr("fill", "none") + .attr("stroke", getTopicColor(urlToTopic())) + .attr("stroke-width", 2) + .attr( + "d", + d3 + .line() + .x((d) => x(d.year)) + .y((d) => y(d.Y)), + ); +} + document.addEventListener("DOMContentLoaded", function () { drawSolowGraph(); window.onresize = drawSolowGraph; + + drawRomerGraph(); + window.onresize = drawRomerGraph; + + drawRomerlGraph(); + window.onresize = drawRomerlGraph; }); diff --git a/styles/graph.css b/styles/graph.css index 03da3a6..9b775a6 100644 --- a/styles/graph.css +++ b/styles/graph.css @@ -68,3 +68,23 @@ ul { list-style: none; margin: 0; } + +.romer-table-container { + display: flex; + justify-content: center; + margin: 20px 0; +} +#romer-table { + text-align: center; + margin-top: 20px; + margin: 0; + font-size: 0.8em; + border-collapse: collapse; +} + +#romer-table th, +#romer-table td { + border: 1px solid black; + text-align: center; + padding: 5px; +}