Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 7 additions & 17 deletions docs/tutorials/price_controls.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,10 @@ A binding price ceiling creates a shortage because quantity demanded exceeds qua
# Apply a binding price ceiling at $8
ceiling_market = Market(demand, supply, ceiling=8)

# Calculate shortage
q_demanded = demand.q(8)
q_supplied = supply.q(8)
shortage = q_demanded - q_supplied

print(f"With Price Ceiling at $8:")
print(f" Quantity Supplied: {q_supplied:.0f}")
print(f" Quantity Demanded: {q_demanded:.0f}")
print(f" Shortage: {shortage:.0f} units")
print(f" Quantity Supplied: {ceiling_market.quantity_supplied:.0f}")
print(f" Quantity Demanded: {ceiling_market.quantity_demanded:.0f}")
print(f" Shortage: {ceiling_market.shortage:.0f} units")
print(f" Deadweight Loss: ${ceiling_market.dwl:.2f}")

# Visualize the market with ceiling
Expand Down Expand Up @@ -99,15 +94,10 @@ A binding price floor creates a surplus because quantity supplied exceeds quanti
# Apply a binding price floor at $12
floor_market = Market(demand, supply, floor=12)

# Calculate surplus
q_demanded = demand.q(12)
q_supplied = supply.q(12)
surplus = q_supplied - q_demanded

print(f"With Price Floor at $12:")
print(f" Quantity Demanded: {q_demanded:.0f}")
print(f" Quantity Supplied: {q_supplied:.0f}")
print(f" Surplus: {surplus:.0f} units")
print(f" Quantity Demanded: {floor_market.quantity_demanded:.0f}")
print(f" Quantity Supplied: {floor_market.quantity_supplied:.0f}")
print(f" Surplus: {floor_market.surplus:.0f} units")
print(f" Deadweight Loss: ${floor_market.dwl:.2f}")

# Visualize the market with floor
Expand Down Expand Up @@ -150,4 +140,4 @@ Price controls only affect the market when they're binding:

Non-binding ceiling at $15: P = $10.00, Q = 10
Non-binding floor at $7: P = $10.00, Q = 10
Free market: P = $10.00, Q = 10
Free market: P = $10.00, Q = 10
24 changes: 24 additions & 0 deletions freeride/equilibrium.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,30 @@ def _valid_in_domain(self, dpiece, spiece, q_val):
def excess_demand(self, p):
return self.demand.q(p) - self.supply.q(p)

@property
def quantity_demanded(self):
return self.demand.q(self.__p_consumer)

@property
def quantity_supplied(self):
return self.supply.q(self.__p_producer)

@property
def shortage(self):
return max(self.quantity_demanded - self.quantity_supplied, 0)

@property
def surplus(self):
return max(self.quantity_supplied - self.quantity_demanded, 0)

@property
def excess_demand_quantity(self):
return self.shortage

@property
def excess_supply(self):
return self.surplus

# ================== Surplus ==================#
@property
def consumer_surplus(self):
Expand Down
46 changes: 41 additions & 5 deletions tests/test_equilibrium.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,55 @@ def test_equilibrium_price(self):
def test_equilibrium_quantity(self):
self.assertTrue(self.equilibrium.q == 8.0)

def test_free_market_has_no_market_gap(self):
self.assertAlmostEqual(self.equilibrium.quantity_demanded, 8.0)
self.assertAlmostEqual(self.equilibrium.quantity_supplied, 8.0)
self.assertAlmostEqual(self.equilibrium.shortage, 0.0)
self.assertAlmostEqual(self.equilibrium.surplus, 0.0)

def test_binding_ceiling_gap_properties(self):
ceiling_price = 5
eq_ceiling = Equilibrium(
self.demand_curve,
self.supply_curve,
ceiling=ceiling_price,
)
self.assertEqual(eq_ceiling.p, ceiling_price)
self.assertAlmostEqual(eq_ceiling.q, 6.0)
self.assertAlmostEqual(eq_ceiling.quantity_demanded, 10.0)
self.assertAlmostEqual(eq_ceiling.quantity_supplied, 6.0)
self.assertAlmostEqual(eq_ceiling.shortage, 4.0)
self.assertAlmostEqual(eq_ceiling.surplus, 0.0)
self.assertAlmostEqual(eq_ceiling.excess_demand_quantity, 4.0)

def test_binding_floor(self):
floor_price = 7
eq_floor = Equilibrium(self.demand_curve, self.supply_curve, floor=floor_price)
self.assertEqual(eq_floor.p, floor_price)
self.assertEqual(eq_floor.q, self.demand_curve.q(floor_price))
if hasattr(eq_floor, "excess_supply"):
expected_excess = self.supply_curve.q(floor_price) - self.demand_curve.q(floor_price)
self.assertEqual(eq_floor.excess_supply, expected_excess)
self.assertAlmostEqual(eq_floor.quantity_demanded, 6.0)
self.assertAlmostEqual(eq_floor.quantity_supplied, 10.0)
self.assertAlmostEqual(eq_floor.shortage, 0.0)
self.assertAlmostEqual(eq_floor.surplus, 4.0)
self.assertAlmostEqual(eq_floor.excess_supply, 4.0)

def test_nonbinding_floor(self):
floor_price = 5
eq_floor = Equilibrium(self.demand_curve, self.supply_curve, floor=floor_price)
self.assertEqual(eq_floor.p, self.equilibrium.p)
self.assertEqual(eq_floor.q, self.equilibrium.q)
if hasattr(eq_floor, "excess_supply"):
self.assertEqual(eq_floor.excess_supply, 0)
self.assertAlmostEqual(eq_floor.shortage, 0.0)
self.assertAlmostEqual(eq_floor.surplus, 0.0)
self.assertAlmostEqual(eq_floor.excess_supply, 0.0)

def test_nonbinding_ceiling_has_no_market_gap(self):
ceiling_price = 7
eq_ceiling = Equilibrium(
self.demand_curve,
self.supply_curve,
ceiling=ceiling_price,
)
self.assertEqual(eq_ceiling.p, self.equilibrium.p)
self.assertEqual(eq_ceiling.q, self.equilibrium.q)
self.assertAlmostEqual(eq_ceiling.shortage, 0.0)
self.assertAlmostEqual(eq_ceiling.surplus, 0.0)
Loading