From d7678599f09d2e70697a909f07c24c91f08529d9 Mon Sep 17 00:00:00 2001 From: John Stachurski Date: Sun, 18 Feb 2024 15:26:14 +1100 Subject: [PATCH 01/10] Adding to supply and demand lecture --- lectures/intro_supply_demand.md | 306 ++++++++++++++++++++++++++++++-- 1 file changed, 295 insertions(+), 11 deletions(-) diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index 0f1c8b9a..f92c8bb3 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.11.5 + jupytext_version: 1.15.2 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -20,26 +20,37 @@ the main topics of elementary microeconomics. Throughout the lecture, we focus on models with one good and one price. - In a {doc}`subsequent lecture ` we will investigate settings with many goods. +### Why does this model matter? + +In the 15th, 16th, 17th and 18th centuries, mercantilist ideas held sway among most rulers of European countries. + +Exports were regarded as good because they brought in bullion (gold flowed into the country). + +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. + +There are many different expressions of this idea in economics. + +This lecture dicusses one of the simplest: how free adjustment of prices can maximize a measure of social welfare in the market for a single good. + + +### Topics and infrastructure + Key infrastructure concepts that we'll encounter in this lecture are * inverse demand curves * inverse supply curves * consumer surplus * producer surplus +* integration * social welfare as the sum of consumer and producer surpluses -* relationship between equilibrium quantity and social welfare optimum - -Throughout the lectures, we'll assume that inverse demand and supply curves are **affine** functions of quantity. - -("Affine" means "linear plus a constant" and [here](https://math.stackexchange.com/questions/275310/what-is-the-difference-between-linear-and-affine-function) is a nice discussion about it.) +* the relationship between equilibrium quantity and social welfare optimum -We'll also assume affine inverse supply and demand functions when we study models with multiple consumption goods in our {doc}`subsequent lecture `. -We do this in order to simplify the exposition and enable us to use just a few tools from linear algebra, namely, matrix multiplication and matrix inversion. In our exposition we will use the following imports. @@ -48,8 +59,283 @@ import numpy as np import matplotlib.pyplot as plt ``` +## Consumer Surplus + +Before we look at the model of supply and demand, it will be helpful to have some background on (a) consumer and producer surpluses and (b) integration. + +(If you are comfortable with both topics you can jump to the next section.) + +### A discrete example + +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. + +Suppose that the willingness to pay amount for each of the 10 consumers is as follows: + +| consumer | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | +|----------------|----|----|----|----|----|----|----|----|----|-----| +| 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$. + +(If $p=w_i$ the consumer is indifferent between buying and not buying; we arbitrarily assume that they buy.) + +The **consumer surplus** of the $i$-th consumer is $\max\{w_i - p, 0\}$ + +* if $w_i \geq p$, then the consumer buys and gets surplus $w_i - p$ +* if $w_i < p$, then the consumer does not buy and gets surplus $0$ + +For example, if the price is $p=40$, then consumer 1 gets surplus $98-40=58$. + +The bar graph below shows the surplus of each consumer when $p=25$. + +The total height of each bar $i$ is willingness to pay by consumer $i$. + +The orange portion of some of the bars shows consumer surplus. + + +```{code-cell} ipython3 +fig, ax = plt.subplots() +consumers = range(1, 11) # consumers 1,..., 10 +# willingness to pay for each consumer +wtp = (98, 72, 41, 38, 29, 21, 17, 12, 11, 10) +price = 25 +ax.bar(consumers, wtp, label="consumer surplus", color="darkorange", alpha=0.8) +ax.plot((0, 12), (price, price), lw=2, label="price $p$") +ax.bar(consumers, [min(w, price) for w in wtp], color="black", alpha=0.6) +ax.set_xlim(0, 12) +ax.set_xticks(consumers) +ax.set_ylabel("willingness to pay, price") +ax.set_xlabel("consumer, quantity") +ax.legend() +plt.show() +``` + +The total consumer surplus in this market is + +$$ + \sum_{i=1}^{10} \max\{w_i - p, 0\} + = \sum_{w_i \geq p} (w_i - p) +$$ + +Since consumer surplus $\max\{w_i-p,0\}$ of consumer $i$ is a measure of her gains from trade (i.e., extent to which the good is valued over and above the amount the consumer had to pay), it is reasonable to consider total consumer surplus as a measurement of consumer welfare. + +Later we will pursue this idea further, considering how different prices lead to different welfare outcomes for consumers and producers. + +### A comment on quantity. + +Notice that in the figure, the horizontal axis is labeled "consumer, quantity". + +We have added "quantity" here because we can read the number of units sold from this axis, assuming for now that there are sellers who are willing to sell as many units as the consumers demand, given the current market price $p$. + +In this example, consumers 1 to 5 buy, and the quantity sold is 5. + +Below we drop the assumption that sellers will provide any amount at a given price and study how this changes outcomes. + ++++ + +### A continuous approximation + +It is often convenient to assume that there is a "very large number" of consumers, so that willingness to pay becomes a continuous curve. + +As before, the vertical axis measures willingness to pay, while the horizontal axis measures quantity. + +This kind of curve is called an **inverse demand curve** + +An example is provided below, showing both an inverse demand curve and a set price. + +The inverse demand curve is given by + +$$ p = 100 e^{-q} $$ + +```{code-cell} ipython3 +def inverse_demand(q): + return 100 * np.exp(- q) + +q_min, q_max = 0, 5 +q_grid = np.linspace(q_min, q_max, 1000) + +fig, ax = plt.subplots() +ax.plot((q_min, q_max), (price, price), lw=2, label="price") +ax.plot(q_grid, inverse_demand(q_grid), + color="k", label="inverse demand curve") +ax.set_ylabel("willingness to pay, price") +ax.set_xlabel("quantity") +ax.set_xlim(q_min, q_max) +ax.set_ylim(0, 110) +ax.legend() +plt.show() +``` + +Reasoning by analogy with the discrete case, the area under the demand curve and above the price is called the **consumer surplus**, and is a measure of total gains from trade on the part of consumers. + +The consumer surplus is shaded in the figure below. + +```{code-cell} ipython3 +# solve for the value of q where demand meets price +q_star = np.log(100) - np.log(price) + +fig, ax = plt.subplots() +ax.plot((q_min, q_max), (price, price), lw=2, label="price") +ax.plot(q_grid, inverse_demand(q_grid), + color="k", label="inverse demand curve") +small_grid = np.linspace(0, q_star, 500) +ax.fill_between(small_grid, np.full(len(small_grid), price), + inverse_demand(small_grid), color="darkorange", + alpha=0.6, label="consumer surplus") +ax.vlines(q_star, 0, price, ls="--") +ax.set_ylabel("willingness to pay, price") +ax.set_xlabel("quantity") +ax.set_xlim(q_min, q_max) +ax.set_ylim(0, 110) +ax.text(q_star, -10, "$q^*$") +ax.legend() +plt.show() +``` + +The value $q^*$ is where the inverse demand curve meets price. + ++++ + +## Producer surplus + +Having dicussed demand, let's now switch over to the supply side of the market. + +### The discrete case + +The figure below shows the price at which a collection of producers, also numbered 1 to 10, are willing to sell one unit of the good in question + +```{code-cell} ipython3 +fig, ax = plt.subplots() +producers = range(1, 11) # producers 1,..., 10 +# willingness to sell for each producer +wts = (5, 8, 17, 22, 35, 39, 46, 57, 88, 91) +price = 25 +ax.bar(producers, wts, label="willingness to sell", color="blue", alpha=0.8) +ax.set_xlim(0, 12) +ax.set_xticks(producers) +ax.set_ylabel("willingness to sell") +ax.set_xlabel("producer") +ax.legend() +plt.show() +``` + +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\}$. + +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 + +$$ + \sum_{i=1}^{10} \max\{p - v_i, 0\} + = \sum_{p \geq v_i} (p - v_i) +$$ + ++++ + +As for the consumer case, it can be helpful for analysis if we approximate producer willingness to sell into a continuous curve. + +This curve is called the **inverse supply curve** + +We show an example below where the inverse supply curve is + +$$ p = 2 q^2$$ + +The shaded area is the total producer surplus in this continuous model. + +```{code-cell} ipython3 +def inverse_supply(q): + return 2 * q**2 + +# solve for the value of q where supply meets price +q_star = (price / 2)**(1/2) + +fig, ax = plt.subplots() +ax.plot((q_min, q_max), (price, price), lw=2, label="price") +ax.plot(q_grid, inverse_supply(q_grid), + color="k", label="inverse supply curve") +small_grid = np.linspace(0, q_star, 500) +ax.fill_between(small_grid, inverse_supply(small_grid), + np.full(len(small_grid), price), + color="darkgreen", + alpha=0.4, label="producer surplus") +ax.vlines(q_star, 0, price, ls="--") +ax.set_ylabel("willingness to sell, price") +ax.set_xlabel("quantity") +ax.set_xlim(q_min, q_max) +ax.set_ylim(0, 60) +ax.text(q_star, -10, "$q^*$") +ax.legend() +plt.show() +``` + +## Integration + +How can we calculate the consumer and producer surplus in the continuous case? + +The short answer is: by using [integration](https://en.wikipedia.org/wiki/Integral). + +Some readers will already be familiar with the basics of integration. + +For those who are not, here is a quick introduction. + +In general, for a function $f$, the **integral** of $f$ over the interval $[a, b]$ is the area under the curve $f$ between $a$ and $b$. + +This value is written as $\int_a^b f(x) dx$ and illustrated in the figure below when $f(x) = \cos(x/2) + 1$. + +```{code-cell} ipython3 +def f(x): + return np.cos(x/2) + 1 + +xmin, xmax = 0, 5 +a, b = 1, 3 +x_grid = np.linspace(xmin, xmax, 1000) +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), + alpha=0.5, label="$\int_a^b f(x) dx$") +ax.legend() +plt.show() +``` + +There are many rules for calculating integrals, with different rules applying to different choices of $f$. + +Many of these rules relate to one of the most beautiful and powerful results in all of mathematics: the [fundamental theorem of calculus](https://en.wikipedia.org/wiki/Fundamental_theorem_of_calculus). + +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 + d x$, then + +$$ \int_a^b f(x) dx = c (b - a) + \frac{d}{2}(b^2 - a^2) $$ + +In fact this rule is so simple that it can be calculated from elementary geometry -- you might like to try by graphing $f$ and calculating the area under the curve between $a$ and $b$. + +We use this rule repeatedly in what follows. + ++++ + ## Supply and demand +Let's now put supply and demand together. + +This leads us to the all important notion of market equilibrium, and from there onto a discussion of equilibra and welfare. + +For most of this discussion, we'll assume that inverse demand and supply curves are **affine** functions of quantity. + +("Affine" means "linear plus a constant" and [here](https://math.stackexchange.com/questions/275310/what-is-the-difference-between-linear-and-affine-function) is a nice discussion about it.) + +We'll also assume affine inverse supply and demand functions when we study models with multiple consumption goods in our {doc}`subsequent lecture `. + +We do this in order to simplify the exposition and enable us to use just a few tools from linear algebra, namely, matrix multiplication and matrix inversion. + + We study a market for a single good in which buyers and sellers exchange a quantity $q$ for a price $p$. Quantity $q$ and price $p$ are both scalars. @@ -137,7 +423,6 @@ $$ (eq:cstm_spls) The next figure illustrates - ```{code-cell} ipython3 :tags: [hide-input] @@ -277,7 +562,6 @@ def W(q, market): The next figure plots welfare as a function of $q$. - ```{code-cell} ipython3 :tags: [hide-input] From cb0c74eca68c48800f171c04e39de72e1bc9a58f Mon Sep 17 00:00:00 2001 From: John Stachurski Date: Sun, 18 Feb 2024 15:42:54 +1100 Subject: [PATCH 02/10] misc --- lectures/intro_supply_demand.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index f92c8bb3..93eaaa64 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -16,7 +16,7 @@ kernelspec: ## Overview This lecture is about some models of equilibrium prices and quantities, one of -the main topics of elementary microeconomics. +the core topics of elementary microeconomics. Throughout the lecture, we focus on models with one good and one price. From b254d3a561fa1e1401662c9546907b9b7250de60 Mon Sep 17 00:00:00 2001 From: mmcky Date: Mon, 19 Feb 2024 10:58:47 +1100 Subject: [PATCH 03/10] @mmcky vscode review --- lectures/intro_supply_demand.md | 131 +++++++++++++++----------------- 1 file changed, 63 insertions(+), 68 deletions(-) diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index 93eaaa64..73426655 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -20,8 +20,10 @@ the core topics of elementary microeconomics. Throughout the lecture, we focus on models with one good and one price. +```{seealso} In a {doc}`subsequent lecture ` we will investigate settings with many goods. +``` ### Why does this model matter? @@ -35,12 +37,12 @@ This [zero-sum](https://en.wikipedia.org/wiki/Zero-sum_game) view of economics w There are many different expressions of this idea in economics. -This lecture dicusses one of the simplest: how free adjustment of prices can maximize a measure of social welfare in the market for a single good. +This lecture discusses one of the simplest: how free adjustment of prices can maximize a measure of social welfare in the market for a single good. ### Topics and infrastructure -Key infrastructure concepts that we'll encounter in this lecture are +Key infrastructure concepts that we will encounter in this lecture are: * inverse demand curves * inverse supply curves @@ -50,16 +52,14 @@ Key infrastructure concepts that we'll encounter in this lecture are * social welfare as the sum of consumer and producer surpluses * the relationship between equilibrium quantity and social welfare optimum - - -In our exposition we will use the following imports. +In our exposition we will use the following Python imports. ```{code-cell} ipython3 import numpy as np import matplotlib.pyplot as plt ``` -## Consumer Surplus +## Consumer surplus Before we look at the model of supply and demand, it will be helpful to have some background on (a) consumer and producer surpluses and (b) integration. @@ -71,7 +71,7 @@ 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. -Suppose that the willingness to pay amount for each of the 10 consumers is as follows: +Suppose that the willingness to pay for each of the 10 consumers is as follows: | consumer | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |----------------|----|----|----|----|----|----|----|----|----|-----| @@ -81,7 +81,9 @@ Suppose that the willingness to pay amount for each of the 10 consumers is as fo 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$. -(If $p=w_i$ the consumer is indifferent between buying and not buying; we arbitrarily assume that they buy.) +```{note} +If $p=w_i$ the consumer is indifferent between buying and not buying; we arbitrarily assume that they buy. +``` The **consumer surplus** of the $i$-th consumer is $\max\{w_i - p, 0\}$ @@ -117,8 +119,8 @@ plt.show() The total consumer surplus in this market is $$ - \sum_{i=1}^{10} \max\{w_i - p, 0\} - = \sum_{w_i \geq p} (w_i - p) +\sum_{i=1}^{10} \max\{w_i - p, 0\} += \sum_{w_i \geq p} (w_i - p) $$ Since consumer surplus $\max\{w_i-p,0\}$ of consumer $i$ is a measure of her gains from trade (i.e., extent to which the good is valued over and above the amount the consumer had to pay), it is reasonable to consider total consumer surplus as a measurement of consumer welfare. @@ -135,8 +137,6 @@ In this example, consumers 1 to 5 buy, and the quantity sold is 5. Below we drop the assumption that sellers will provide any amount at a given price and study how this changes outcomes. -+++ - ### A continuous approximation It is often convenient to assume that there is a "very large number" of consumers, so that willingness to pay becomes a continuous curve. @@ -149,15 +149,19 @@ An example is provided below, showing both an inverse demand curve and a set pri The inverse demand curve is given by -$$ p = 100 e^{-q} $$ +$$ +p = 100 e^{-q} +$$ ```{code-cell} ipython3 def inverse_demand(q): return 100 * np.exp(- q) +# build a grid to evaluate the function at different values of q q_min, q_max = 0, 5 q_grid = np.linspace(q_min, q_max, 1000) +# plot the inverse demand curve fig, ax = plt.subplots() ax.plot((q_min, q_max), (price, price), lw=2, label="price") ax.plot(q_grid, inverse_demand(q_grid), @@ -198,11 +202,9 @@ plt.show() The value $q^*$ is where the inverse demand curve meets price. -+++ - ## Producer surplus -Having dicussed demand, let's now switch over to the supply side of the market. +Having discussed demand, let's now switch over to the supply side of the market. ### The discrete case @@ -232,19 +234,19 @@ For example, a producer willing to sell at \$10 and selling at price \$20 makes Total producer surplus is given by $$ - \sum_{i=1}^{10} \max\{p - v_i, 0\} - = \sum_{p \geq v_i} (p - v_i) +\sum_{i=1}^{10} \max\{p - v_i, 0\} += \sum_{p \geq v_i} (p - v_i) $$ -+++ - As for the consumer case, it can be helpful for analysis if we approximate producer willingness to sell into a continuous curve. This curve is called the **inverse supply curve** We show an example below where the inverse supply curve is -$$ p = 2 q^2$$ +$$ +p = 2 q^2 +$$ The shaded area is the total producer surplus in this continuous model. @@ -255,6 +257,7 @@ def inverse_supply(q): # solve for the value of q where supply meets price q_star = (price / 2)**(1/2) +# plot the inverse supply curve fig, ax = plt.subplots() ax.plot((q_min, q_max), (price, price), lw=2, label="price") ax.plot(q_grid, inverse_supply(q_grid), @@ -313,29 +316,30 @@ We will not try to cover these ideas here, partly because the subject is too big If $f(x) = c + d x$, then -$$ \int_a^b f(x) dx = c (b - a) + \frac{d}{2}(b^2 - a^2) $$ +$$ +\int_a^b f(x) dx = c (b - a) + \frac{d}{2}(b^2 - a^2) +$$ In fact this rule is so simple that it can be calculated from elementary geometry -- you might like to try by graphing $f$ and calculating the area under the curve between $a$ and $b$. We use this rule repeatedly in what follows. -+++ - ## Supply and demand Let's now put supply and demand together. -This leads us to the all important notion of market equilibrium, and from there onto a discussion of equilibra and welfare. +This leads us to the all important notion of market equilibrium, and from there onto a discussion of equilibria and welfare. For most of this discussion, we'll assume that inverse demand and supply curves are **affine** functions of quantity. -("Affine" means "linear plus a constant" and [here](https://math.stackexchange.com/questions/275310/what-is-the-difference-between-linear-and-affine-function) is a nice discussion about it.) +```{note} +"Affine" means "linear plus a constant" and [here](https://math.stackexchange.com/questions/275310/what-is-the-difference-between-linear-and-affine-function) is a nice discussion about it. +``` We'll also assume affine inverse supply and demand functions when we study models with multiple consumption goods in our {doc}`subsequent lecture `. We do this in order to simplify the exposition and enable us to use just a few tools from linear algebra, namely, matrix multiplication and matrix inversion. - We study a market for a single good in which buyers and sellers exchange a quantity $q$ for a price $p$. Quantity $q$ and price $p$ are both scalars. @@ -343,17 +347,15 @@ Quantity $q$ and price $p$ are both scalars. We assume that inverse demand and supply curves for the good are: $$ - p = d_0 - d_1 q, \quad d_0, d_1 > 0 +p = d_0 - d_1 q, \quad d_0, d_1 > 0 $$ $$ - p = s_0 + s_1 q , \quad s_0, s_1 > 0 +p = s_0 + s_1 q , \quad s_0, s_1 > 0 $$ We call them inverse demand and supply curves because price is on the left side of the equation rather than on the right side as it would be in a direct demand or supply function. - - Here is a class that stores parameters for our single good market, as well as implementing the inverse demand and supply curves. @@ -417,8 +419,8 @@ We define **consumer surplus** $S_c(q)$ as the area under an inverse demand curve minus $p q$: $$ - S_c(q) := - \int_0^{q} (d_0 - d_1 x) dx - p q +S_c(q) := +\int_0^{q} (d_0 - d_1 x) dx - p q $$ (eq:cstm_spls) The next figure illustrates @@ -464,24 +466,20 @@ quantity purchased is $q$ and the purchase price is $p$. Evaluating the integral in the definition of consumer surplus {eq}`eq:cstm_spls` gives $$ - S_c(q) - = d_0 q - \frac{1}{2} d_1 q^2 - p q +S_c(q) += d_0 q - \frac{1}{2} d_1 q^2 - p q $$ - - - ### Producer surplus Let a quantity $q$ be given and let $p := s_0 + s_1 q$ be the corresponding price on the inverse supply curve. - We define **producer surplus** as $p q$ minus the area under an inverse supply curve $$ - S_p(q) - := p q - \int_0^q (s_0 + s_1 x) dx +S_p(q) +:= p q - \int_0^q (s_0 + s_1 x) dx $$ (eq:pdcr_spls) The next figure illustrates @@ -528,7 +526,7 @@ The value $S_p(q)$ is the integral of these surpluses. Evaluating the integral in the definition of producer surplus {eq}`eq:pdcr_spls` gives $$ - S_p(q) = pq - s_0 q - \frac{1}{2} s_1 q^2 +S_p(q) = pq - s_0 q - \frac{1}{2} s_1 q^2 $$ @@ -539,14 +537,14 @@ equals consumer surplus plus producer surplus, assuming that consumers and producers pay the same price: $$ - W(q) - = \int_0^q (d_0 - d_1 x) dx - \int_0^q (s_0 + s_1 x) dx +W(q) += \int_0^q (d_0 - d_1 x) dx - \int_0^q (s_0 + s_1 x) dx $$ Evaluating the integrals gives $$ - W(q) = (d_0 - s_0) q - \frac{1}{2} (d_1 + s_1) q^2 +W(q) = (d_0 - s_0) q - \frac{1}{2} (d_1 + s_1) q^2 $$ Here is a Python function that evaluates this social welfare at a given @@ -579,35 +577,33 @@ To compute a quantity that maximizes the welfare criterion, we differentiate $W$ with respect to $q$ and then set the derivative to zero. $$ - \frac{d W(q)}{d q} = d_0 - s_0 - (d_1 + s_1) q = 0 +\frac{d W(q)}{d q} = d_0 - s_0 - (d_1 + s_1) q = 0 $$ Solving for $q$ yields $$ - q = \frac{ d_0 - s_0}{s_1 + d_1} +q = \frac{ d_0 - s_0}{s_1 + d_1} $$ (eq:old1) Let's remember the quantity $q$ given by equation {eq}`eq:old1` that a social planner would choose to maximize consumer surplus plus producer surplus. We'll compare it to the quantity that emerges in a competitive equilibrium that equates supply to demand. - - ### Competitive equilibrium Instead of equating quantities supplied and demanded, we can accomplish the same thing by equating demand price to supply price: $$ - p = d_0 - d_1 q = s_0 + s_1 q +p = d_0 - d_1 q = s_0 + s_1 q $$ If we solve the equation defined by the second equality in the above line for $q$, we obtain $$ - q = \frac{ d_0 - s_0}{s_1 + d_1} +q = \frac{ d_0 - s_0}{s_1 + d_1} $$ (eq:equilib_q) @@ -635,11 +631,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 @@ -647,16 +643,15 @@ Suppose now that the inverse demand and supply curves are modified to take the form $$ - p = i_d(q) := d_0 - d_1 q^{0.6} +p = i_d(q) := d_0 - d_1 q^{0.6} $$ $$ - p = i_s(q) := s_0 + s_1 q^{1.8} +p = i_s(q) := s_0 + s_1 q^{1.8} $$ All parameters are positive, as before. - ```{exercise} :label: isd_ex1 @@ -731,7 +726,7 @@ As before, consumer surplus at $q$ is the area under the demand curve minus price times quantity: $$ - S_c(q) = \int_0^{q} i_d(x) dx - p q +S_c(q) = \int_0^{q} i_d(x) dx - p q $$ Here $p$ is set to $i_d(q)$ @@ -740,8 +735,8 @@ Producer surplus is price times quantity minus the area under the inverse supply curve: $$ - S_p(q) - = p q - \int_0^q i_s(x) dx +S_p(q) += p q - \int_0^q i_s(x) dx $$ Here $p$ is set to $i_s(q)$. @@ -750,8 +745,8 @@ Social welfare is the sum of consumer and producer surplus under the assumption that the price is the same for buyers and sellers: $$ - W(q) - = \int_0^q i_d(x) dx - \int_0^q i_s(x) dx +W(q) += \int_0^q i_d(x) dx - \int_0^q i_s(x) dx $$ Solve the integrals and write a function to compute this quantity numerically @@ -769,9 +764,9 @@ Plot welfare as a function of $q$. Solving the integrals gives $$ - W(q) - = d_0 q - \frac{d_1 q^{1.6}}{1.6} - - \left( s_0 q + \frac{s_1 q^{2.8}}{2.8} \right) +W(q) += d_0 q - \frac{d_1 q^{1.6}}{1.6} + - \left( s_0 q + \frac{s_1 q^{2.8}}{2.8} \right) $$ Here's a Python function that computes this value: @@ -804,7 +799,7 @@ plt.show() ```{exercise} :label: isd_ex3 -Due to nonlinearities, the new welfare function is not easy to maximize with +Due to non-linearities, the new welfare function is not easy to maximize with pencil and paper. Maximize it using `scipy.optimize.minimize_scalar` instead. @@ -844,7 +839,7 @@ and demand. You can do this numerically by finding the root of the excess demand function $$ - e_d(q) := i_d(q) - i_s(q) +e_d(q) := i_d(q) - i_s(q) $$ You can use `scipy.optimize.newton` to compute the root. From 541a962db87ac1303207f11ce3a54e3de66b4019 Mon Sep 17 00:00:00 2001 From: mmcky Date: Mon, 19 Feb 2024 11:17:20 +1100 Subject: [PATCH 04/10] @mmcky review in jupyter lab, standardise colors + math updates --- lectures/intro_supply_demand.md | 60 +++++++++++++++++---------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index 73426655..f41243bb 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.15.2 + jupytext_version: 1.15.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -98,7 +98,6 @@ The total height of each bar $i$ is willingness to pay by consumer $i$. The orange portion of some of the bars shows consumer surplus. - ```{code-cell} ipython3 fig, ax = plt.subplots() consumers = range(1, 11) # consumers 1,..., 10 @@ -165,7 +164,7 @@ q_grid = np.linspace(q_min, q_max, 1000) fig, ax = plt.subplots() ax.plot((q_min, q_max), (price, price), lw=2, label="price") ax.plot(q_grid, inverse_demand(q_grid), - color="k", label="inverse demand curve") + color="orange", label="inverse demand curve") ax.set_ylabel("willingness to pay, price") ax.set_xlabel("quantity") ax.set_xlim(q_min, q_max) @@ -185,11 +184,11 @@ q_star = np.log(100) - np.log(price) fig, ax = plt.subplots() ax.plot((q_min, q_max), (price, price), lw=2, label="price") ax.plot(q_grid, inverse_demand(q_grid), - color="k", label="inverse demand curve") + color="orange", label="inverse demand curve") small_grid = np.linspace(0, q_star, 500) ax.fill_between(small_grid, np.full(len(small_grid), price), - inverse_demand(small_grid), color="darkorange", - alpha=0.6, label="consumer surplus") + inverse_demand(small_grid), color="orange", + alpha=0.5, label="consumer surplus") ax.vlines(q_star, 0, price, ls="--") ax.set_ylabel("willingness to pay, price") ax.set_xlabel("quantity") @@ -261,12 +260,12 @@ q_star = (price / 2)**(1/2) fig, ax = plt.subplots() ax.plot((q_min, q_max), (price, price), lw=2, label="price") ax.plot(q_grid, inverse_supply(q_grid), - color="k", label="inverse supply curve") + color="green", label="inverse supply curve") small_grid = np.linspace(0, q_star, 500) ax.fill_between(small_grid, inverse_supply(small_grid), np.full(len(small_grid), price), - color="darkgreen", - alpha=0.4, label="producer surplus") + color="green", + alpha=0.5, label="producer surplus") ax.vlines(q_star, 0, price, ls="--") ax.set_ylabel("willingness to sell, price") ax.set_xlabel("quantity") @@ -289,7 +288,7 @@ For those who are not, here is a quick introduction. In general, for a function $f$, the **integral** of $f$ over the interval $[a, b]$ is the area under the curve $f$ between $a$ and $b$. -This value is written as $\int_a^b f(x) dx$ and illustrated in the figure below when $f(x) = \cos(x/2) + 1$. +This value is written as $\int_a^b f(x) \mathrm{d} x$ and illustrated in the figure below when $f(x) = \cos(x/2) + 1$. ```{code-cell} ipython3 def f(x): @@ -303,7 +302,8 @@ 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), - alpha=0.5, label="$\int_a^b f(x) dx$") + label="$\int_a^b f(x) dx$", + color='grey', alpha=0.5) ax.legend() plt.show() ``` @@ -314,10 +314,10 @@ 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 + d x$, then +If $f(x) = c + \mathrm{d} x$, then $$ -\int_a^b f(x) dx = c (b - a) + \frac{d}{2}(b^2 - a^2) +\int_a^b f(x) \mathrm{d} x = c (b - a) + \frac{d}{2}(b^2 - a^2) $$ In fact this rule is so simple that it can be calculated from elementary geometry -- you might like to try by graphing $f$ and calculating the area under the curve between $a$ and $b$. @@ -397,8 +397,8 @@ supply_curve = market.inverse_supply(q_grid) demand_curve = market.inverse_demand(q_grid) fig, ax = plt.subplots() -ax.plot(q_grid, supply_curve, label='supply') -ax.plot(q_grid, demand_curve, label='demand') +ax.plot(q_grid, supply_curve, label='supply', color='green') +ax.plot(q_grid, demand_curve, label='demand', color='orange') ax.legend(loc='upper center', frameon=False) ax.set_ylim(0, 1.2) ax.set_xticks((0, 1)) @@ -420,7 +420,7 @@ curve minus $p q$: $$ S_c(q) := -\int_0^{q} (d_0 - d_1 x) dx - p q +\int_0^{q} (d_0 - d_1 x) \mathrm{d} x - p q $$ (eq:cstm_spls) The next figure illustrates @@ -433,12 +433,13 @@ p = market.inverse_demand(q) ps = np.ones_like(q_grid) * p fig, ax = plt.subplots() -ax.plot(q_grid, demand_curve, label='demand') +ax.plot(q_grid, demand_curve, label='demand', color='orange') ax.fill_between(q_grid[q_grid <= q], demand_curve[q_grid <= q], ps[q_grid <= q], label='consumer surplus', - color='#EED1CF') + color="orange", + alpha=0.5) ax.vlines(q, 0, p, linestyle="dashed", color='black', alpha=0.7) ax.hlines(p, 0, q, linestyle="dashed", color='black', alpha=0.7) @@ -479,7 +480,7 @@ We define **producer surplus** as $p q$ minus the area under an inverse supply c $$ S_p(q) -:= p q - \int_0^q (s_0 + s_1 x) dx +:= p q - \int_0^q (s_0 + s_1 x) \mathrm{d} x $$ (eq:pdcr_spls) The next figure illustrates @@ -492,12 +493,13 @@ p = market.inverse_supply(q) ps = np.ones_like(q_grid) * p fig, ax = plt.subplots() -ax.plot(q_grid, supply_curve, label='supply') +ax.plot(q_grid, supply_curve, label='supply', color='green') ax.fill_between(q_grid[q_grid <= q], supply_curve[q_grid <= q], ps[q_grid <= q], label='producer surplus', - color='#E6E6F5') + color="green", + alpha=0.5) ax.vlines(q, 0, p, linestyle="dashed", color='black', alpha=0.7) ax.hlines(p, 0, q, linestyle="dashed", color='black', alpha=0.7) @@ -538,7 +540,7 @@ producers pay the same price: $$ W(q) -= \int_0^q (d_0 - d_1 x) dx - \int_0^q (s_0 + s_1 x) dx += \int_0^q (d_0 - d_1 x) dx - \int_0^q (s_0 + s_1 x) \mathrm{d} x $$ Evaluating the integrals gives @@ -565,7 +567,7 @@ The next figure plots welfare as a function of $q$. q_vals = np.linspace(0, 1.78, 200) fig, ax = plt.subplots() -ax.plot(q_vals, W(q_vals, market), label='welfare') +ax.plot(q_vals, W(q_vals, market), label='welfare', color='brown') ax.legend(frameon=False) ax.set_xlabel('quantity') plt.show() @@ -577,7 +579,7 @@ To compute a quantity that maximizes the welfare criterion, we differentiate $W$ with respect to $q$ and then set the derivative to zero. $$ -\frac{d W(q)}{d q} = d_0 - s_0 - (d_1 + s_1) q = 0 +\frac{\mathrm{d} W(q)}{\mathrm{d} q} = d_0 - s_0 - (d_1 + s_1) q = 0 $$ Solving for $q$ yields @@ -704,8 +706,8 @@ supply_curve = market.inverse_supply(q_grid) demand_curve = market.inverse_demand(q_grid) fig, ax = plt.subplots() -ax.plot(q_grid, supply_curve, label='supply') -ax.plot(q_grid, demand_curve, label='demand') +ax.plot(q_grid, supply_curve, label='supply', color='green') +ax.plot(q_grid, demand_curve, label='demand', color='orange') ax.legend(loc='upper center', frameon=False) ax.set_ylim(0, 1.2) ax.set_xticks((0, 1)) @@ -736,7 +738,7 @@ supply curve: $$ S_p(q) -= p q - \int_0^q i_s(x) dx += p q - \int_0^q i_s(x) \mathrm{d} x $$ Here $p$ is set to $i_s(q)$. @@ -746,7 +748,7 @@ assumption that the price is the same for buyers and sellers: $$ W(q) -= \int_0^q i_d(x) dx - \int_0^q i_s(x) dx += \int_0^q i_d(x) dx - \int_0^q i_s(x) \mathrm{d} x $$ Solve the integrals and write a function to compute this quantity numerically @@ -786,7 +788,7 @@ The next figure plots welfare as a function of $q$. ```{code-cell} ipython3 fig, ax = plt.subplots() -ax.plot(q_vals, W(q_vals, market), label='welfare') +ax.plot(q_vals, W(q_vals, market), label='welfare', color='brown') ax.legend(frameon=False) ax.set_xlabel('quantity') plt.show() From bbb1577aae0cf7a0e6a16334f152b89a3ba2644b Mon Sep 17 00:00:00 2001 From: mmcky Date: Mon, 19 Feb 2024 15:31:56 +1100 Subject: [PATCH 05/10] migrate to namedtuple over class implementation for Market --- lectures/intro_supply_demand.md | 89 +++++++++++++++------------------ 1 file changed, 40 insertions(+), 49 deletions(-) diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index f41243bb..ec419c55 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -57,6 +57,7 @@ In our exposition we will use the following Python imports. ```{code-cell} ipython3 import numpy as np import matplotlib.pyplot as plt +from collections import namedtuple ``` ## Consumer surplus @@ -356,45 +357,38 @@ $$ We call them inverse demand and supply curves because price is on the left side of the equation rather than on the right side as it would be in a direct demand or supply function. -Here is a class that stores parameters for our single good market, as well as -implementing the inverse demand and supply curves. +We can use a [namedtuple](https://docs.python.org/3/library/collections.html#collections.namedtuple) to store the parameters for our single good market. ```{code-cell} ipython3 -class Market: +Market = namedtuple('Market', ['d_0', # demand intercept + 'd_1', # demand slope + 's_0', # supply intercept + 's_1'] # supply slope + ) - def __init__(self, - d_0=1.0, # demand intercept - d_1=0.6, # demand slope - s_0=0.1, # supply intercept - s_1=0.4): # supply slope - - self.d_0, self.d_1 = d_0, d_1 - self.s_0, self.s_1 = s_0, s_1 - - def inverse_demand(self, q): - return self.d_0 - self.d_1 * q - - def inverse_supply(self, q): - return self.s_0 + self.s_1 * q +def create_market(d_0=1.0, d_1=0.6, s_0=0.1, s_1=0.4): + return Market(d_0=d_0, d_1=d_1, s_0=s_0, s_1=s_1) ``` -Let's create an instance. +This `Market` namedtuple can then be used by our `inverse_demand` and `inverse_supply` functions. ```{code-cell} ipython3 -market = Market() +def inverse_demand(q, model): + return model.d_0 - model.d_1 * q + +def inverse_supply(q, model): + return model.s_0 + model.s_1 * q ``` Here is a plot of these two functions using `market`. ```{code-cell} ipython3 -:tags: [hide-input] - -market = Market() +market = create_market() grid_min, grid_max, grid_size = 0, 1.5, 200 q_grid = np.linspace(grid_min, grid_max, grid_size) -supply_curve = market.inverse_supply(q_grid) -demand_curve = market.inverse_demand(q_grid) +supply_curve = inverse_supply(q_grid, market) +demand_curve = inverse_demand(q_grid, market) fig, ax = plt.subplots() ax.plot(q_grid, supply_curve, label='supply', color='green') @@ -429,7 +423,7 @@ The next figure illustrates :tags: [hide-input] q = 1.25 -p = market.inverse_demand(q) +p = inverse_demand(q, market) ps = np.ones_like(q_grid) * p fig, ax = plt.subplots() @@ -489,7 +483,7 @@ The next figure illustrates :tags: [hide-input] q = 0.75 -p = market.inverse_supply(q) +p = inverse_supply(q, market) ps = np.ones_like(q_grid) * p fig, ax = plt.subplots() @@ -670,40 +664,37 @@ Using the class, plot the inverse demand and supply curves $i_d$ and $i_s$ :class: dropdown ``` -```{code-cell} ipython3 -class Market: - - def __init__(self, - d_0=1.0, # demand intercept - d_1=0.6, # demand slope - s_0=0.1, # supply intercept - s_1=0.4): # supply slope +Let us make use of a [namedtuple](https://docs.python.org/3/library/collections.html#collections.namedtuple) container provided by Python to hold the parameters of the Market. - self.d_0, self.d_1 = d_0, d_1 - self.s_0, self.s_1 = s_0, s_1 - - def inverse_demand(self, q): - return self.d_0 - self.d_1 * q**0.6 - - def inverse_supply(self, q): - return self.s_0 + self.s_1 * q**1.8 +```{code-cell} ipython3 +Market = namedtuple('Market', ['d_0', # demand intercept + 'd_1', # demand slope + 's_0', # supply intercept + 's_1'] # supply slope + ) ``` -Let's create an instance. +We can now define some functions that `create` and `operate` on these Market parameters. ```{code-cell} ipython3 -market = Market() +def create_market(d_0=1.0, d_1=0.6, s_0=0.1, s_1=0.4): + return Market(d_0=d_0, d_1=d_1, s_0=s_0, s_1=s_1) + +def inverse_demand(q, model): + return model.d_0 - model.d_1 * q**0.6 + +def inverse_supply(q, model): + return model.s_0 + model.s_1 * q**1.8 ``` Here is a plot of inverse supply and demand. ```{code-cell} ipython3 -:tags: [hide-input] - grid_min, grid_max, grid_size = 0, 1.5, 200 q_grid = np.linspace(grid_min, grid_max, grid_size) -supply_curve = market.inverse_supply(q_grid) -demand_curve = market.inverse_demand(q_grid) +market = create_market() +supply_curve = inverse_supply(q_grid, market) +demand_curve = inverse_demand(q_grid, market) fig, ax = plt.subplots() ax.plot(q_grid, supply_curve, label='supply', color='green') @@ -864,7 +855,7 @@ price, in line with the first fundamental welfare theorem. from scipy.optimize import newton def excess_demand(q): - return market.inverse_demand(q) - market.inverse_supply(q) + return inverse_demand(q, market) - inverse_supply(q, market) equilibrium_q = newton(excess_demand, 0.99) print(f"{equilibrium_q: .5f}") From 0b81954d17893c398aae3c77cf0e484ea86100e1 Mon Sep 17 00:00:00 2001 From: mmcky Date: Mon, 19 Feb 2024 15:36:24 +1100 Subject: [PATCH 06/10] add links and references to pyprog:scipy --- lectures/intro_supply_demand.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index ec419c55..e4cd54b9 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -797,6 +797,12 @@ pencil and paper. Maximize it using `scipy.optimize.minimize_scalar` instead. +```{seealso} +Our [SciPy](https://python-programming.quantecon.org/scipy.html) lecture has +a section on [Optimization](https://python-programming.quantecon.org/scipy.html#optimization) +is a useful resource to find out more. +``` + ``` @@ -837,6 +843,12 @@ $$ You can use `scipy.optimize.newton` to compute the root. +```{seealso} +Our [SciPy](https://python-programming.quantecon.org/scipy.html) lecture has +a section on [Roots and Fixed Points](https://python-programming.quantecon.org/scipy.html#roots-and-fixed-points) +is a useful resource to find out more. +``` + Initialize `newton` with a starting guess somewhere close to 1.0. (Similar initial conditions will give the same result.) From 046db95f04ae185e3fcaca6816f8e2731d5bb126 Mon Sep 17 00:00:00 2001 From: mmcky Date: Mon, 19 Feb 2024 15:39:18 +1100 Subject: [PATCH 07/10] update explantion text for create_market function --- lectures/intro_supply_demand.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index e4cd54b9..fe9c03b3 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -365,12 +365,16 @@ Market = namedtuple('Market', ['d_0', # demand intercept 's_0', # supply intercept 's_1'] # supply slope ) +``` + +The function below creates an instance of a Market namedtuple with default values. +```{code-cell} ipython3 def create_market(d_0=1.0, d_1=0.6, s_0=0.1, s_1=0.4): return Market(d_0=d_0, d_1=d_1, s_0=s_0, s_1=s_1) ``` -This `Market` namedtuple can then be used by our `inverse_demand` and `inverse_supply` functions. +This `market` can then be used by our `inverse_demand` and `inverse_supply` functions. ```{code-cell} ipython3 def inverse_demand(q, model): From 5e2d75bcb745ff5274c0d292bd80dae3e1ae8304 Mon Sep 17 00:00:00 2001 From: mmcky Date: Mon, 19 Feb 2024 15:54:39 +1100 Subject: [PATCH 08/10] @mmcky re-read --- lectures/intro_supply_demand.md | 48 ++++++++++----------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index fe9c03b3..934e40cd 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -64,7 +64,7 @@ from collections import namedtuple Before we look at the model of supply and demand, it will be helpful to have some background on (a) consumer and producer surpluses and (b) integration. -(If you are comfortable with both topics you can jump to the next section.) +(If you are comfortable with both topics you can jump to the {ref}`next section `.) ### A discrete example @@ -277,6 +277,7 @@ ax.legend() plt.show() ``` +(integration)= ## Integration How can we calculate the consumer and producer surplus in the continuous case? @@ -357,7 +358,7 @@ $$ We call them inverse demand and supply curves because price is on the left side of the equation rather than on the right side as it would be in a direct demand or supply function. -We can use a [namedtuple](https://docs.python.org/3/library/collections.html#collections.namedtuple) to store the parameters for our single good market. +We can use a [namedtuple](https://docs.python.org/3/library/collections.html#collections.namedtuple) to store the parameters for our single good market. ```{code-cell} ipython3 Market = namedtuple('Market', ['d_0', # demand intercept @@ -552,10 +553,8 @@ quantity $q$ and a fixed set of parameters. ```{code-cell} ipython3 def W(q, market): - # Unpack - d_0, d_1, s_0, s_1 = market.d_0, market.d_1, market.s_0, market.s_1 # Compute and return welfare - return (d_0 - s_0) * q - 0.5 * (d_1 + s_1) * q**2 + return (market.d_0 - market.s_0) * q - 0.5 * (market.d_1 + market.s_1) * q**2 ``` The next figure plots welfare as a function of $q$. @@ -655,35 +654,20 @@ All parameters are positive, as before. ```{exercise} :label: isd_ex1 -Define a new `Market` class that holds the same parameter values as before by -changing the `inverse_demand` and `inverse_supply` methods to -match these new definitions. +Use the same `Market` namedtuple that holds the parameter values as before but +make new `inverse_demand` and `inverse_supply` functions to match these new definitions. -Using the class, plot the inverse demand and supply curves $i_d$ and $i_s$ +Then plot the inverse demand and supply curves $i_d$ and $i_s$. ``` - ```{solution-start} isd_ex1 :class: dropdown ``` -Let us make use of a [namedtuple](https://docs.python.org/3/library/collections.html#collections.namedtuple) container provided by Python to hold the parameters of the Market. - -```{code-cell} ipython3 -Market = namedtuple('Market', ['d_0', # demand intercept - 'd_1', # demand slope - 's_0', # supply intercept - 's_1'] # supply slope - ) -``` - -We can now define some functions that `create` and `operate` on these Market parameters. +Let's update the `inverse_demand` and `inverse_supply` functions, as defined above. ```{code-cell} ipython3 -def create_market(d_0=1.0, d_1=0.6, s_0=0.1, s_1=0.4): - return Market(d_0=d_0, d_1=d_1, s_0=s_0, s_1=s_1) - def inverse_demand(q, model): return model.d_0 - model.d_1 * q**0.6 @@ -750,7 +734,6 @@ Solve the integrals and write a function to compute this quantity numerically at given $q$. Plot welfare as a function of $q$. - ``` @@ -770,12 +753,9 @@ Here's a Python function that computes this value: ```{code-cell} ipython3 def W(q, market): - # Unpack - d_0, d_1 = market.d_0, market.d_1 - s_0, s_1 = market.s_0, market.s_1 # Compute and return welfare - S_c = d_0 * q - d_1 * q**1.6 / 1.6 - S_p = s_0 * q + s_1 * q**2.8 / 2.8 + S_c = market.d_0 * q - market.d_1 * q**1.6 / 1.6 + S_p = market.s_0 * q + market.s_1 * q**2.8 / 2.8 return S_c - S_p ``` @@ -793,7 +773,7 @@ plt.show() ``` -```{exercise} +````{exercise} :label: isd_ex3 Due to non-linearities, the new welfare function is not easy to maximize with @@ -807,7 +787,7 @@ a section on [Optimization](https://python-programming.quantecon.org/scipy.html# is a useful resource to find out more. ``` -``` +```` ```{solution-start} isd_ex3 @@ -833,7 +813,7 @@ print(f"{maximizing_q: .5f}") ``` -```{exercise} +````{exercise} :label: isd_ex4 Now compute the equilibrium quantity by finding the price that equates supply @@ -860,7 +840,7 @@ Initialize `newton` with a starting guess somewhere close to 1.0. You should find that the equilibrium price agrees with the welfare maximizing price, in line with the first fundamental welfare theorem. -``` +```` ```{solution-start} isd_ex4 From 215e2d9182e97f01297a4ff9ba9ade8908dfedc7 Mon Sep 17 00:00:00 2001 From: mmcky Date: Mon, 19 Feb 2024 20:27:28 +1100 Subject: [PATCH 09/10] fig: add captions and numbers --- lectures/intro_supply_demand.md | 65 +++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index 934e40cd..a673d41d 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -100,6 +100,12 @@ The total height of each bar $i$ is willingness to pay by consumer $i$. The orange portion of some of the bars shows consumer surplus. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "Willingness to pay (discrete)" + name: wpdisc +--- fig, ax = plt.subplots() consumers = range(1, 11) # consumers 1,..., 10 # willingness to pay for each consumer @@ -154,6 +160,12 @@ p = 100 e^{-q} $$ ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "Willingness to pay (continuous)" + name: wpcont +--- def inverse_demand(q): return 100 * np.exp(- q) @@ -179,6 +191,12 @@ Reasoning by analogy with the discrete case, the area under the demand curve and The consumer surplus is shaded in the figure below. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "Willingness to pay (continuous) with consumer surplus" + name: wpcont_cs +--- # solve for the value of q where demand meets price q_star = np.log(100) - np.log(price) @@ -211,12 +229,18 @@ Having discussed demand, let's now switch over to the supply side of the market. The figure below shows the price at which a collection of producers, also numbered 1 to 10, are willing to sell one unit of the good in question ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "Willingness to sell (discrete)" + name: wsdisc +--- fig, ax = plt.subplots() producers = range(1, 11) # producers 1,..., 10 # willingness to sell for each producer wts = (5, 8, 17, 22, 35, 39, 46, 57, 88, 91) price = 25 -ax.bar(producers, wts, label="willingness to sell", color="blue", alpha=0.8) +ax.bar(producers, wts, label="willingness to sell", color="green", alpha=0.5) ax.set_xlim(0, 12) ax.set_xticks(producers) ax.set_ylabel("willingness to sell") @@ -251,6 +275,12 @@ $$ The shaded area is the total producer surplus in this continuous model. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "Willingness to sell (continuous) with producer surplus" + name: wscont +--- def inverse_supply(q): return 2 * q**2 @@ -293,6 +323,12 @@ In general, for a function $f$, the **integral** of $f$ over the interval $[a, b This value is written as $\int_a^b f(x) \mathrm{d} x$ and illustrated in the figure below when $f(x) = \cos(x/2) + 1$. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "Area under the curve" + name: integrate +--- def f(x): return np.cos(x/2) + 1 @@ -304,8 +340,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$", - color='grey', alpha=0.5) + label="$\int_a^b f(x) dx$") ax.legend() plt.show() ``` @@ -388,6 +423,12 @@ def inverse_supply(q, model): Here is a plot of these two functions using `market`. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "Supply and demand" + name: supply_demand +--- market = create_market() grid_min, grid_max, grid_size = 0, 1.5, 200 @@ -425,6 +466,12 @@ $$ (eq:cstm_spls) The next figure illustrates ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "Supply and demand (consumer surplus)" + name: supply_demand_cs +--- :tags: [hide-input] q = 1.25 @@ -485,6 +532,12 @@ $$ (eq:pdcr_spls) The next figure illustrates ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "Supply and demand (producer surplus)" + name: supply_demand_ps +--- :tags: [hide-input] q = 0.75 @@ -560,6 +613,12 @@ def W(q, market): The next figure plots welfare as a function of $q$. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: "Welfare" + name: wf +--- :tags: [hide-input] q_vals = np.linspace(0, 1.78, 200) From bb680be29c11a6ffbd14e251dba1ae6eb1cd4f26 Mon Sep 17 00:00:00 2001 From: mmcky Date: Mon, 19 Feb 2024 20:38:17 +1100 Subject: [PATCH 10/10] fix config status issue --- lectures/intro_supply_demand.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lectures/intro_supply_demand.md b/lectures/intro_supply_demand.md index a673d41d..baacb821 100644 --- a/lectures/intro_supply_demand.md +++ b/lectures/intro_supply_demand.md @@ -471,8 +471,8 @@ mystnb: figure: caption: "Supply and demand (consumer surplus)" name: supply_demand_cs +tags: [hide-input] --- -:tags: [hide-input] q = 1.25 p = inverse_demand(q, market) @@ -537,8 +537,8 @@ mystnb: figure: caption: "Supply and demand (producer surplus)" name: supply_demand_ps +tags: [hide-input] --- -:tags: [hide-input] q = 0.75 p = inverse_supply(q, market) @@ -618,8 +618,8 @@ mystnb: figure: caption: "Welfare" name: wf +tags: [hide-input] --- -:tags: [hide-input] q_vals = np.linspace(0, 1.78, 200) fig, ax = plt.subplots()