Level 3 · Economics: Firms and the Macro Model
Level 1 drew supply curves without asking where they come from, and Level 2 followed one shopper's choices. This level turns to the sellers. The micro half follows a firm. What does each extra unit cost? How much should a firm make when it has to take the market price, and when should it make nothing at all? What happens when new firms can move in, and what changes when there is only one seller, free to choose its own price, or even to charge different buyers different prices? Every answer comes from the same few numbers: total, average and marginal cost, set against the price or against marginal revenue.
The macro half adds money to Level 2's Keynesian cross. Investment falls when the interest rate rises, so the goods market no longer clears at one output but along a curve (IS); the demand for money gives a second curve (LM); and the economy sits where both markets clear, the solution of two linear equations. From there you will measure how much extra government spending is crowded out, let the price level move to get aggregate demand and supply, follow expectations as they catch up with prices, and see what changes when the interest rate cannot fall below zero.
The paths meet in specific places. Choosing the most profitable output from a table, or the best single price when demand has kinks, is the exhaustive and piecewise search of the Algorithms path, and the bisection of Levels 1 and 2 returns as a second way to solve the AD-AS model. "Marginal revenue equals marginal cost" is the rule the slope of profit is zero at the top, the same condition the Machine Learning path uses when it minimises a loss. And prices catching up with expectations period by period is a feedback loop of the Signals & Control path: each period closes part of the remaining gap.
Costs from a table
A bicycle repair workshop knows what a day costs at each output. costs[q] is the total cost C(q) of repairing q bikes in a day. costs[0] is the fixed cost F (rent, insurance), paid even on a day with no repairs; everything above it is the variable cost VC(q) = C(q) - C(0), which grows with output. Per unit:
- average cost AC(q) = C(q) / q, the cost per bike;
- average variable cost AVC(q) = VC(q) / q, the variable cost per bike;
- marginal cost MC(q) = C(q) - C(q - 1), what the
q-th bike adds to the total.
costs = [80, 110, 130, 143, 164, 195, 240, 300] # euros for q = 0, 1, ..., 7 bikes
F = costs[0]
print(" q C AC AVC MC")
for q in range(1, len(costs)):
ac = costs[q] / q
avc = (costs[q] - F) / q
mc = costs[q] - costs[q - 1]
print(f"{q:2} {costs[q]:4} {ac:6.2f} {avc:6.2f} {mc:4}")
q C AC AVC MC
1 110 110.00 30.00 30
2 130 65.00 25.00 20
3 143 47.67 21.00 13
4 164 41.00 21.00 21
5 195 39.00 23.00 31
6 240 40.00 26.67 45
7 300 42.86 31.43 60
Output 0 has no average (nothing to divide by), so the per-unit lists start at q = 1. The fixed cost makes the first bike's average cost large, 110, but it does not touch any marginal cost: it is paid whatever the output, so no single bike adds it. Average cost minus average variable cost is F / q, the fixed cost spread over more and more bikes.
Read the marginal and average columns together. While a bike adds less than the current average (the 4th adds 21 against an average of 47.67), the average falls; once it adds more (the 6th adds 45 against 39), the average rises. So the marginal cost curve cuts each average curve at that curve's lowest point: here average cost is lowest at 5 bikes, and average variable cost at 3 and 4 bikes, where the 4th bike's marginal cost, 21, equals the average variable cost exactly. Press Run to see the three curves:
costs = [80, 110, 130, 143, 164, 195, 240, 300]
qs = list(range(1, len(costs)))
plot(qs, [costs[q] / q for q in qs], label="AC", xlabel="bikes a day", ylabel="euros")
plot(qs, [(costs[q] - costs[0]) / q for q in qs], label="AVC")
plot(qs, [costs[q] - costs[q - 1] for q in qs], label="MC")
Average variable cost ties between 3 and 4 bikes. A problem that asks for "the output with the lowest value" must say which of a tie to report, and the code must follow it. To keep the smallest output, start with the first candidate and replace the best only on a strictly better value; <= would keep the last of a tie. When the values are floats computed along different routes, "equal" means equal within a stated tolerance.
costs = [80, 110, 130, 143, 164, 195, 240, 300]
avc = [(costs[q] - costs[0]) / q for q in range(1, len(costs))]
best = 1
for q in range(2, len(costs)):
if avc[q - 1] < avc[best - 1]: # strictly lower: the first of a tie stays
best = q
print(best, avc[best - 1])
3 21.0
Breaking even. When each unit sells for a fixed price and costs a fixed amount to make, every unit leaves a margin, price minus unit cost, towards the fixed cost. The break-even output is the fewest units whose margins cover it: the fixed cost divided by the margin, rounded up, since 227.3 talks cannot be held and 227 do not cover the hall. A lecture series rents a hall for 2500 euros; a ticket sells for 18 and each listener's coffee costs 7:
import math
fixed, price, unit_cost = 2500, 18, 7
margin = price - unit_cost
print(fixed / margin, math.ceil(fixed / margin), -(-fixed // margin))
print(227 * margin - fixed, 228 * margin - fixed)
227.27272727272728 228 228
-3 8
-(-a // b) rounds up using only whole numbers: // rounds down, and rounding down the negative is rounding up the positive. It stays exact for any size of number, while a / b goes through a float first and can be wrong once numbers pass about 10^{15}:
import math
a = 10 ** 17 + 1
print(math.ceil(a / 1), -(-a // 1))
100000000000000000 100000000000000001
If the margin is 0 or negative, no number of units ever breaks even. That option does not exist, and the honest answer is None, not a huge number or an error.
Common mistakes: dividing costs[0] by 0, or shifting the lists so that avc[0] belongs to zero output. Counting the fixed cost in the first unit's marginal cost. Rounding a break-even output down, or with round. Using <= when a tie should keep the first candidate.
Practice: The Pottery's Cost Sheet, Is the Festival Pitch Worth It?
The price taker's best output, and when to shut down
When many sellers offer the same good, none of them can charge more than the going price, and each can sell as much as it likes at that price. Such a firm is a price taker: the only thing it chooses is its output q, and its profit is
Making nothing is always one of the choices, and it is not worth 0: the fixed cost is already committed, so \pi(0) = -F. The repair workshop of the last section, at three going prices per repair:
costs = [80, 110, 130, 143, 164, 195, 240, 300]
for price in (45, 35, 18):
profits = [price * q - costs[q] for q in range(len(costs))]
print(price, profits)
45 [-80, -65, -40, -8, 16, 30, 30, 15]
35 [-80, -75, -60, -38, -24, -20, -30, -55]
18 [-80, -92, -94, -89, -92, -105, -132, -174]
At 45 euros a repair the best is a profit of 30, and two outputs reach it, 5 and 6 bikes: the 6th bike adds 45 of revenue and exactly 45 of cost. At 35 every output loses money, but repairing 5 bikes loses only 20, much less than the 80 lost by closing for the day: the workshop should open. At 18 every bike adds more cost than revenue, and closing (losing the rent, 80) is best.
That is the shutdown rule. The fixed cost is lost either way, so it cannot change the choice; what matters is whether the price covers the variable cost of some output. Opening beats closing exactly when P \cdot q - VC(q) > 0 for some q, that is, when the price is above the lowest average variable cost, the shutdown price. For this workshop it is 21 euros (from the table of the last section). Above the shutdown price the firm may still lose money (between 21 and the lowest average cost, 39, it does), but it loses less by producing.
Moving from q - 1 to q changes profit by P - MC(q), so a price taker keeps adding units while each one's marginal cost is below the price. When a problem asks for "the best output", search them all, including 0, and apply the stated tie rule:
costs = [80, 110, 130, 143, 164, 195, 240, 300]
price = 45
best_q, best = 0, -costs[0] # making nothing: lose the fixed cost
for q in range(1, len(costs)):
profit = price * q - costs[q]
if profit > best: # strictly better: a tie keeps the smaller output
best_q, best = q, profit
print(best_q, best)
5 30
Common mistakes: starting the best profit at 0, as if making nothing were free. Using average total cost for the shutdown price (that is the break-even price, which is higher). Letting the fixed cost decide whether to produce, once it is already paid. Using >=, which keeps the largest of tied outputs.
Practice: Strawberries at the Going Price
Smooth costs: slopes, parabolas and the supply curve
Many models write cost as a formula, with output any number q \ge 0. Then marginal cost is the slope of the cost curve: the extra cost of a tiny extra amount, divided by that amount. For powers of q the slope follows one rule: q^n has slope n \, q^{n-1}. So q has slope 1, q^2 has slope 2q, q^3 has slope 3q^2, and a constant (the fixed cost) has slope 0. A sum's slope is the sum of the slopes, and a number in front stays in front:
You can check any slope numerically, by computing the cost a tiny step further on:
def C(q):
return 50 + 20 * q - 4 * q ** 2 + 0.5 * q ** 3
def MC(q):
return 20 - 8 * q + 1.5 * q ** 2
step = 1e-6
for q in (1, 4, 6):
print(q, round((C(q + step) - C(q)) / step, 4), MC(q))
1 13.5 13.5
4 12.0 12.0
6 26.0 26.0
Average variable cost divides each term of the variable cost by q: AVC(q) = 20 - 4q + 0.5 q^2. Both AVC and MC are parabolas, a + b q + c q^2 with c > 0, U-shaped. A parabola is symmetric about its lowest point, and the lowest point is where its slope b + 2cq is zero:
For AVC that is q = 4/(2 \cdot 0.5) = 4, where AVC = 20 - 16 + 8 = 12; for MC it is q = 8/3, earlier. So this firm's shutdown price is 12.
To find the output a price taker chooses, solve P = MC(q). That is a quadratic equation, 1.5 q^2 - 8q + (20 - P) = 0, and A q^2 + B q + C = 0 has the roots
when B^2 - 4AC \ge 0 (otherwise none):
import math
def roots(A, B, C): # A q^2 + B q + C = 0, smaller root first
disc = B * B - 4 * A * C
if disc < 0:
return None
s = math.sqrt(disc)
return ((-B - s) / (2 * A), (-B + s) / (2 * A))
for P in (12, 18, 30):
print(P, [round(q, 4) for q in roots(1.5, -8, 20 - P)])
12 [1.3333, 4.0]
18 [0.263, 5.0704]
30 [-1.0452, 6.3785]
Two roots, and economics decides which one counts. At a price of 18 marginal cost equals the price at 0.263 and at 5.070. At the smaller root marginal cost is falling: the next units cost less than the price and less than the units before, so profit is at its lowest there, not its highest. The firm keeps going to the root on the rising part of the curve, the larger one. At 30 the smaller root is negative and cannot be an output at all.
So a price taker's supply curve is its marginal cost curve above the shutdown price, and 0 below it. At a price exactly equal to the shutdown price, here 12, the larger root is q = 4, the bottom of AVC: the firm just covers its variable cost there, and a problem must say whether it produces. With n identical firms the market supply at each price is n times one firm's output. Press Run to see one firm's supply curve, drawn as economists draw it (quantity across, price up), with its jump at the shutdown price:
import math
qs, ps = [], []
for i in range(0, 401):
P = i / 10
q = (8 + math.sqrt(64 - 6 * (20 - P))) / 3 if P >= 12 else 0
qs.append(q)
ps.append(P)
plot(qs, ps, label="one firm's supply", xlabel="output q", ylabel="price P")
Common mistakes: forgetting the factor n in the slope (q^3 has slope 3q^2, not q^2). Taking the smaller root of P = MC. Using the lowest point of MC as the shutdown price instead of the lowest point of AVC. Taking a square root of a negative discriminant.
Practice: A Hundred Identical Bakeries
The long run: firms come until profits vanish
In the short run the number of firms is fixed. In the long run firms can enter a market (if they expect to make money) or leave it, and a firm that stays out pays nothing. Entry adds supply and lowers the price, so it stops when one more firm would make a loss.
Take identical firms with cost C(q) = F + c q^2: marginal cost 2cq, so at price P each supplies q = P / (2c). Their average cost F/q + cq is the sum of a term that falls with q and one that rises. Their product, F c, does not depend on q, and two positive numbers with a fixed product have the smallest sum when they are equal: F / q = c q, so q = \sqrt{F / c} and
(The slope rule says the same: -F/q^2 + c = 0.) With F = 72 and c = 2:
import math
F, c = 72, 2
q_best = math.sqrt(F / c)
print(q_best, 2 * math.sqrt(F * c))
print(min(round(F / q + c * q, 6) for q in [i / 100 for i in range(1, 2001)]))
6.0 24.0
24.0
A search over a fine grid agrees: the lowest average cost is 24, at 6 units. Now let the market's buyers spend a fixed 2880 euros a day whatever the price, so they buy Q = 2880 / P. With n firms, the price clears the market when total supply equals demand, n \cdot P/4 = 2880 / P, so P = \sqrt{11520 / n}:
import math
F, c = 72, 2
for n in (1, 5, 10, 20, 21):
P = math.sqrt(11520 / n)
q = P / (2 * c)
profit = P * q - F - c * q * q
print(n, round(P, 4), round(q, 4), round(profit, 4))
1 107.3313 26.8328 1368.0
5 48.0 12.0 216.0
10 33.9411 8.4853 72.0
20 24.0 6.0 0.0
21 23.4216 5.8554 -3.4286
Each new firm lowers the price and every firm's profit. With 20 firms the price is exactly 24, the minimum average cost, and each firm breaks even; a 21st would push the price below 24 and lose money, so it stays away. That is the long-run result for a market of many small firms with free entry: the price falls to (just above) the bottom of the average cost curve, and profits to (nearly) zero. With whole numbers of firms the last entrant usually leaves a small profit, so a problem states its rule (here: a firm comes if it would make at least 0).
Common mistakes: counting the entrant that would lose money. Forgetting that demand at the new, lower price changes too. Using marginal cost instead of average cost as the long-run floor. Rounding a closed-form count of firms with int where a value meant to be whole can come out a hair below it; check each entrant's profit instead.
Practice: Room for One More Food Truck?
Monopoly: marginal revenue meets marginal cost
A monopoly is the only seller. It still cannot make buyers pay more than they want to; it faces the whole demand curve, and choosing a quantity means choosing the price at which that quantity sells. It is convenient to write demand the other way round, as the inverse demand curve: the direct form Q = m - kP (quantity at each price) becomes P = (m - Q)/k (price at each quantity). Its top, where Q = 0, is the choke price m / k, at and above which nobody buys.
A museum's daily visitors follow Q = 2000 - 50P, so P(Q) = 40 - 0.02 Q with a choke price of 40 euros. Each visitor costs the museum 8 euros (a constant marginal cost). Revenue is R(Q) = P(Q) \cdot Q = 40Q - 0.02Q^2, and by the slope rule the marginal revenue is
In general, for P = a - bQ, MR = a - 2bQ: it starts at the same height and falls twice as fast as demand. Selling one more ticket brings in its price but lowers the price of every ticket already sold. Profit rises while MR > MC and falls after, so the monopolist sells the quantity where
and charges the price read off the demand curve at that quantity:
a, b, c = 40, 0.02, 8
def profit(Q):
return (a - b * Q) * Q - c * Q
Q = (a - c) / (2 * b) # a - 2bQ = c
P = a - b * Q
print("Q =", Q, " P =", P, " profit =", profit(Q), " markup =", P - c)
print("search:", max(range(0, 2001), key=profit))
print("revenue of visitor 801:", round((a - b * 801) * 801 - (a - b * 800) * 800, 4))
Q = 800.0 P = 24.0 profit = 12800.0 markup = 16.0
search: 800
revenue of visitor 801: 7.98
The museum admits 800 visitors at 24 euros each. The 801st visitor would bring in only 7.98 of extra revenue (the slope, 8, to within the step) and costs 8. The price, 24, is far above the marginal cost of 8: the gap P - MC is the monopolist's markup. With a constant marginal cost c the price lands exactly halfway between the choke price and c, P = (a + c)/2, because Q = (a - c)/(2b) is half the quantity at which demand reaches c.
When marginal cost rises with output, MC = c + dQ (or c + 2dQ from a cost c Q + d Q^2), the rule is the same: write a - 2bQ = MC(Q) and collect the Q terms on one side. A fixed cost does not change the quantity (it has no slope), only the profit.
Common mistakes: setting price equal to marginal cost, which is what a price taker does. Using the demand curve a - bQ as marginal revenue. Reading the price off the MC or MR curve instead of demand. Mixing up the direct and the inverse form: in Q = m - kP the choke price is m/k, not m.
Practice: The Only Ferry to the Island
What monopoly costs: surplus and deadweight loss
Level 1 measured what a market is worth as areas: consumer surplus between the demand curve and the price, producer surplus between the price and the supply curve, and the deadweight loss of units worth more than they cost but never traded. The same areas compare a monopoly with competition on the same demand and cost curves.
Under competition the industry's supply curve is its marginal cost curve (as two sections back), so the market settles where demand meets marginal cost. Producer surplus is the area between the price and the marginal cost curve. When marginal cost rises from c as c + dQ, that area is a rectangle minus a triangle: the rectangle (P - c) \, Q between the price and the bottom of the cost line, minus the triangle under the price that the rising cost line cuts away, \tfrac12 \cdot Q \cdot dQ:
An industry with inverse demand P = 40 - 0.02Q and marginal cost MC = 4 + 0.04Q:
a, b, c, d = 40, 0.02, 4, 0.04
def surplus(Q):
P = a - b * Q
cs = 0.5 * (a - P) * Q
ps = (P - c) * Q - 0.5 * d * Q * Q
return P, round(cs, 4), round(ps, 4), round(cs + ps, 4)
Q_comp = (a - c) / (b + d) # demand = MC
Q_mono = (a - c) / (2 * b + d) # MR = MC
print("competition", round(Q_comp, 4), surplus(Q_comp))
print("monopoly ", round(Q_mono, 4), surplus(Q_mono))
competition 600.0 (28.0, 3600.0, 7200.0, 10800.0)
monopoly 450.0 (31.0, 2025.0, 8100.0, 10125.0)
The monopoly sells 450 instead of 600 at 31 instead of 28. Buyers lose 1575 of surplus; the owner gains 900; total surplus falls by 675. Most of the buyers' loss is a transfer: they pay 3 more on each of the 450 units they still buy, and that money is not lost, it moves to the owner. What is lost is the triangle between demand and marginal cost over the units no longer sold:
a, b, c, d = 40, 0.02, 4, 0.04
Q_comp, Q_mono = 600, 450
P_mono = a - b * Q_mono
print(0.5 * (P_mono - (c + d * Q_mono)) * (Q_comp - Q_mono))
675.0
Its height is the gap at Q_m between what the next unit is worth to a buyer (31) and what it would cost (22); its base is the 150 units not sold. Two ways to the same number make a good check.
Common mistakes: computing producer surplus as the rectangle (P - c)Q when marginal cost rises. Counting the transfer from buyers to the owner as part of the deadweight loss. Using the monopoly price for the competitive outcome.
Practice: One Owner for Every Quarry
Charging different prices
A monopolist that can tell its buyers apart may charge them differently: price discrimination. A swimming pool has two groups, adults with Q = 300 - 10P (choke price 30) and children with Q = 200 - 20P (choke price 10); each swim costs the pool 2.
A price per group (third-degree discrimination). Each group is its own small monopoly, so each gets its own monopoly price, halfway between its choke price and the marginal cost: P = (m/k + c)/2. A group whose choke price is at most c is not worth serving.
Every buyer pays the most they would pay (first-degree, or perfect, discrimination). Then every unit worth more than c is sold, and the seller takes the whole area between the demand line and the cost line: a triangle with height m/k - c and base m - kc.
groups = {"adults": (300, 10), "children": (200, 20)}
c = 2
group_total = perfect_total = 0
for name, (m, k) in groups.items():
choke = m / k
P = (choke + c) / 2
group_total += (P - c) * (m - k * P)
perfect_total += 0.5 * (choke - c) * (m - k * c)
print(name, "price", P, "swims", m - k * P)
print("profit with a price per group", group_total, " with perfect discrimination", perfect_total)
adults price 16.0 swims 140.0
children price 6.0 swims 80.0
profit with a price per group 2280.0 with perfect discrimination 4560.0
One price for everyone is harder, because the total demand has a kink. Above 10 euros children do not come, so total demand is the adults' line; below 10 it is the sum of both lines, 500 - 30P. A group never buys a negative amount, so each line is \max(0, m - kP), and the sum is a different straight line on each stretch between choke prices. On each stretch profit is a parabola in P, and its top is the monopoly price of that stretch's line, (M/K + c)/2 with M and K the sums of the riders' m and k. That top only counts if it lies inside its stretch; otherwise the best price on the stretch is at an end. So search piece by piece: collect each stretch's top (if inside) and the kinks, evaluate the true profit at each, keep the best.
groups = [(300, 10), (200, 20)]
c = 2
def profit(P):
return (P - c) * sum(max(0, m - k * P) for m, k in groups)
stretches = [(10, 30, 300, 10), (0, 10, 500, 30)] # (low, high, M, K) of the buyers on the stretch
candidates = [10, 30] # the kinks and the top
for low, high, M, K in stretches:
top = (M / K + c) / 2
print(f"stretch {low}..{high}: top at {round(top, 4)}", "inside" if low <= top <= high else "outside")
if low <= top <= high:
candidates.append(top)
for P in sorted(candidates):
print(round(P, 4), round(profit(P), 4))
stretch 10..30: top at 16.0 inside
stretch 0..10: top at 9.3333 inside
9.3333 1613.3333
10 1600
16.0 1960.0
30 0
Both tops are inside their stretches here, and the higher price wins: with one price the pool does best to price the children out and earn 1960. Charging per group earns 2280 (the extra 320 comes from the children), and perfect discrimination 4560. A brute-force check over a fine grid of prices agrees, and is worth running whenever you write a piecewise search:
groups, c = [(300, 10), (200, 20)], 2
def profit(P):
return (P - c) * sum(max(0, m - k * P) for m, k in groups)
print(max((round(profit(i / 1000), 6), i / 1000) for i in range(30001)))
(1960.0, 16.0)
When two candidate prices tie, a problem names the winner (say, the lowest price): sort the candidates and replace the best only on a profit better by more than a tiny tolerance.
Common mistakes: adding the groups' lines without max(0, ...), so a group buys a negative amount above its choke price. Taking the top of the all-groups parabola without checking that every group really buys at that price. Serving a group whose choke price is below the marginal cost.
Practice: Fares for the Cable Car
Production: returns to scale and the cheapest mix
Behind every cost table is a production function: how much output a firm gets from its inputs. With capital K (machines) and labour L (workers) the standard form is Cobb-Douglas, the shape you met as a utility function in Level 2:
Multiply both inputs by 2 and output is multiplied by 2^{\alpha} \cdot 2^{\beta} = 2^{\alpha + \beta}. So the sum of the exponents decides the returns to scale: increasing if \alpha + \beta > 1 (twice the inputs, more than twice the output), constant if it equals 1, decreasing if below. Comparing a float sum with 1 needs a tolerance:
print(0.7 + 0.2 + 0.1, 0.7 + 0.2 + 0.1 == 1, abs(0.7 + 0.2 + 0.1 - 1) <= 1e-9)
for alpha, beta in ((0.3, 0.6), (0.5, 0.5), (0.6, 0.7)):
print(alpha, beta, "doubling multiplies output by", round(2 ** (alpha + beta), 4))
0.9999999999999999 False True
0.3 0.6 doubling multiplies output by 1.8661
0.5 0.5 doubling multiplies output by 2.0
0.6 0.7 doubling multiplies output by 2.4623
The cheapest mix. Machines rent at r each and workers earn w. To reach an output target as cheaply as possible, use Level 2's rule for spending a budget, with inputs in place of goods: spend where the extra output per euro is highest, so at the best mix the two are equal, MP_K / r = MP_L / w. The marginal products of Cobb-Douglas are MP_K = \alpha Q / K and MP_L = \beta Q / L (as Level 2 found for utility), so \alpha / (rK) = \beta / (wL) and
Inputs that are cheap or productive are used more. A vineyard with Q = 4 K^{0.3} L^{0.6} (tractors and pickers), tractors at 60 a day and pickers at 15: the best ratio is (0.3/0.6)(15/60) = 1/8, one tractor for every eight pickers. With whole tractors and pickers the ratio can only be approximately right, and a search over all whole mixes that reach 100 units finds:
A, alpha, beta = 4, 0.3, 0.6
r, w, target = 60, 15, 100
best = None
for K in range(1, 101):
for L in range(1, 101):
if A * K ** alpha * L ** beta >= target - 1e-9: # reaches the target (with float slack)
key = (r * K + w * L, K) # cheapest; on a tie, fewer tractors
if best is None or key < best:
best = key + (L,)
cost, K, L = best
print("K =", K, " L =", L, " cost", cost, " K/L =", round(K / L, 4), " formula:", (alpha / beta) * (w / r))
K = 8 L = 76 cost 1620 K/L = 0.1053 formula: 0.125
The search is 100 × 100 checks; a smarter one notices that for a fixed number of tractors, the only sensible number of pickers is the fewest that reach the target (more pickers only cost more). Solving A K^\alpha L^\beta = \text{target} for L gives a starting point, and because a float formula rounded to a whole number can be off by one, step it down or up while the exact check says so. The - 1e-9 on the target absorbs rounding in the powers: an output that is exactly the target in real arithmetic may come out a hair below it in floats.
Common mistakes: comparing alpha + beta == 1 exactly. Inverting the ratio (K/L is \alpha w / (\beta r), so dearer labour means more machines per worker). Trusting a rounded formula without checking the neighbours. Breaking a cost tie the wrong way.
Practice: Ovens and Bakers
Natural monopoly and regulated prices
Some goods are cheapest with one supplier: a water network, a railway line, a power grid. Building a second set of pipes would double a huge fixed cost, while each extra cubic metre costs little. With fixed cost F and a constant cost c per unit, average cost F/Q + c falls for ever: this is a natural monopoly. Regulators then face a choice, and each rule is one price (and maybe a fee) put into the same formulas.
A town's 500 households together use Q = 5000 - 250P cubic metres a month (choke price 20); each costs 4 to deliver, and the network costs F = 9000 a month.
- Unregulated monopoly: MR = MC, the price halfway between 20 and 4, so 12.
- Marginal-cost pricing: P = c = 4. Every unit worth more than it costs is sold, the most total surplus there can be, but revenue covers only the running cost: the utility loses F, and taxpayers must pay a subsidy of F to keep it going.
- Average-cost pricing: the lowest price at which the utility breaks even, (P - c) \, Q(P) = F. That is a quadratic in P:
It has two roots; both break even, and the regulator wants the smaller one, the lower price. If the discriminant is negative, even the monopoly price does not cover F, and no single price breaks even.
- Two-part tariff: P = c plus a monthly fee of F / 500 per household. The fee covers the network, and the price per cubic metre stays efficient, as long as each household's surplus at P = c is at least the fee (otherwise households would leave).
Total surplus is consumer surplus plus profit. Fees and subsidies are transfers: a fee is paid by households and received by the utility, so it cancels in the total; a subsidy moves money from taxpayers to the utility and is not counted either. Only the price, through the quantity used, changes the total.
import math
N, c, F = 500, 4, 9000
def tariff(P, fee):
Q = max(0, 5000 - 250 * P)
profit = (P - c) * Q + N * fee - F
consumers = 0.5 * (20 - P) * Q - N * fee
total = consumers + profit
return round(P, 4), round(profit, 4) + 0.0, round(consumers, 4), round(total, 4) # + 0.0 turns -0.0 into 0.0
P_ac = (24 - math.sqrt(24 * 24 - 4 * 116)) / 2
print("monopoly ", tariff(12, 0))
print("average cost ", tariff(P_ac, 0))
print("marginal cost", tariff(4, 0))
print("two-part ", tariff(4, F / N), " household surplus at c:", 0.5 * (20 - 4) * 4000 / N)
monopoly (12, 7000.0, 8000.0, 15000.0)
average cost (6.7085, 0.0, 22083.0052, 22083.0052)
marginal cost (4, -9000.0, 32000.0, 23000.0)
two-part (4, 0.0, 23000.0, 23000.0) household surplus at c: 64.0
Marginal-cost pricing and the two-part tariff reach the same total surplus, 23000; one needs a subsidy of 9000, the other charges each household 18 a month, well below the 64 of surplus a household gets at that price. Average-cost pricing loses about 900 of surplus, the monopoly 8000.
Common mistakes: taking the larger root for average-cost pricing (it breaks even too, at a higher price). Counting a fee twice, or adding a subsidy to total surplus. Rejecting a two-part tariff whose fee exactly equals a household's surplus when the problem says that is enough. Forgetting that None is the answer when no price breaks even.
Practice: Four Tariffs for the Valley's Water
Investment and the IS curve
Now the whole economy again. Level 2's Keynesian cross took investment I as a fixed number. But firms borrow to build and to buy machines, and borrowing costs interest. The interest rate r is written as a fraction (5 % is 0.05), and planned investment falls as it rises:
i_0 is what firms would invest if borrowing were free, and i_1 says how much each unit of rate cuts it (with i_1 = 2000, one percentage point, r up by 0.01, cuts investment by 20). Some models add that firms never plan negative investment, I = \max(0, i_0 - i_1 r); others say there is "no floor on r or I", which means: use the equations as they stand, even where a number comes out negative.
At any fixed rate, investment is just a number and the goods market is the cross of Level 2, with its notation: Y = C + I + G, C = c_0 + c_1 (Y - T). Solving it at each rate gives the IS curve, the outputs at which the goods market clears, one for each rate. In the island economy of Marra:
c0, c1, T, i0, i1, G = 60, 0.8, 50, 150, 1000, 100
for r in (0, 0.03, 0.06, 0.09):
I = i0 - i1 * r
Y = (c0 - c1 * T + I + G) / (1 - c1)
print(r, round(I, 4), round(Y, 4))
0 150 1350.0
0.03 120.0 1200.0
0.06 90.0 1050.0
0.09 60.0 900.0
Each point of rate costs 10 of investment and, through the multiplier 1/(1 - c_1) = 5, 50 of output. So the IS curve slopes down: a higher rate goes with a lower output. Press Run to draw it the way economists do, output across and the rate up:
c0, c1, T, i0, i1, G = 60, 0.8, 50, 150, 1000, 100
rates = [i / 1000 for i in range(0, 121)]
plot([(c0 - c1 * T + i0 - i1 * r + G) / (1 - c1) for r in rates], rates, label="IS", xlabel="output Y", ylabel="interest rate r")
Anything that raises spending at a given rate (more G, a lower T, a higher c_0 or i_0) moves the whole curve to the right, by the multiplier times the change.
Common mistakes: writing 5 % as r = 5. Applying a floor to output instead of to investment. Subtracting the whole tax T instead of c_1 T.
Practice: Cheaper Loans, Busier Workshops
Money and the LM curve
The central bank issues the money supply M, a number of crowns. What a crown buys depends on the price level P, a price index as in Level 1 (at P = 2, goods cost twice what they cost in the base year). So what matters is the real money supply M / P: how many base-year goods the money could buy. M is nominal; M/P is real.
People hold money to pay for things, so they want more of it when output (and income) is higher. But money pays no interest, while a bond does: the higher the interest rate, the more it costs to hold money instead of bonds, and the less people hold. Real money demand is
The money market clears when M / P = L. If people want more money than there is, they sell bonds to get it, which pushes the rate up until they want less; so at each output the rate settles where M/P = kY - hr, that is r = (kY - M/P) / h. These pairs (output, rate) form the LM curve:
k, h, M = 0.4, 2500, 900
for P in (1.5, 2):
real = M / P
print("P =", P, " M/P =", real, " rates:", [round((k * Y - real) / h, 4) for Y in (1200, 1500, 1800, 2000)])
P = 1.5 M/P = 600.0 rates: [-0.048, 0.0, 0.048, 0.08]
P = 2 M/P = 450.0 rates: [0.012, 0.06, 0.108, 0.14]
The LM curve slopes up: more output means more money wanted from the same supply, so a higher rate. A higher price level shrinks M/P (from 600 to 450 here) and lifts the whole curve: each output now needs a higher rate. At low outputs the formula can give a negative rate, -0.048 at 1200; whether a model allows that is something it must state (the last section of this lesson adds a floor at zero).
Common mistakes: using the nominal M where the model needs M/P. Getting the sign backwards: (M/P - kY)/h makes the curve slope down. Clipping a negative rate to zero when the model says nothing about a floor.
Practice: The Price of Holding Cash
Two equations, two unknowns
The goods market allows many pairs (Y, r), and so does the money market. The economy sits at the one pair that clears both: the crossing of IS and LM. Each curve is a straight line, so the crossing solves two linear equations in two unknowns. Level 2 solved bigger systems by elimination; for two unknowns there are two quick methods. Take
Substitution: solve one equation for one unknown and put it into the other. The second gives x = 4y - 8; the first becomes 3(4y - 8) + 2y = 18, so 14y = 42, y = 3 and x = 4.
Cramer's rule: for a x + b y = e and c x + d y = f, with the determinant \det = ad - bc not zero,
Each numerator is the determinant with that unknown's column replaced by the right-hand sides. Whatever the method, put the answer back into both equations:
def solve2(a, b, e, c, d, f): # a x + b y = e, c x + d y = f
det = a * d - b * c
return (e * d - b * f) / det, (a * f - e * c) / det
x, y = solve2(3, 2, 18, 1, -4, -8)
print(x, y, 3 * x + 2 * y, x - 4 * y)
4.0 3.0 18.0 -8.0
To use this on IS-LM, write both markets with the unknowns Y and r on the left. The goods market Y = c_0 + c_1(Y - T) + i_0 - i_1 r + G becomes
where A is autonomous spending, everything that does not depend on Y or r. The money market is already linear: k \, Y - h \, r = M / P. The determinant is -\bigl(h(1 - c_1) + i_1 k\bigr), never zero when h > 0 and c_1 < 1: two lines of opposite slope always cross exactly once.
The economy of Tollan has a twist from Level 2's leakages section: it taxes a share t of income on top of a fixed T_0, T = T_0 + tY. Substituting into consumption, the coefficient of Y in its goods market becomes 1 - c_1(1 - t) and A = c_0 - c_1 T_0 + i_0 + G. Everything else is as above:
def solve2(a, b, e, c, d, f):
det = a * d - b * c
return (e * d - b * f) / det, (a * f - e * c) / det
c0, c1, T0, t, i0, i1, G = 100, 0.8, 50, 0.25, 360, 2400, 300
k, h, M, P = 0.5, 2000, 1625, 2.5
A = c0 - c1 * T0 + i0 + G
Y, r = solve2(1 - c1 * (1 - t), i1, A, k, -h, M / P)
I = i0 - i1 * r
C = c0 + c1 * (Y - (T0 + t * Y))
print("Y =", round(Y, 4), " r =", round(r, 4), " I =", round(I, 4))
print("goods: C + I + G =", round(C + I + G, 4), " money: kY - hr =", round(k * Y - h * r, 4), " M/P =", M / P)
Y = 1500.0 r = 0.05 I = 240.0
goods: C + I + G = 1500.0 money: kY - hr = 650.0 M/P = 650.0
Both checks pass: planned spending equals output, and money demand equals the real money supply. Press Run to see the crossing:
c0, c1, T0, t, i0, i1, G = 100, 0.8, 50, 0.25, 360, 2400, 300
k, h, M, P = 0.5, 2000, 1625, 2.5
A = c0 - c1 * T0 + i0 + G
ys = list(range(1000, 2001, 25))
plot(ys, [(A - (1 - c1 * (1 - t)) * y) / i1 for y in ys], label="IS", xlabel="output Y", ylabel="interest rate r")
plot(ys, [(k * y - M / P) / h for y in ys], label="LM")
Aside (optional): how economists view IS-LM today. IS-LM is a first model of how the goods market and the money market constrain each other, and it is still taught that way. Its critics note that most central banks today set an interest rate rather than a quantity of money, that the model has no explicit expectations about the future, and that its curves are not derived from the choices of households and firms; the models central banks use instead are dynamic, forward-looking ones, which often keep an IS-like relation but replace the LM curve with an interest-rate rule. Its defenders reply that its answers to many questions (how fiscal policy moves rates, why monetary policy loses power at a zero rate) match those richer models, and that its simplicity is the point. Problems here use it as stated.
Common mistakes: using M instead of M/P. Dropping -c_1 T from autonomous spending. A sign slip in Cramer's rule, which the substitution check catches at once.
Practice: Where Goods Meet Money
Comparative statics: crowding out
How does the equilibrium move when one number changes? As with Level 2's multiplier: solve twice and subtract. Tollan's government buys 50 more:
def solve2(a, b, e, c, d, f):
det = a * d - b * c
return (e * d - b * f) / det, (a * f - e * c) / det
c0, c1, T0, t, i0, i1 = 100, 0.8, 50, 0.25, 360, 2400
k, h, M, P = 0.5, 2000, 1625, 2.5
s = 1 - c1 * (1 - t) # Tollan's coefficient of Y in the goods market
def equilibrium(G):
return solve2(s, i1, c0 - c1 * T0 + i0 + G, k, -h, M / P)
Y0, r0 = equilibrium(300)
Y1, r1 = equilibrium(350)
print("IS-LM change: dY =", round(Y1 - Y0, 4), " dr =", round(r1 - r0, 4))
print("cross change (r fixed): dY =", round(50 / s, 4))
print("investment lost:", round(i1 * (r1 - r0), 4), " check:", round((50 / s - (Y1 - Y0)) * s, 4))
IS-LM change: dY = 50.0 dr = 0.0125
cross change (r fixed): dY = 125.0
investment lost: 30.0 check: 30.0
At a fixed rate, the cross change would be the full Keynesian multiplier, 50 / 0.4 = 125 (Tollan's leakages make it 1/(1 - c_1(1 - t))). In IS-LM output rises only 50. The extra output raises money demand; with the money supply unchanged the rate must rise (here by 0.0125, 1.25 points) to bring it back down; and the higher rate cuts investment by i_1 \Delta r = 30. Private investment is crowded out by the public spending. The check line shows the link: the 75 of output that the cross change had and IS-LM lacks is exactly the lost investment times the multiplier.
How much is crowded out depends on the slopes. If investment ignores the rate (i_1 = 0), nothing is crowded out and the cross multiplier holds. If money demand reacts strongly to the rate (large h), a small rate rise frees enough money and little is crowded out. If it hardly reacts (small h), the rate must rise a lot, and most of the spending is crowded out.
Common mistakes: reporting levels when the question asks for changes. Computing the cross change with the new rate: it holds the rate at its old value. Getting the sign of lost investment wrong: a higher rate means positive lost investment.
Practice: A New Bridge, Fewer New Warehouses
Holding the rate still
The money supply is not a law of nature: the central bank chooses it. Many central banks announce a target rate instead and supply whatever money makes the money market clear at that rate. Then the IS-LM system splits in two. With r fixed, investment is fixed, and the goods market alone gives output, the IS curve at that rate. The money market then only says how much money is needed: M/P = kY - hr, so M = P \, (kY - hr).
If Tollan's bank wants the rate at 0.04 instead of 0.05:
c0, c1, T0, t, i0, i1, G = 100, 0.8, 50, 0.25, 360, 2400, 300
k, h, P = 0.5, 2000, 2.5
s = 1 - c1 * (1 - t)
r = 0.04
Y = (c0 - c1 * T0 + i0 - i1 * r + G) / s # goods market at the target rate
real = k * Y - h * r # the real money supply it needs
print("Y =", round(Y, 4), " M/P =", round(real, 4), " M =", round(real * P, 4))
Y = 1560.0 M/P = 700.0 M = 1750.0
Output rises from 1500 to 1560, and the bank must raise the money supply from 1625 to 1750. A target that would need a money supply of zero or less cannot be reached this way.
The same split explains accommodation. In the last section, 50 more of G raised the rate and crowded out 30 of investment. If the bank adds just enough money to hold the rate where it was, nothing is crowded out and the purchases work with the full cross multiplier: output rises by 125. The money needed follows from the money market at the old rate, \Delta(M/P) = k \, \Delta Y = 62.5, so \Delta M = P \cdot 62.5 = 156.25. A treasury and a bank that want output to move by a given amount with the rate unchanged can therefore plan in two steps: the fiscal change from the cross multiplier, the money change from k \, \Delta Y. (With taxes as the tool, use the tax multiplier of Level 2, -c_1/(1 - c_1) in the plain model.)
Common mistakes: using the IS-LM fiscal effect, which assumes the rate rises, when the rate is held. Returning the real money supply instead of M = P \cdot (M/P). Forgetting that some plans need a negative G, T or M, which cannot happen.
Practice: The Bank Names Its Rate, More Output, Same Rate
Aggregate demand: output at every price level
So far the price level was fixed. Let it vary: for each P, solve IS-LM with the real money supply M/P and record the output. The result, output demanded as a function of the price level, is the aggregate demand (AD) curve. For Tollan:
def solve2(a, b, e, c, d, f):
det = a * d - b * c
return (e * d - b * f) / det, (a * f - e * c) / det
c0, c1, T0, t, i0, i1, G = 100, 0.8, 50, 0.25, 360, 2400, 300
k, h, M = 0.5, 2000, 1625
s, A = 1 - c1 * (1 - t), c0 - c1 * T0 + i0 + G
Y_far, _ = solve2(s, i1, A, k, -h, 0) # no real money at all: P without bound
for P in (1.5, 2, 2.5, 3, 5, 100):
Y, r = solve2(s, i1, A, k, -h, M / P)
print(P, round(Y, 4), round(r, 4), " (Y - Y_far) * P =", round((Y - Y_far) * P, 4))
print("Y_far =", round(Y_far, 4))
1.5 2020.0 -0.0367 (Y - Y_far) * P = 1950.0
2 1695.0 0.0175 (Y - Y_far) * P = 1950.0
2.5 1500.0 0.05 (Y - Y_far) * P = 1950.0
3 1370.0 0.0717 (Y - Y_far) * P = 1950.0
5 1110.0 0.115 (Y - Y_far) * P = 1950.0
100 739.5 0.1768 (Y - Y_far) * P = 1950.0
Y_far = 720.0
At P = 1.5 the rate comes out negative: this model has no floor on r, so the equations stand as they are. Why AD slopes down: a higher price level shrinks the real money supply; the money market then clears only at a higher rate; the higher rate cuts investment; and the multiplier turns that into lower output.
The last column reveals the shape. M/P appears only on the right-hand side of the system, and Cramer's rule makes the solution a linear function of the right-hand sides. So output is a constant plus a constant times M/P:
Here \alpha = 720 is the output with no real money at all (what demand approaches as prices grow without bound), and \beta = 1950 is the constant in the last column. You can get both from any two price levels, or from the letters by Cramer's rule. Turned around, the price level at which demand equals a given output Y is
which exists only for Y > \alpha: no positive price level makes Tollan demand 700. Press Run to draw the AD curve, output across and the price level up:
alpha, beta = 720, 1950 # Tollan's AD: Y = alpha + beta / P
prices = [1 + i / 20 for i in range(81)]
plot([alpha + beta / P for P in prices], prices, label="AD", xlabel="output Y", ylabel="price level P")
Common mistakes: holding the rate fixed while P changes: the money market must be solved again at each price level. Using the economy's current P instead of each price in the list. Inverting AD without checking that Y > \alpha.
Practice: Demand at Every Price Level
Aggregate supply and the short run
Firms set many prices in advance, based on the price level they expect, P_e. If demand then turns out strong, they produce more and raise prices somewhat. One simple model of this is the short-run aggregate supply (SRAS) line
Y_n is natural output, what the economy produces when prices turn out as expected; a \ge 0 says how strongly prices rise when output runs above it; and z is a supply shock, a jump in costs (a failed harvest, dearer fuel) that raises prices at every output (z > 0; a fall in costs is z < 0).
The short-run equilibrium is where AD and SRAS hold together. Put AD, Y = \alpha + \beta/P, into SRAS:
Multiply by P and collect terms, with b = P_e + z + a(\alpha - Y_n):
A quadratic, so two roots, and again economics picks one. The product of the two roots of P^2 + BP + C = 0 is C (multiply out (P - P_1)(P - P_2)), here -a\beta. With a > 0 and \beta > 0 that is negative, so one root is positive and one negative, and only the positive one is a price level:
Tollan with \alpha = 720, \beta = 1950, natural output 1500, expected prices 2.5 and a = 0.001; first without a shock, then with a shock of z = 0.25:
import math
alpha, beta = 720, 1950
Pe, a, Y_n = 2.5, 0.001, 1500
for z in (0, 0.25):
b = Pe + z + a * (alpha - Y_n)
P = (b + math.sqrt(b * b + 4 * a * beta)) / 2
other = (b - math.sqrt(b * b + 4 * a * beta)) / 2
Y = alpha + beta / P
print("z =", z, " P =", round(P, 4), " Y =", round(Y, 4), " other root", round(other, 4), " product", round(P * other, 4))
z = 0 P = 2.5 Y = 1500.0 other root -0.78 product -1.95
z = 0.25 P = 2.6939 Y = 1443.8666 other root -0.7239 product -1.95
Without a shock the economy sits at natural output and the expected price level. The shock raises prices, but by less than 0.25: higher prices shrink real money, demand falls, and lower output pulls part of the price rise back. Output falls and prices rise at the same time, the mark of a supply shock.
There is a second way that needs no algebra. AD falls as P rises and SRAS rises with Y, so the gap "SRAS price at the AD output, minus P" falls steadily in P and crosses zero once: bisection, as in Levels 1 and 2, traps it.
alpha, beta = 720, 1950
Pe, a, Y_n, z = 2.5, 0.001, 1500, 0.25
def gap(P):
Y = alpha + beta / P
return Pe + a * (Y - Y_n) + z - P
lo, hi = 0.01, 100.0 # gap(lo) > 0, gap(hi) < 0
while hi - lo > 1e-12:
mid = (lo + hi) / 2
if gap(mid) > 0:
lo = mid
else:
hi = mid
print(round(lo, 6), round(alpha + beta / lo, 4))
2.693867 1443.8666
Common mistakes: taking the negative root. Adding the shock to output instead of to prices. Holding the rate (or demand) fixed while the price level moves: AD already includes the money market's response.
Practice: When the Harvest Fails
Expectations catch up: the long run
The short run lasts as long as firms' expectations are wrong. A simple rule for how they learn is adaptive expectations: each period firms expect last period's price level,
Suppose Tollan's central bank raises the money supply from 1625 to 1950, by 20 %. AD moves out (\beta becomes 2400 \cdot 1950 / 2000 = 2340), but in period 0 firms still expect the old price level, 2.5. Each period solve the short-run equilibrium with that period's expectation, then hand its price level to the next period:
import math
alpha, beta = 720, 2340
a, Y_n = 0.001, 1500
def short_run(Pe):
b = Pe + a * (alpha - Y_n)
P = (b + math.sqrt(b * b + 4 * a * beta)) / 2
return alpha + beta / P, P
Pe = 2.5
for t in range(8):
Y, P = short_run(Pe)
print(t, round(Y, 4), round(P, 4), " gap", round(Y - Y_n, 4))
Pe = P # next period expects this period's price level
print("long run:", beta / (Y_n - alpha))
0 1614.8789 2.6149 gap 114.8789
1 1586.2912 2.7012 gap 86.2912
2 1565.716 2.7669 gap 65.716
3 1550.5441 2.8174 gap 50.5441
4 1539.1588 2.8566 gap 39.1588
5 1530.5039 2.8871 gap 30.5039
6 1523.8604 2.911 gap 23.8604
7 1518.723 2.9297 gap 18.723
long run: 3.0
Output jumps above natural output, then falls back as prices climb; the gap shrinks by roughly the same factor each period, the first-order convergence of Level 2's catch-up loop and of the Signals & Control path. In the long run expectations are right, P = P^e, so SRAS gives Y = Y_n, and the AD curve gives the price level: P = \beta / (Y_n - \alpha) = 3.0. The money rose by 20 %, and in the long run so does the price level (from 2.5 to 3), while output returns to where it was.
To stop "at the first period within a tolerance of natural output", use Level 2's rules for stopping: measure the distance |Y_t - Y_n|, not the change from last period; check period 0 before any update (it may already be close enough); and remember that "within tol" includes a distance exactly equal to tol.
Aside (optional): adaptive or rational expectations? Adaptive expectations make people repeat the same mistake for many periods: prices keep rising, and firms keep expecting last period's level. Economists in the rational-expectations tradition argue that people use what they know about the economy, so a money increase everyone sees coming would raise prices quickly and move output little. Others point to surveys in which expectations do adjust slowly, and to prices and wages fixed by contracts, as reasons why money can affect output for a while. Modern models often mix the two, and how fast expectations adjust in practice is still studied. Problems here state the rule to use.
Common mistakes: updating the expectation before solving period 0. Using this period's price as this period's expectation. Counting periods from 1. Returning the long-run values instead of the first period inside the tolerance.
Practice: Expectations Catch Up
When the rate cannot fall below zero
Nobody lends at a negative interest rate when holding money pays zero. So in many models the rate has a floor at 0:
The LM curve now has two pieces: flat at r = 0 for outputs up to M/(Pk), where money demand at a zero rate, kY, uses up the real money supply, and the usual rising line beyond. If the IS curve crosses the flat piece, the economy is in a liquidity trap: people hold more money than they need, as idle balances, and the rate stays at zero.
To solve: first solve IS-LM without the floor. If the rate comes out at 0 or above, that is the answer. If it is negative, the IS curve meets the flat piece instead: set r = 0 and take output from the goods market alone. Clipping only the rate and keeping the unconstrained output gives a pair that is not on the IS curve.
Tollan in a slump: firms invest less (i_0 = 160) and the real money supply is 700:
def solve2(a, b, e, c, d, f):
det = a * d - b * c
return (e * d - b * f) / det, (a * f - e * c) / det
c0, c1, T0, t, i0, i1 = 100, 0.8, 50, 0.25, 160, 2400
k, h, P = 0.5, 2000, 2.5
s = 1 - c1 * (1 - t)
def equilibrium(G, M):
A = c0 - c1 * T0 + i0 + G
Y, r = solve2(s, i1, A, k, -h, M / P)
if r < 0:
return round(A / s, 4), 0.0 # on the flat piece: r = 0, goods market alone
return round(Y, 4), round(r, 4)
print("now ", equilibrium(300, 1750))
print("money + 250 ", equilibrium(300, 2000))
print("G + 20 ", equilibrium(320, 1750))
print("G + 60 ", equilibrium(360, 1750))
print("edge of the trap at Y =", 1750 / (P * k))
now (1300.0, 0.0)
money + 250 (1300.0, 0.0)
G + 20 (1350.0, 0.0)
G + 60 (1420.0, 0.005)
edge of the trap at Y = 1400.0
In the trap, extra money does nothing: it joins the idle balances, and the rate cannot fall further to raise investment. Extra purchases work with the full cross multiplier (20 / 0.4 = 50), because there is no rate rise to crowd out investment. Once spending pushes output past the edge, 1400, the rate leaves zero and the usual IS-LM rules return: 60 more of G would give 150 at a fixed rate, but only 120 once the rate rises. The rise in G that brings output exactly to the edge makes the goods market clear at Y = 1400 with r = 0: here 0.4 \cdot 1400 - 520 = 40.
Common mistakes: clipping the rate to 0 but keeping the unconstrained output. Applying the floor in one case and forgetting it in the others. Expecting money to work in the trap the way it works outside it.
Practice: Stuck at Zero
Practice
These problems are required on this path at this level; the path adds one problem from each of the level's topics, picked for you and kept.
- The Pottery's Cost Sheet
- Strawberries at the Going Price
- One Owner for Every Quarry
- Where Goods Meet Money
- A New Bridge, Fewer New Warehouses
- Demand at Every Price Level
Checklist
You can now:
- Read fixed, variable, average and marginal cost off a table, find a break-even output by rounding up exactly, and apply a stated tie rule.
- Choose a price taker's most profitable output, including making nothing, and explain why a fixed cost already paid does not change the choice.
- Find marginal cost as a slope, the lowest point of a parabola, and the right root of a quadratic; build a supply curve from marginal cost above the shutdown price.
- Follow free entry to the long-run price at the bottom of average cost, 2\sqrt{Fc}.
- Solve a monopoly with MR = MC, read its price off demand, and measure the surplus it transfers and destroys.
- Price per group, find the best single price on a kinked demand curve piece by piece, and compute perfect discrimination.
- Classify returns to scale and find the cheapest input mix, K/L = (\alpha/\beta)(w/r).
- Compare monopoly, average-cost, marginal-cost and two-part pricing for a natural monopoly, treating fees and subsidies as transfers.
- Derive the IS and LM curves, solve IS-LM by substitution or Cramer's rule, check the answer in both markets, and measure crowding out and accommodation.
- Trace aggregate demand as \alpha + \beta/P, solve the short-run AD-AS equilibrium with the positive root or bisection, simulate adaptive expectations to the long run, and solve a model with a zero lower bound.