Chapter 7 Producer
import requests
= requests.get("https://www.dropbox.com/s/cyp43ve6wyqnof1/consumers.py?dl=1")
response = open("consumers.py", "w")
output_file_object
output_file_object.writelines(response.text)
output_file_object.close()
from pathlib import Path
= Path()
currentPath if currentPath.cwd() not in sys.path:
sys.path.append(currentPath.cwd())
import consumers as cs
from numpy.random import default_rng
= default_rng(2020)
rng_alpha = default_rng(3892)
rng_beta
= 500
size = [
consumers500 for alpha, beta in zip(rng_alpha.uniform(300,500,size), rng_beta.uniform(5,30,size))
cs.Consumer(alpha, beta) ]
- It is wise to close a file object when necessary operations are finished.
7.1 Monopoly
Suppose a monopoly has a constant marginal cost (mc) with no fixed cost. The producer sees market demand (i.e. aggregate demand, Qd), and decides market price. The quantity he can sell at a given price level is Qd(p)
class Monopoly:
def __init__(self, mc, Qd):
self.mc=mc
self.Qd=Qd
def cost(self, p):
return self.mc*self.Qd(p)
def revenue(self, p):
return p*self.Qd(p)
def profit(self, p):
return p*self.Qd(p) - self.mc *self.Qd(p)
- A monopoly not only knows his own cost of production, but also knows exactly market demend (Qd).
7.1.1 Market demand
import numpy as np
def Qd(p):
return np.maximum(np.zeros(len(p)),100-2*p)
# np.zeros: generate array of zeros
# np.maximum: compare two arrays elementwise and choose the maximal one
= np.arange(1,101)
prices Qd(prices)
Qd
maps 1-D array to
from scipy import optimize
=Monopoly(2, Qd)
monopoly3]))
monopoly.cost(np.array([3]))
monopoly.revenue(np.array([3])) monopoly.profit(np.array([
7.1.2 Profit maximization
def negative_conversion(fn):
def neg_fun(p):
return -1*fn(p)
return neg_fun
=negative_conversion(monopoly.profit) objective_negative
optimize.minimize(=negative_conversion(monopoly.profit),
fun=np.array([3])
x0 )
def monopoly_optim(x0=3):
= optimize.minimize(
optim =negative_conversion(monopoly.profit),
fun=np.array([x0])
x0
)return optim
= monopoly_optim()
optim
optim.x monopoly.Qd(optim.x)
7.1.3 Class
class Monopoly:
def __init__(self, mc, Qd):
self.mc=mc
self.Qd=Qd
def cost(self, p):
return self.mc*self.Qd(p)
def revenue(self, p):
return p*self.Qd(p)
def profit(self, p):
return p*self.Qd(p) - self.mc *self.Qd(p)
def optimize(self, x0=3):
= optimize.minimize(
optim =negative_conversion(self.profit),
fun=np.array([x0])
x0
)self.optim_p = optim.x
self.optim_q = self.Qd(self.optim_p)
return optim
= Monopoly(5, Qd)
monopoly
monopoly.Qd monopoly.mc
monopoly.optimize()
monopoly.optim_p
monopoly.optim_q monopoly.profit(monopoly.optim_p)
7.2 Class variable
7.2.1 Class: Market Demand
class MarketDemand:
def __init__(self, intercept, slope):
self.intercept = intercept
self.slope = slope
def Qd(self, p):
return self.intercept - self.slope * p
= MarketDemand(500, 7)
marketDemand = marketDemand.Qd
Qd = Monopoly(10, Qd)
monopoly
monopoly.optimize()
monopoly.optim_p monopoly.optim_q
7.2.2 Change of demand
= MarketDemand(380, 5)
marketDemand2 = marketDemand2.Qd
Qd
# optimization will give the same result
monopoly.optimize()
monopoly.optim_p monopoly.optim_q
7.2.3 Class variable
import numpy as np
from scipy import optimize
class Monopoly:
=100
intercept=2
slope
def __init__(self, mc):
self.mc=mc
def cost(self, p):
return self.mc*self.__class__.Qd(p)
def revenue(self, p):
return p*self.__class__.Qd(p)
def profit(self, p):
return p*self.__class__.Qd(p) - self.mc *self.__class__.Qd(p)
def optimize(self, x0=3):
= optimize.minimize(
optim_res =negative_conversion(self.profit),
fun=np.array([x0])
x0
)self.optim_p = optim_res.x
self.optim_q = self.__class__.Qd(self.optim_p)
return optim_res
@classmethod
def Qd(cls, p):
return cls.intercept - cls.slope*p
# helper
def negative_conversion(fn):
def neg_fun(p):
return -1*fn(p)
return neg_fun
\[Qd(p)=100-2p\]
= Monopoly(5)
monopoly 3) monopoly.Qd(
\[Qd(p)=300-7p\]
= 300
Monopoly.intercept = 7
Monopoly.slope 3) monopoly.Qd(
Note that once class variables are changed. It stay that way until next change
= Monopoly(5) # will not go back to original Monopoly definition
monopoly2 3) monopoly2.Qd(
= 300
Monopoly.intercept = 7
Monopoly.slope
monopoly.optimize()
monopoly.optim_p monopoly.optim_q
= 100
Monopoly.intercept = 3
Monopoly.slope
monopoly.optimize()
monopoly.optim_p monopoly.optim_q
7.3 Ex-Post Manipulation
Class variables and instance variables can be manipulated ex post – including adding and deletion.
class Apple:
pass # do nothing
= Apple()
apple1 = Apple() apple2
# An instance variable
= "red"
apple1.color = "green"
apple2.color
# A class variable
type = "fruit" Apple.
# type is a class variable to all instances
type
apple1.__class__.type
apple2.__class__.# class variable can be accessed as it is an instance variables
# except all instances share the same value (common knowledge)
type
apple1.type
apple2.
# instance variables
apple1.color apple2.color
If there is also an instance variable called type
such as:
type = "animal" # instance variable creation apple1.
Then apple1.type
represents the instance variable instead of the class variable:
type
apple1.type # you still can access class variable (type) this way apple1.__class__.
Deletion:
del Apple.type
del apple1.color
del apple2.color
del apple1
del
can be used to delete any object in the environment:
del Apple
7.4 Common knowledge
7.4.1 Market structure narrative
In a country where demand is always linear, any demand is an instance of LinearDemand class via:
class LinearDemand:
def __init__(self, intercept, slope):
self.intercept=intercept
self.slope=slope
= LinearDemand(intercept=300, slope=0.2)
demand
demand.intercept demand.slope
There are three producers to serve the market: mono, duo, and trio. They are instances of the same Producer class.
How can we model the common knowledge demand for these three instances so that:
mono.demand
duo.demand
trio.demand# all are aware of the SAME demand
In addition, whenever something changes to demand, such as:
=500 demand.intercept
all instance.demand
s changes as well.
7.4.2 Common in id
=
: identical assignment
The first approach is to feed demand as instance variable when each instance is created. Consider the following class constructor:
class Producer:
def __init__(self, demand):
self.demand = demand
= Producer(demand)
mono = Producer(demand) duo
- The design ensures that demand is in mono and duo’s knowledge domain (as an instance variable).
The above construction has:
print(id(demand))
print(id(mono.demand))
print(id(duo.demand))
the same.
Change one will change all:
+= 2
demand.slope
demand.slope
mono.demand.slope duo.demand.slope
However, the above common knowledge structure works only under the same ID source of instance variable. It can be breached easily when users accidentally create another new instance source and feed it into a new instance, such as:
import copy
= copy.deepcopy(demand)
demand = Producer(demand)
trio
print(id(mono.demand))
print(id(duo.demand))
print(id(trio.demand)) # different from the other two
print(id(demand)) # same as trio, different from the other two
# change to demand
+= 50
demand.intercept
demand.intercept# changes
trio.demand.intercept
# but not
mono.demand.intercept duo.demand.intercept
7.4.3 Common as class variables
If you want to ensure mono, duo, trio share the common knowledge of demand, you ought to make demand a class variable.
class Producer:
pass
= Producer()
mono = Producer() duo
= LinearDemand(intercept=300, slope=0.2)
demand = demand
Producer.demand
print(id(mono.demand))
print(id(duo.demand))
# create a new copy
= copy.deepcopy(demand)
demand print(id(demand))
# Attach new copy to Producer
= demand
Producer.demand # will immediately change each instance's knowledge
print(id(mono.demand))
print(id(duo.demand))
- This is because the common knowledge ID comes from the class Producer – not from its own instance variable. This ensures each instance access the same source of demand knowledge.
Always model common knowledge across instances as their class variable.
7.5 Examples
7.5.1 Consumers
In an economy, there are many consumers with Cobb-Douglass utility: \[U(x_1, x_2)=x_1^\alpha x_2^{1-\alpha},\] with given prices \((p_1,p_2)\) and income \(I\). Optimal consumptions will be: \[x_1^*=\alpha*I/p_1,\ x_2^*=(1-\alpha)*I/p_2.\] Suppose there are 30 consumers randomly drawn from \(\alpha\sim uniform(0.2, 0.8)\) and \(I\sim uniform(500,1000)\)
from numpy.random import default_rng
= default_rng(2038).uniform(0.2,0.8, size=30)
alpha_s = default_rng(2033).uniform(500,100, size=30)
I_s
class Consumer:
def __init__(self, alpha, I):
self.alpha = alpha
self.I = I
def optimise(self):
= self.__class__.p
p1, p2 self.x1 = self.alpha * self.I/p1
self.x2 = (1-self.alpha) * self.I/p2
= [
consumers for alpha, I in zip(alpha_s, I_s)
Consumer(alpha, I) ]
- note that class variable p is not assigned yet.
# Given p1=1, p2=1
= (1, 1)
p # Assign it as common knowledge for all consumers
= p Consumer.p
Once consumers share the common knowledge, they know how much they want to consume:
for i in range(len(consumers)):
consumers[i].optimise()
# check their decisions
0].x1
consumers[0].x2
consumers[22].x1
consumers[22].x2 consumers[
You can also:
for consumer_i in consumers:
consumer_i.optimise()
# check their decisions
0].x1
consumers[0].x2
consumers[22].x1
consumers[22].x2 consumers[
- The iterates from the iterable object are representing its element identically (i.e. sharing the same memory address).
7.5.2 Producers
An economy has many log production function producers. Each has production function: \[q(x)=\sqrt x,\] where \(x\) is some intermediate input quantity (such as labor). Assume intermediate input has a constant unit price \(w\) so that hiring \(x\) units of intermediate input will incur \(wx\) total cost while generating \(q(x)\) units of output and \(p q(x)\) total revenue. This means the producer’s total profit function is: \[\pi(x)=p\sqrt x-wx.\]
There are 10 producers in the economy whose \(w\) is randomly drawn from \(w\sim uniform(2, 5)\). They take market price \(p\) as their common knowledge. They are price taker. Optimal production of output will have: \[x^*=(p/w)^2/4,\ q^*=(p/w)/2\]
= default_rng(2033).uniform(2,5, size=10)
rng_w
class Producer:
def __init__(self, w):
self.w=w
def optimise(self):
= self.__class__.p
p self.x = (p/self.w)**2 /4
self.q = (p/self.w)/2
= [
producers for w in rng_w
Producer(w) ]
- note that class variable p is not assignment yet.
# Given
= 1
p # Assign it as common knowledge for all producers
= p Producer.p
Once producers share the common knowledge, they know how many they want to produce:
for i in range(len(producers)):
producers[i].optimise()
# check their decisions
0].x
producers[0].q
producers[7].x
producers[7].q producers[
7.5.3 Competitive markets
A (perfect) competition market consists of market demand, marke supply and an equilibrium condition that requires demand equal to supply to determine equilibrium price and quantity.
import numpy as np
from scipy.optimize import root
class Competitive_market:
def equilibrium(self):
= lambda x: self.Qd(x) - self.Qs(x)
excess_demand = root(excess_demand, x0=np.array([1]))
result self.P = result.x
self.Q = self.Qd(self.P)
def excess_demand(x):
return Qd(x) - Qs(x)
= Competitive_market()
market
def Qd(p):
return max(0, 3-p)
def Qs(p):
return max(0, 0+2*p)
# supply Qd and Qs
= Qd
market.Qd = Qs
market.Qs
market.equilibrium()
market.P market.Q
We can change Qd and Qs instance variables, and reuse optimise instance method:
def Qd(p):
= (p, 1)
Consumer.p = 0
total for consumer_i in consumers:
consumer_i.optimise()+= consumer_i.x1
total return total
def Qs(p):
= p
Producer.p = 0
total for producer_i in producers:
producer_i.optimise()+= producer_i.q
total return total
= Qd
market.Qd = Qs
market.Qs
market.equilibrium()
market.P market.Q
7.6 綜合練習
1. Consumers
In an economy, there are many Cobb-Douglas preference consumers. Each faces a utility function \(U(\bf{x})\): \[U({\bf x})=x_1^{\alpha}x_2^{1-\alpha},\] where \({\bf x}=[x_1, x_2]\) is a vector representing the consumption of \((x_1, x_2)\) bundle.
For any consumer, say consumer \(i\), he faces a budget constraint: \[p_1x_1+p_2x_2\leq I_i,\] Assume that the market prices are \((p_1=2, p_2=5)\) at the current moment. We can give birth to a \((\alpha=0.3, I_i=200)\) consumer via:
= 0.3
alpha = 200
I = Consumer(alpha, I) consumer_i
Once he is born, he:
# is aware of his budget constraint
# will generate his budget constraint at the following instance variable
consumer_i.describe_budget_constraint() # shows a dictionary object that represents the nonnegative budget constraint description as restriction optimization procedure requires
consumer_i.budget_constraint # knows his preference
2,3]) # shows utility of x1=2, x2=3 consumption
consumer_i.U([# is able to optimize
# generate consumer_i.x1 consumer_i.x2 to show the optimized x1, x2 consumption bundle. consumer_i.optimize()
We describe the market prices change to \((p_1=2.5, p_2=4)\) via:
=2.5
Consumer.p1=4 Consumer.p2
Once the change is done, consumer_i can:
# re-optimize
consumer_i.optimize()# which gives you a new optimal consumption bundle
consumer_i.x1 consumer_i.x2
We can play God to give birth to 300 consumers via
from numpy.random import default_rng
= default_rng(2020)
rng_alpha = default_rng(2020)
rng_I = rng_alpha.uniform(0.01, 0.99, size=300)
world_alpha = rng_I.uniform(500, 1000, size=300)
world_I = [Consumer(alpha, I) for alpha, I in zip(world_alpha, world_I)] world_consumers
Not only does world_consumers
keep track of these 300 consumers, so does the class object Consumer
keep the record as well, which can be checked via:
Consumer.world_consumers
In addition, whenever God is not happy, it can destroy all consumers via:
Consumer.destroy()
which will turn Consumer.world_consumers
into an empty list.
Design the Consumer class.
2. Market demand function
Given the Consumer from question 1, run the following code to generate 30 consumers:
from numpy.random import default_rng
= default_rng(2020)
rng_alpha = default_rng(2020)
rng_I = rng_alpha.uniform(0.2, 0.8, size=30)
world_alpha = rng_I.uniform(500, 1000, size=30)
world_I
Consumer.destroy()for alpha, I in zip(world_alpha, world_I):
Consumer(alpha, I)
Complete the design of the following market demand function for \(x1\)
def Qd(class_consumer, p1):
....
Given the construction of 30 consumers earlier,
3) # You can use a **class** as an input argument. Qd(Consumer,
will return the quantity of market demand at a price of p1=3
(which is around 4718), given the default value of Consumer.p2=5
.
3. Cocky producer
Continue from the setting of question 1. There is only one producer Cocky who produces \(x_1\) (think it as chocolate cake). Cocky thinks his product is extremely unique so that the other commodity \(x_2\) (think it as bubble tea) is completely different and won’t affect Cocky’s profit – at least Cocky thinks so. At the current moment \(p_2=5\), Cocky think this price will continue to be that way no matter what price \(p_1\) he sets for \(x_1\).
Cocky is generated by a Producer1 class via:
= Producer1(5, Consumer) cocky
where 5 is his marginal cost of production, and Consumer is the class Consumer you design earlier.
Cocky:
# knows his market quantity demanded at price p1=3 via:
3)
cocky.Qd(# Other than that, he can calculate his cost of production at price =3
3)
cocky.cost(# his revenue of production at price=3
3)
cocky.revenue(# his profit of production at price=3
3) cocky.profit(
Cocky think the bubble tea will continue to charge at \(p_2=5\) as fixed via:
= 5 Consumer.p2
Given that perception, Cocky chooses a price \(p_1\) to maximize his profit via:
cocky.optimize()
# his optimal price and output will show up at
# around 9.99
cocky.p1 # around 1415 cocky.x1
You can play around with your simulated economy at different \(p_2\) price scenarios and see how Cocky would respond with his optimal \(p_1\). From the exercise, you can think about the following question:
Is there truly a pure monopoly in reality ?
同場加映(中間會有一首非常有名的曲子):
3. Prudent producer
Prue is the unique producer of \(x_2\). She grows up with Cocky; therefore, she know everything about Cocky. To model such an information structure, assume Prue is a instance generated by:
= Producer2(2, Consumer, cocky) Prue
Different from Cocky, whenever Prue thinks of her market demand, she thinks of the ability of the influence of her price \(p_2\) on \(p_1\) as an instance method, prue.p1
, which tells Prue what optimal p1 will be charge by Cocky. For example, to know how much Cocky will charge when Prue charges \(p_1=5\), he can:
5) # tell us what p1 will be when Prue set a price of 5 prue.p1(
Prue has two different types of market demands. One that take \(p_1\) as constant: \[\text{Qd_typeA} = Qd(p_2, p_1),\] the other takes \(p_1\) as an influced price of Prue’s \(p_2\), i.e. \[\text{Qd_typeB} = Qd(p_2, p_1^*(p_2)),\] where \(p_1^*(p_2)\) means the optimized price setting of \(p_1\) from Cocky given \(p_2\).
::opts_chunk$set(message=F, eval=F)
knitr::klippy(lang=c("r","python")) klippy