Fares for the Cable Car

price discrimination · monopoly · kinked demand · piecewise optimisation · surplus

A mountain cable car is the only way up, and its riders come in groups (tourists, hikers, students...). Group i buys

Q_i = \max(0,\ m_i - k_i\,P)

tickets a day at a price of P dollars, so it buys nothing at or above its choke price m_i / k_i. Each rider costs the operator c dollars (constant marginal cost); there are no fixed costs. The operator compares three ways of pricing (tickets may be fractional and prices any non-negative number):

  1. One price for everyone. It chooses one price P for all groups, earning (P - c) \sum_i Q_i. If several prices tie for the highest profit (within 1e-9 relative: profits that differ by at most 1e-9 * max(1, best)), it picks the lowest. If no price earns a positive profit, the price is None and the profit 0.
  2. A price per group (it can check a student card). Each group gets the price that maximises the profit from that group alone. A group whose choke price is at most c is not served: its price is None and it adds nothing.
  3. Perfect discrimination. Every ticket goes for exactly the most its rider would pay, as long as that covers c. From group i this earns the area between its demand curve and the cost line: the triangle with height m_i/k_i - c and base m_i - k_i\,c (or nothing, if the choke price is at most c).

Write fares(groups, c) where groups is a list of pairs (m, k). Return a dict with the keys "uniform_price", "uniform_profit", "group_prices" (a list, one entry per group, in the given order), "group_profit" (the total over groups) and "perfect_profit".

Examples

Input:  groups = [(100, 2), (90, 3)], c = 10
Output: {'uniform_price': 24.0, 'uniform_profit': 980.0, 'group_prices': [30.0, 20.0],
         'group_profit': 1100.0, 'perfect_profit': 2200.0}
Explanation: at 24 both groups ride: 52 + 18 = 70 tickets at a margin of 14.

Input:  groups = [(120, 2), (60, 3)], c = 4
Output: {'uniform_price': 32.0, 'uniform_profit': 1568.0, 'group_prices': [32.0, 12.0],
         'group_profit': 1760.0, 'perfect_profit': 3520.0}
Explanation: with one price it pays to give up the second group (choke price 20) entirely.

Input:  groups = [(10, 1), (30, 15)], c = 0
Output: {'uniform_price': 1.25, 'uniform_profit': 25.0, 'group_prices': [5.0, 1.0],
         'group_profit': 40.0, 'perfect_profit': 80.0}
Explanation: 1.25 (both groups ride) and 5 (only the first) both earn 25; the lower price is returned.

Constraints

  • answers are compared with a tolerance of 1e-6

Goals

  • Price each group separately where its own marginal revenue meets marginal cost
  • Find the best single price when the total demand curve has kinks
  • Measure what perfect price discrimination would capture
Starting Python…