diff --git a/lectures/_static/quant-econ.bib b/lectures/_static/quant-econ.bib
index 9594beaee..1c082c164 100644
--- a/lectures/_static/quant-econ.bib
+++ b/lectures/_static/quant-econ.bib
@@ -5225,3 +5225,134 @@ @article{PhanEtAl2019
journal = {arXiv preprint arXiv:1912.11554},
year = {2019}
}
+
+@article{BergemannBonattiSmolin2018,
+ author = {Bergemann, Dirk and Bonatti, Alessandro and Smolin, Alex},
+ title = {The Design and Price of Information},
+ journal = {American Economic Review},
+ volume = {108},
+ number = {1},
+ pages = {1--48},
+ year = {2018},
+ doi = {10.1257/aer.20161079}
+}
+
+@article{AdmatiPfleiderer1986,
+ author = {Admati, Anat R. and Pfleiderer, Paul},
+ title = {A Monopolistic Market for Information},
+ journal = {Journal of Economic Theory},
+ volume = {39},
+ number = {2},
+ pages = {400--438},
+ year = {1986}
+}
+
+@article{Myerson1981,
+ author = {Myerson, Roger B.},
+ title = {Optimal Auction Design},
+ journal = {Mathematics of Operations Research},
+ volume = {6},
+ number = {1},
+ pages = {58--73},
+ year = {1981}
+}
+
+@article{RileyZeckhauser1983,
+ author = {Riley, John and Zeckhauser, Richard},
+ title = {Optimal Selling Strategies: When to Haggle, When to Hold Firm},
+ journal = {Quarterly Journal of Economics},
+ volume = {98},
+ number = {2},
+ pages = {267--289},
+ year = {1983}
+}
+
+@article{KamenicaGentzkow2011,
+ author = {Kamenica, Emir and Gentzkow, Matthew},
+ title = {Bayesian Persuasion},
+ journal = {American Economic Review},
+ volume = {101},
+ number = {6},
+ pages = {2590--2615},
+ year = {2011}
+}
+
+@article{Toikka2011,
+ author = {Toikka, Juuso},
+ title = {Ironing without Control},
+ journal = {Journal of Economic Theory},
+ volume = {146},
+ number = {6},
+ pages = {2510--2526},
+ year = {2011}
+}
+
+@article{BergemannBonatti2015,
+ author = {Bergemann, Dirk and Bonatti, Alessandro},
+ title = {Selling Cookies},
+ journal = {American Economic Journal: Microeconomics},
+ volume = {7},
+ number = {3},
+ pages = {259--294},
+ year = {2015}
+}
+
+@article{BergemannValimaki1997,
+ author = {Bergemann, Dirk and V{\"a}lim{\"a}ki, Juuso},
+ title = {Market Diffusion with Two-Sided Learning},
+ journal = {RAND Journal of Economics},
+ volume = {28},
+ number = {4},
+ pages = {773--795},
+ year = {1997}
+}
+
+@article{BergemannValimaki2000,
+ author = {Bergemann, Dirk and V{\"a}lim{\"a}ki, Juuso},
+ title = {Experimentation in Markets},
+ journal = {Review of Economic Studies},
+ volume = {67},
+ number = {2},
+ pages = {213--234},
+ year = {2000},
+ doi = {10.1111/1467-937X.00128}
+}
+
+@article{BoltonHarris1999,
+ author = {Bolton, Patrick and Harris, Christopher},
+ title = {Strategic Experimentation},
+ journal = {Econometrica},
+ volume = {67},
+ number = {2},
+ pages = {349--374},
+ year = {1999}
+}
+
+@article{Dutta1991,
+ author = {Dutta, Prajit K.},
+ title = {What Do Discounted Optima Converge To? A Theory of Discount Rate
+ Asymptotics in Economic Models},
+ journal = {Journal of Economic Theory},
+ volume = {55},
+ number = {1},
+ pages = {64--94},
+ year = {1991}
+}
+
+@book{LiptserShiryaev1977,
+ author = {Liptser, Robert S. and Shiryaev, Albert N.},
+ title = {Statistics of Random Processes I: General Theory},
+ publisher = {Springer-Verlag},
+ address = {New York},
+ year = {1977}
+}
+
+@article{ShakedSutton1982,
+ author = {Shaked, Avner and Sutton, John},
+ title = {Relaxing Price Competition Through Product Differentiation},
+ journal = {Review of Economic Studies},
+ volume = {49},
+ number = {1},
+ pages = {3--13},
+ year = {1982}
+}
diff --git a/lectures/_toc.yml b/lectures/_toc.yml
index dcd0a4545..25c1a17a0 100644
--- a/lectures/_toc.yml
+++ b/lectures/_toc.yml
@@ -48,6 +48,8 @@ parts:
- file: navy_captain
- file: merging_of_opinions
- file: survival_recursive_preferences
+ - file: pricing_information
+ - file: market_diffusion
- caption: Linear Programming
numbered: true
chapters:
diff --git a/lectures/market_diffusion.md b/lectures/market_diffusion.md
new file mode 100644
index 000000000..52de25d29
--- /dev/null
+++ b/lectures/market_diffusion.md
@@ -0,0 +1,1009 @@
+---
+jupytext:
+ text_representation:
+ extension: .md
+ format_name: myst
+ format_version: 0.13
+ jupytext_version: 1.16.7
+kernelspec:
+ display_name: Python 3 (ipykernel)
+ language: python
+ name: python3
+---
+
+(market_diffusion)=
+```{raw} jupyter
+
+```
+
+# Market Diffusion with Two-Sided Learning
+
+```{index} single: Information; strategic experimentation
+```
+
+```{index} single: Learning; two-sided
+```
+
+```{contents} Contents
+:depth: 2
+```
+
+## Overview
+
+In {doc}`pricing_information` a monopolist *owned* information and sold it.
+
+This lecture studies a market in which nobody sells information and everybody
+produces it.
+
+We follow {cite:t}`BergemannValimaki1997`, who study a duopoly in which an
+established firm competes on price with a firm selling a new product of unknown
+quality.
+
+Buyers learn what the new product is worth only by using it, and the aggregate
+record of their experience is public.
+
+So every purchase of the new product is simultaneously a consumption decision and an
+experiment, and its informational value spills over to everyone.
+
+Both sides of the market learn from the same public record, which is what "two-sided
+learning" means here: buyers and sellers hold identical beliefs at every date, and no
+asymmetric information ever arises.
+
+Three results organize the lecture.
+
+First, both firms *want* more information, but only the new firm's sales produce it.
+
+That asymmetry softens price competition: the established firm prices less
+aggressively than it would in a one-shot game, and the entrant captures a larger
+market share early on.
+
+Second, equilibrium experimentation is **excessive** when beliefs are pessimistic and
+**insufficient** when they are optimistic, with a single crossing in between.
+
+Third, the diffusion path of a successful new product is **S-shaped**, matching a
+long empirical tradition, and the inflection occurs at a belief we can pin down
+exactly.
+
+```{note}
+The connection to the rest of this section runs through the *value of information*.
+
+{doc}`blackwell_kihlstrom` shows that a decision maker benefits from a more
+informative experiment exactly when the value of the decision problem is convex in the
+belief, since a more informative experiment spreads the posterior in the convex order.
+
+Here beliefs are a martingale and experimentation controls how fast they spread, so
+each firm's gain from experimentation is governed by the convexity of its value
+function.
+
+The belief itself is driven by a log-likelihood-ratio process of the kind studied in
+{doc}`likelihood_ratio_process`, now run in continuous time.
+```
+
+Let's start with imports.
+
+```{code-cell} ipython3
+import matplotlib.pyplot as plt
+import numpy as np
+
+plt.rcParams['figure.figsize'] = (10, 5)
+np.set_printoptions(precision=4, suppress=True)
+```
+
+## The market
+
+Buyers are distributed uniformly on $[0, 1]$ and each demands one unit per instant.
+
+The established product delivers value
+
+$$
+s_n = s + n h
+$$ (eq:md_established)
+
+to buyer $n$, and the new product delivers
+
+$$
+\mu_n = \mu + (1 - n) h .
+$$ (eq:md_new)
+
+The parameter $h > 0$ measures horizontal differentiation, so buyers near $n = 0$ are
+naturally drawn to the new product and buyers near $n = 1$ to the established one.
+
+This is the standard Hotelling structure, with one twist: the vertical quality $\mu$
+of the new product is **unknown** and can take one of two values,
+
+$$
+\mu \in \{\mu_L, \mu_H\},
+\qquad
+0 < s - h < \mu_L < s < \mu_H < s + h .
+$$ (eq:md_condition4)
+
+The inner inequalities say the new product may be better or worse than the established
+one.
+
+The outer inequalities say that under full information both firms would retain a
+positive share of the market, so the innovation is not drastic.
+
+Marginal cost is zero for both firms.
+
+If the new firm serves the buyers in $[0, n]$, the average flow value delivered by each
+product is
+
+$$
+\bar\mu(n) = \mu + \frac{(2 - n)h}{2},
+\qquad
+\bar s(n) = s + \frac{(1 + n)h}{2} ,
+$$ (eq:md_averages)
+
+so total surplus per unit of time is $n \bar\mu(n) + (1-n)\bar s(n)$.
+
+Writing $\mu(\alpha)$ for the expected quality under belief $\alpha = \Pr[\mu = \mu_H]$,
+a little algebra puts the flow surplus in a convenient quadratic form,
+
+$$
+F(n, \alpha) = s + \frac h2 + n\bigl(\mu(\alpha) - s + h\bigr) - n^2 h .
+$$ (eq:md_flow)
+
+```{code-cell} ipython3
+class Market:
+ """The duopoly of Bergemann and Valimaki (1997)."""
+
+ def __init__(self, s=4.0, h=1.0, mu_L=3.1, mu_H=4.9, sigma=1.0):
+ self.s, self.h = s, h
+ self.mu_L, self.mu_H, self.sigma = mu_L, mu_H, sigma
+ assert 0 < s - h < mu_L < s < mu_H < s + h, 'condition (4) fails'
+
+ def mu(self, a):
+ """Expected quality of the new product under belief a."""
+ return (1 - a) * self.mu_L + a * self.mu_H
+
+ def flow_surplus(self, n, a):
+ return (self.s + self.h / 2 + n * (self.mu(a) - self.s + self.h)
+ - n ** 2 * self.h)
+```
+
+## Two-sided learning
+
+A buyer's individual experience is a noisy draw on $\mu$, and since each buyer has
+measure zero, only the *aggregate* record matters.
+
+When a fraction $n$ of buyers uses the new product, the cumulative market outcome
+$X$ evolves as
+
+$$
+dX = n \mu \, dt + \sigma \sqrt{n} \, dB ,
+$$ (eq:md_signal)
+
+so both the drift and the variance scale with the size of the experiment $n$.
+
+Everyone observes $X$, so beliefs stay common.
+
+Since $\mu$ takes only two values, the belief $\alpha_t = \Pr[\mu = \mu_H \mid \mathcal F_t]$
+is a sufficient statistic.
+
+```{prf:proposition} Posterior belief
+:label: md_prop_belief
+
+The belief $\alpha_t$ is a martingale with zero drift and instantaneous variance
+
+$$
+n \Sigma^2(\alpha) = n\left[\frac{\alpha(1-\alpha)(\mu_H - \mu_L)}{\sigma}\right]^2 .
+$$ (eq:md_variance)
+```
+
+This is the standard filtering result for a two-point prior observed through a
+diffusion; see {cite:t}`LiptserShiryaev1977`.
+
+Two features of {eq}`eq:md_variance` drive everything.
+
+The variance is **linear in $n$**, so information arrives in proportion to the size of
+the experiment, and only the new firm's sales generate it.
+
+The variance is proportional to $\alpha^2(1-\alpha)^2$, so learning is fastest when
+beliefs are most diffuse and grinds to a halt as $\alpha$ approaches $0$ or $1$.
+
+### Learning as a likelihood ratio process
+
+It is worth seeing where {eq}`eq:md_variance` comes from, because the mechanism is the
+one studied in {doc}`likelihood_ratio_process`, transplanted to continuous time.
+
+Over a short interval of length $\Delta$ the increment $\Delta X$ is normal with mean
+$n \mu \Delta$ and variance $\sigma^2 n \Delta$ under either hypothesis, so the
+increment to the **log likelihood ratio** is
+
+$$
+\Delta \ell
+= \log\frac{f_H(\Delta X)}{f_L(\Delta X)}
+= \frac{(\mu_H - \mu_L)\,\Delta X - \tfrac12 n \Delta (\mu_H^2 - \mu_L^2)}{\sigma^2} .
+$$ (eq:md_loglr)
+
+Beliefs then follow from Bayes' rule in its log-odds form, exactly as in the discrete
+time lectures,
+
+$$
+\log\frac{\alpha_{t+\Delta}}{1 - \alpha_{t+\Delta}}
+= \log\frac{\alpha_t}{1 - \alpha_t} + \Delta \ell .
+$$ (eq:md_logodds)
+
+We implement {eq}`eq:md_loglr` and {eq}`eq:md_logodds` directly, which gives an *exact*
+Bayesian update at each step rather than a discretization of a stochastic differential
+equation.
+
+```{code-cell} ipython3
+def simulate_beliefs(mkt, alpha0, T, dt, mu_true, rng, policy):
+ """Simulate beliefs by exact Bayesian updating of the log odds.
+
+ `mu_true` holds the true quality for each path, so the paths run in parallel.
+ Returns an array of shape (number of paths, number of steps + 1).
+ """
+ mu_true = np.atleast_1d(np.asarray(mu_true, dtype=float))
+ M, steps = len(mu_true), int(T / dt)
+ a = np.empty((M, steps + 1))
+ a[:, 0] = alpha0
+ ell = np.full(M, np.log(alpha0 / (1 - alpha0)))
+ dmu, half = mkt.mu_H - mkt.mu_L, (mkt.mu_H ** 2 - mkt.mu_L ** 2) / 2
+ for k in range(steps):
+ n = policy(a[:, k])
+ dX = n * mu_true * dt + mkt.sigma * np.sqrt(n * dt) * rng.standard_normal(M)
+ ell += (dmu * dX - n * dt * half) / mkt.sigma ** 2
+ a[:, k + 1] = 1 / (1 + np.exp(-ell))
+ return a
+```
+
+Before using it, we check {prf:ref}`md_prop_belief` by Monte Carlo.
+
+```{code-cell} ipython3
+def Sigma2(mkt, a):
+ return (a * (1 - a) * (mkt.mu_H - mkt.mu_L) / mkt.sigma) ** 2
+
+
+mkt = Market()
+rng = np.random.default_rng(0)
+dt, n_draw = 1e-4, 400_000
+
+print(f'{"alpha":>7s}{"simulated var/dt":>19s}{"formula n*Sigma^2":>20s}'
+ f'{"mean/dt (s.e.)":>22s}')
+for a0 in [0.2, 0.5, 0.8]:
+ n = 0.5 # hold the experiment size fixed
+ ell0 = np.log(a0 / (1 - a0))
+ steps = []
+ for mu_true, w in [(mkt.mu_H, a0), (mkt.mu_L, 1 - a0)]:
+ k = int(n_draw * w)
+ dX = n * mu_true * dt + mkt.sigma * np.sqrt(n * dt) * rng.standard_normal(k)
+ ell = ell0 + ((mkt.mu_H - mkt.mu_L) * dX
+ - n * dt * (mkt.mu_H ** 2 - mkt.mu_L ** 2) / 2) / mkt.sigma ** 2
+ steps.append(1 / (1 + np.exp(-ell)) - a0)
+ d = np.concatenate(steps)
+ se = d.std() / np.sqrt(len(d)) / dt
+ print(f'{a0:7.2f}{d.var() / dt:19.6f}{n * Sigma2(mkt, a0):20.6f}'
+ f'{d.mean() / dt:14.4f} ({se:.3f})')
+```
+
+The simulated variance matches {eq}`eq:md_variance`, and the mean increment is
+indistinguishable from zero, confirming that beliefs form a martingale.
+
+## Efficient experimentation
+
+A planner choosing $n(\alpha)$ trades current surplus against the information that
+sales generate.
+
+{cite:t}`BergemannValimaki1997` avoid the nonlinear differential equations that
+discounting would produce by working with the **undiscounted** limit, using the strong
+long-run average criterion of {cite:t}`Dutta1991`.
+
+The optimal policies in this limit are the limits of the discounted policies as the
+discount rate goes to zero, so the intertemporal tradeoff survives.
+
+The Bellman equation becomes
+
+$$
+\max_{n} \left\{ F(n, \alpha) - v(\alpha)
++ \tfrac12 n \Sigma^2(\alpha) V''(\alpha) \right\} = 0 ,
+$$ (eq:md_bellman)
+
+where $v(\alpha)$ is the long-run average attainable under full information and the
+last term is the **value of information**: the size of the experiment $n$ times the
+speed of learning $\Sigma^2$ times the shadow price $V''$.
+
+Because the belief is a martingale, no first-derivative term appears.
+
+Since $\mu$ is eventually learned, $v$ is just the linear interpolation of the two
+full-information values,
+
+$$
+v(\alpha) = \frac{s + \mu(\alpha) + \frac32 h}{2}
++ (1 - \alpha)\frac{(\mu_L - s)^2}{4h} + \alpha\frac{(\mu_H - s)^2}{4h} .
+$$ (eq:md_vsocial)
+
+The clever step is that the maximized bracket in {eq}`eq:md_bellman` equals zero, so we
+may divide through by $n$ without changing the maximizer.
+
+Doing so removes $V''$ from the first-order condition entirely and leaves
+
+$$
+\max_n \left\{ \frac{s + \frac h2 - v(\alpha)}{n} - h n \right\} + \text{terms free of } n ,
+$$
+
+whose first-order condition gives the efficient policy in closed form.
+
+```{prf:proposition} Efficient experimentation
+:label: md_prop_efficient
+
+The efficient market share of the new product is
+
+$$
+n^*(\alpha) = \sqrt{\frac{v(\alpha) - s - \frac h2}{h}} .
+$$ (eq:md_nstar)
+```
+
+The myopic planner, who ignores the informational value of sales, instead sets
+$m^*(\alpha) = \arg\max_n F(n,\alpha)$.
+
+```{code-cell} ipython3
+def v_social(mkt, a):
+ s, h = mkt.s, mkt.h
+ return ((s + mkt.mu(a) + 1.5 * h) / 2
+ + (1 - a) * (mkt.mu_L - s) ** 2 / (4 * h)
+ + a * (mkt.mu_H - s) ** 2 / (4 * h))
+
+
+def n_star(mkt, a):
+ """Efficient share, equation (nstar)."""
+ return np.sqrt((v_social(mkt, a) - mkt.s - mkt.h / 2) / mkt.h)
+
+
+def m_star(mkt, a):
+ """Myopically efficient share."""
+ return (mkt.mu(a) - mkt.s + mkt.h) / (2 * mkt.h)
+```
+
+At $\alpha \in \{0, 1\}$ there is nothing left to learn, so the two must agree, and
+they do.
+
+```{code-cell} ipython3
+for a, mu_i in [(0.0, mkt.mu_L), (1.0, mkt.mu_H)]:
+ direct = (mu_i - mkt.s + mkt.h) / (2 * mkt.h)
+ print(f'alpha = {a}: n* = {n_star(mkt, a):.6f} '
+ f'full-information share = {direct:.6f}')
+
+A = np.linspace(1e-6, 1 - 1e-6, 4001) # full grid, for plotting
+A_int = np.linspace(0.05, 0.95, 1801) # strictly interior grid
+
+gap_myopic = n_star(mkt, A_int) - m_star(mkt, A_int)
+print(f'\nn*(alpha) - m*(alpha) on [0.05, 0.95]: '
+ f'min {gap_myopic.min():.5f}, at alpha = 0.5 it is '
+ f'{float(n_star(mkt, 0.5) - m_star(mkt, 0.5)):.5f}')
+```
+
+The planner always experiments **more** than the myopic benchmark, which is the
+intertemporal value of information showing up as extra sales of the new product.
+
+## Equilibrium
+
+Now let the two firms set prices $p_1$ and $p_2$ and let buyers choose.
+
+The marginal buyer $n$ is indifferent when $s + nh - p_1 = \mu(\alpha) + (1-n)h - p_2$,
+which pins the market share to prices.
+
+Each firm solves a dynamic program in which its own value of information appears,
+and the same divide-by-$n$ trick removes the second derivatives from the first-order
+conditions.
+
+```{prf:proposition} Equilibrium
+:label: md_prop_equilibrium
+
+There is a unique Markov-perfect equilibrium, with
+
+$$
+p_1(\alpha) = \tfrac23\bigl(s - \mu(\alpha)\bigr) + \sqrt{2 h v_2(\alpha)},
+\qquad
+p_2(\alpha) = \tfrac13\bigl(\mu(\alpha) - s\bigr) + h ,
+$$ (eq:md_prices)
+
+and market share of the new firm
+
+$$
+n(\alpha) = \sqrt{\frac{v_2(\alpha)}{2h}} ,
+$$ (eq:md_share)
+
+where $v_i(\alpha)$ is firm $i$'s full-information long-run average revenue.
+```
+
+```{code-cell} ipython3
+def v1(mkt, a):
+ s, h = mkt.s, mkt.h
+ return ((1 - a) * ((s - mkt.mu_L) / 3 + h) ** 2 / (2 * h)
+ + a * ((s - mkt.mu_H) / 3 + h) ** 2 / (2 * h))
+
+
+def v2(mkt, a):
+ s, h = mkt.s, mkt.h
+ return ((1 - a) * ((mkt.mu_L - s) / 3 + h) ** 2 / (2 * h)
+ + a * ((mkt.mu_H - s) / 3 + h) ** 2 / (2 * h))
+
+
+def n_eq(mkt, a):
+ return np.sqrt(v2(mkt, a) / (2 * mkt.h))
+
+
+def p1(mkt, a):
+ return 2 / 3 * (mkt.s - mkt.mu(a)) + np.sqrt(2 * mkt.h * v2(mkt, a))
+
+
+def p2(mkt, a):
+ return (mkt.mu(a) - mkt.s) / 3 + mkt.h
+
+
+def p1_myopic(mkt, a):
+ return (mkt.s - mkt.mu(a)) / 3 + mkt.h
+
+
+def n_myopic(mkt, a):
+ return ((mkt.mu(a) - mkt.s) / 3 + mkt.h) / (2 * mkt.h)
+```
+
+Comparing the dynamic equilibrium with the static one played period by period reveals
+the asymmetry at the heart of the paper.
+
+```{code-cell} ipython3
+print('comparing the dynamic equilibrium with the static one, on [0.05, 0.95]')
+print(f' max |p2 - p2_myopic| {np.abs(p2(mkt, A_int) - p2(mkt, A_int)).max():.2e}')
+print(f' min (p1 - p1_myopic) {(p1(mkt, A_int) - p1_myopic(mkt, A_int)).min():.5f}')
+print(f' min (n_eq - n_myopic) {(n_eq(mkt, A_int) - n_myopic(mkt, A_int)).min():.5f}')
+```
+
+The new firm's price is *exactly* its myopic price, a knife-edge consequence of the
+linear preference structure and the absence of discounting.
+
+The established firm charges *more* than it would in a one-shot game, and so concedes
+market share.
+
+That is the striking result: the incumbent softens competition, not out of weakness,
+but because the entrant's sales are the only source of information and the incumbent
+wants the information.
+
+### Who values information more?
+
+The Bellman equations imply that each firm's value of information equals the gap
+between its expected full-information revenue and its current revenue.
+
+```{code-cell} ipython3
+voi_1 = v1(mkt, A) - (1 - n_eq(mkt, A)) * p1(mkt, A)
+voi_2 = v2(mkt, A) - n_eq(mkt, A) * p2(mkt, A)
+
+print(f'established firm, minimum value of information {voi_1.min():.3e}')
+print(f'new firm, minimum value of information {voi_2.min():.3e}')
+print(f'ratio voi_1 / voi_2: min {np.min(voi_1 / voi_2):.6f}, '
+ f'max {np.max(voi_1 / voi_2):.6f}')
+```
+
+Both are positive, so both value functions are convex in the belief.
+
+That is the {doc}`blackwell_kihlstrom` logic at work: beliefs are a martingale, more
+experimentation spreads them further, and a firm with a convex value function gains
+from the spread.
+
+More surprisingly, the ratio is exactly $2$ at every belief.
+
+The **established** firm values information twice as much as the entrant, because in
+equilibrium it is the incumbent that has given up current revenue relative to what it
+would earn once uncertainty is resolved.
+
+## Too much experimentation, then too little
+
+We can now compare the equilibrium share with the efficient one.
+
+```{code-cell} ipython3
+---
+mystnb:
+ figure:
+ caption: Equilibrium versus efficient experimentation
+ name: fig-md-efficiency
+---
+gap = n_star(mkt, A) - n_eq(mkt, A)
+cross = A[np.argmin(np.abs(gap))]
+
+fig, axes = plt.subplots(1, 2, figsize=(12, 4.2))
+axes[0].plot(A, n_star(mkt, A), lw=2, label=r'efficient $n^*(\alpha)$')
+axes[0].plot(A, n_eq(mkt, A), lw=2, label=r'equilibrium $n(\alpha)$')
+axes[0].plot(A, m_star(mkt, A), lw=1.5, ls='--', color='0.5',
+ label=r'myopic planner $m^*(\alpha)$')
+axes[0].set(xlabel=r'$\alpha$', ylabel='market share of the new firm',
+ title='experimentation policies')
+axes[0].legend(fontsize=9)
+
+axes[1].plot(A, gap, lw=2, color='C3')
+axes[1].axhline(0, color='0.3', lw=1)
+axes[1].axvline(cross, color='0.6', ls=':', lw=1.5)
+axes[1].fill_between(A, gap, 0, where=gap < 0, alpha=0.15, color='C3')
+axes[1].fill_between(A, gap, 0, where=gap > 0, alpha=0.15, color='C0')
+axes[1].annotate('equilibrium\nexperiments too much', (0.05, gap.min() / 2),
+ fontsize=9)
+axes[1].annotate('too little', (0.75, gap.max() / 2), fontsize=9)
+axes[1].set(xlabel=r'$\alpha$', ylabel=r'$n^*(\alpha) - n(\alpha)$',
+ title=f'single crossing at ' + rf'$\alpha = {cross:.3f}$')
+fig.tight_layout()
+plt.show()
+
+print(f'gap is monotone increasing: {np.all(np.diff(gap) > 0)}')
+print(f'number of sign changes: {int(np.sum(np.diff(np.sign(gap)) != 0))}')
+```
+
+The intuition is about who has to cut price to gain a buyer.
+
+At pessimistic beliefs the entrant is small, so attracting one more buyer costs it
+little in inframarginal revenue, while the incumbent is large and unwilling to defend
+its share by cutting price on everyone.
+
+The entrant therefore expands aggressively and the market over-experiments.
+
+At optimistic beliefs the positions are reversed, the incumbent fights harder, and
+experimentation falls short of the efficient level.
+
+## Diffusion over time
+
+So far everything is a function of the state $\alpha$.
+
+To follow a product over calendar time we need the law of motion of the belief when the
+product really is good.
+
+Conditional on $\mu = \mu_H$, the belief acquires an upward drift, since the data are
+generated by $\mu_H$ while the market still puts weight $1 - \alpha$ on $\mu_L$,
+
+$$
+d\alpha = \frac{n(\alpha)(\mu_H - \mu_L)^2 \alpha (1-\alpha)^2}{\sigma^2}\, dt
++ \frac{(\mu_H - \mu_L)\alpha(1-\alpha)\sqrt{n(\alpha)}}{\sigma}\, dB .
+$$ (eq:md_conditional)
+
+Stripping out the noise gives a deterministic path for the mean belief.
+
+```{code-cell} ipython3
+def mean_belief_path(mkt, alpha0, T, dt, policy):
+ """Deterministic path of the mean posterior when mu = mu_H."""
+ steps = int(T / dt)
+ a = np.empty(steps + 1)
+ a[0] = alpha0
+ dmu2 = (mkt.mu_H - mkt.mu_L) ** 2 / mkt.sigma ** 2
+ for k in range(steps):
+ drift = policy(a[k]) * dmu2 * a[k] * (1 - a[k]) ** 2
+ a[k + 1] = min(max(a[k] + drift * dt, 1e-12), 1 - 1e-12)
+ return a
+```
+
+```{prf:proposition} S-shaped diffusion
+:label: md_prop_sshape
+
+Conditional on the product being good, the mean market share $\hat n(t)$ is increasing
+over time.
+
+Its rate of increase is itself increasing while $\hat\alpha(t) \leq 1/3$ and
+decreasing thereafter.
+```
+
+The composition of two forces produces the S.
+
+Learning accelerates as beliefs move away from zero, which speeds up the growth of the
+entrant's share; but the equilibrium share $n(\alpha)$ is concave, so further belief
+improvements translate into ever smaller share gains.
+
+```{code-cell} ipython3
+---
+mystnb:
+ figure:
+ caption: The S-shaped diffusion path of a successful new product
+ name: fig-md-diffusion
+---
+T, dt, alpha0 = 8.0, 1e-3, 0.03
+policy = lambda a: n_eq(mkt, a)
+
+a_mean = mean_belief_path(mkt, alpha0, T, dt, policy)
+t_grid = np.linspace(0, T, len(a_mean))
+
+rng = np.random.default_rng(12)
+paths = simulate_beliefs(mkt, alpha0, T, dt, np.full(6, mkt.mu_H), rng, policy)
+
+fig, axes = plt.subplots(1, 2, figsize=(12, 4.2))
+for pth in paths:
+ axes[0].plot(t_grid, pth, lw=0.7, alpha=0.55, color='C0')
+axes[0].plot(t_grid, a_mean, lw=2.5, color='C3', label='mean path')
+axes[0].axhline(1 / 3, color='0.5', ls=':', lw=1.5)
+axes[0].set(xlabel='time', ylabel=r'$\alpha(t)$', title='beliefs')
+axes[0].legend(fontsize=9)
+
+for pth in paths:
+ axes[1].plot(t_grid, n_eq(mkt, pth), lw=0.7, alpha=0.55, color='C0')
+axes[1].plot(t_grid, n_eq(mkt, a_mean), lw=2.5, color='C3', label='mean path')
+axes[1].set(xlabel='time', ylabel=r'$n(t)$',
+ title='market share of the new firm')
+axes[1].legend(fontsize=9)
+fig.tight_layout()
+plt.show()
+```
+
+The inflection point is exactly where {prf:ref}`md_prop_sshape` says it is.
+
+```{code-cell} ipython3
+n_mean = n_eq(mkt, a_mean)
+growth = np.gradient(n_mean, t_grid)
+k = np.argmax(growth)
+print(f'share grows fastest at t = {t_grid[k]:.3f}, '
+ f'where alpha = {a_mean[k]:.4f} (theory: 1/3)')
+
+drift = policy(A) * (mkt.mu_H - mkt.mu_L) ** 2 * A * (1 - A) ** 2
+print(f'belief drift peaks at alpha = {A[np.argmax(drift)]:.4f} '
+ f'(theory: between 1/3 and 2/3)')
+```
+
+Prices move in step with shares.
+
+```{code-cell} ipython3
+---
+mystnb:
+ figure:
+ caption: Price paths of the two firms
+ name: fig-md-prices
+---
+fig, ax = plt.subplots()
+for pth in paths:
+ ax.plot(t_grid, p1(mkt, pth), lw=0.7, alpha=0.5, color='C0')
+ ax.plot(t_grid, p2(mkt, pth), lw=0.7, alpha=0.5, color='C1')
+ax.plot(t_grid, p1(mkt, a_mean), lw=2.5, color='C0',
+ label=r'$p_1$, established firm')
+ax.plot(t_grid, p2(mkt, a_mean), lw=2.5, color='C1', label=r'$p_2$, new firm')
+ax.set(xlabel='time', ylabel='price',
+ title='the incumbent retreats as the entrant is vindicated')
+ax.legend()
+fig.tight_layout()
+plt.show()
+```
+
+## Martingale properties
+
+{cite:t}`BergemannValimaki1997` characterize the equilibrium objects probabilistically:
+the entrant's price is a martingale, the incumbent's price and the entrant's share are
+supermartingales, and both revenues are submartingales.
+
+Because $\alpha$ is a martingale, each of these follows from the shape of the
+corresponding function of $\alpha$, and we can check them all by simulation.
+
+```{code-cell} ipython3
+rng = np.random.default_rng(3)
+a0, M = 0.5, 20_000
+
+# draw the true quality from the prior, one value per path
+mu_true = np.where(rng.random(M) < a0, mkt.mu_H, mkt.mu_L)
+ends = simulate_beliefs(mkt, a0, 4.0, 2e-3, mu_true, rng, policy)[:, -1]
+
+rows = [
+ ('belief', a0, ends.mean(), 'martingale'),
+ ('share of new firm', n_eq(mkt, a0), n_eq(mkt, ends).mean(), 'supermartingale'),
+ ('price of new firm', p2(mkt, a0), p2(mkt, ends).mean(), 'martingale'),
+ ('price of incumbent', p1(mkt, a0), p1(mkt, ends).mean(), 'supermartingale'),
+ ('revenue of incumbent', (1 - n_eq(mkt, a0)) * p1(mkt, a0),
+ ((1 - n_eq(mkt, ends)) * p1(mkt, ends)).mean(), 'submartingale'),
+ ('revenue of new firm', n_eq(mkt, a0) * p2(mkt, a0),
+ (n_eq(mkt, ends) * p2(mkt, ends)).mean(), 'submartingale')]
+
+print(f'{"":24s}{"t = 0":>10s}{"E[t = 4]":>11s}{"change":>10s} prediction')
+for name, x0, xT, pred in rows:
+ print(f'{name:24s}{x0:10.4f}{xT:11.4f}{xT - x0:+10.4f} {pred}')
+```
+
+Every sign comes out as predicted.
+
+The entrant's expected share *falls* over time even though its share rises conditional
+on the product being good, because the early aggression reflects the value of
+information rather than confidence in the product.
+
+Both firms expect to earn more later, which is the sense in which they sacrifice
+current profit to buy information.
+
+## Concluding remarks
+
+Two lectures in this section now feature information whose value is entirely
+instrumental.
+
+In {doc}`pricing_information` a seller designs and prices experiments, and the
+interesting economics comes from the fact that Blackwell's order is incomplete.
+
+Here nobody prices information at all, and the interesting economics comes from the
+fact that only one firm's sales produce it.
+
+Both rest on the same foundation from {doc}`blackwell_kihlstrom`: information is
+valuable to a decision maker exactly to the extent that the value of the decision
+problem is convex in the belief.
+
+The distinctive lesson of {cite:t}`BergemannValimaki1997` is that this convexity is
+shared by *competitors*.
+
+Because both firms would rather face a market that has sorted out the quality of the
+new product, uncertainty about vertical quality relaxes price competition much as
+deterministic differentiation does in {cite:t}`ShakedSutton1982`.
+
+That is why the incumbent lets the entrant in cheaply at first and why a successful
+product diffuses along an S-shaped path.
+
+The continuous-time technique used here, and in particular the device of taking the
+undiscounted limit to keep the Bellman equations tractable, comes from
+{cite:t}`BoltonHarris1999`, who were the first to study strategic experimentation in
+continuous time.
+
+A companion paper, {cite:t}`BergemannValimaki2000`, studies the same duopoly with a
+continuum of *identical* consumers.
+
+Homogeneity there rules out market sharing, so the horizontal differentiation that
+generates the diffusion path in this lecture is absent and the analysis concentrates
+instead on how informational externalities affect market efficiency.
+
+## Exercises
+
+```{exercise-start}
+:label: md_ex1
+```
+
+Condition {eq}`eq:md_condition4` requires $|\mu_i - s| < h$ for both quality levels.
+
+1. Show algebraically that this confines the full-information equilibrium share of the
+ new firm to the interval $(1/3, 2/3)$, and hence that $n(\alpha) \in (1/3, 2/3)$ for
+ every belief.
+
+2. Verify this numerically for several admissible $(\mu_L, \mu_H)$ pairs.
+
+3. {cite:t}`BergemannValimaki1997` draw their diffusion figures with $s = 4$, $h = 1$,
+ $\mu_L = 2$ and $\mu_H = 6$.
+
+ Check whether these satisfy {eq}`eq:md_condition4`, compute the equilibrium shares
+ at $\alpha \in \{0, 1\}$, and compute the myopically efficient share $m^*$ at each
+ quality level.
+
+ What goes wrong, and which of the lecture's results still hold?
+
+```{exercise-end}
+```
+
+```{solution-start} md_ex1
+:class: dropdown
+```
+
+Here is one solution:
+
+Under full information with quality $\mu_i$ the equilibrium share is
+$n_i = \bigl(\tfrac13(\mu_i - s) + h\bigr)/(2h)$.
+
+Condition {eq}`eq:md_condition4` gives $-h < \mu_i - s < h$, so
+$\tfrac13(\mu_i - s) \in (-h/3, h/3)$ and therefore
+$n_i \in \bigl(\tfrac{2h/3}{2h}, \tfrac{4h/3}{2h}\bigr) = (1/3, 2/3)$.
+
+Since $n(\alpha)^2$ is a convex combination of $n_0^2$ and $n_1^2$, the equilibrium
+share lies between $n_0$ and $n_1$ for every $\alpha$.
+
+```{code-cell} ipython3
+for mu_L, mu_H in [(3.1, 4.9), (3.4, 4.6), (3.9, 4.1)]:
+ m_ = Market(mu_L=mu_L, mu_H=mu_H)
+ lo, hi = n_eq(m_, 0.0), n_eq(m_, 1.0)
+ print(f'(mu_L, mu_H) = ({mu_L}, {mu_H}): n_eq ranges over '
+ f'[{lo:.4f}, {hi:.4f}] inside (1/3, 2/3): {1/3 < lo and hi < 2/3}')
+```
+
+```{code-cell} ipython3
+class LooseMarket(Market):
+ def __init__(self, **kw): # skip the assertion
+ self.s, self.h = kw['s'], kw['h']
+ self.mu_L, self.mu_H, self.sigma = kw['mu_L'], kw['mu_H'], kw.get('sigma', 1.0)
+
+
+paper = LooseMarket(s=4, h=1, mu_L=2, mu_H=6)
+print(f'condition (4) needs s - h < mu_L: {paper.s - paper.h} < {paper.mu_L}? '
+ f'{paper.s - paper.h < paper.mu_L}')
+print(f'condition (4) needs mu_H < s + h: {paper.mu_H} < {paper.s + paper.h}? '
+ f'{paper.mu_H < paper.s + paper.h}')
+print(f'\nequilibrium shares: n(0) = {n_eq(paper, 0.0):.4f}, '
+ f'n(1) = {n_eq(paper, 1.0):.4f}')
+for mu_i, nm in [(paper.mu_L, 'mu_L'), (paper.mu_H, 'mu_H')]:
+ print(f'myopically efficient share at {nm}: '
+ f'{(mu_i - paper.s + paper.h) / (2 * paper.h):+.4f}')
+```
+
+The paper's figure parameters violate {eq}`eq:md_condition4` at both ends.
+
+The consequence is that the *efficient* allocation is at a corner: it would assign every
+buyer to the established product when $\mu = \mu_L$ and every buyer to the new product
+when $\mu = \mu_H$, so the interior formula {eq}`eq:md_nstar` no longer applies and the
+efficiency comparison of {prf:ref}`md_prop_efficient` breaks down.
+
+Everything about the *equilibrium* survives, because equilibrium shares remain strictly
+interior at $1/6$ and $5/6$.
+
+That is why those parameters are fine for drawing diffusion paths, which is all the
+paper uses them for, and why they buy a much more dramatic S-curve than any admissible
+parameter set could.
+
+```{solution-end}
+```
+
+```{exercise-start}
+:label: md_ex2
+```
+
+The lecture found a single belief at which equilibrium experimentation switches from
+excessive to insufficient.
+
+1. Write a function that locates this crossing point by bisection.
+
+2. Compute it as the quality spread $\mu_H - \mu_L$ widens, holding the midpoint
+ $\tfrac12(\mu_L + \mu_H) = s$ fixed, and again as the horizontal differentiation
+ parameter $h$ varies.
+
+3. Both experiments produce the same numbers whenever the ratio
+ $(\mu_H - \mu_L)/h$ agrees.
+
+ Guess the closed form for the crossing point and check it numerically.
+
+4. Does your formula survive when the quality midpoint is moved away from $s$?
+
+```{exercise-end}
+```
+
+```{solution-start} md_ex2
+:class: dropdown
+```
+
+Here is one solution:
+
+```{code-cell} ipython3
+def crossing(mkt, tol=1e-13):
+ """Belief at which n*(alpha) = n(alpha), by bisection."""
+ lo, hi = 1e-12, 1 - 1e-12
+ f = lambda a: n_star(mkt, a) - n_eq(mkt, a)
+ if f(lo) > 0 or f(hi) < 0:
+ return np.nan
+ while hi - lo > tol:
+ mid = (lo + hi) / 2
+ lo, hi = (mid, hi) if f(mid) < 0 else (lo, mid)
+ return (lo + hi) / 2
+
+
+print('widening the quality spread, midpoint fixed at s = 4, h = 1')
+for spread in [0.4, 0.8, 1.2, 1.6, 1.9]:
+ m_ = Market(s=4, h=1, mu_L=4 - spread / 2, mu_H=4 + spread / 2)
+ print(f' (mu_H - mu_L)/h = {spread / 1:.3f}: crossing = {crossing(m_):.6f}')
+
+print('\nvarying horizontal differentiation, mu = (3.4, 4.6)')
+for h_ in [0.65, 0.8, 1.0, 1.5, 2.5]:
+ m_ = Market(s=4, h=h_, mu_L=3.4, mu_H=4.6)
+ print(f' (mu_H - mu_L)/h = {1.2 / h_:.3f}: crossing = {crossing(m_):.6f}')
+```
+
+Sorted by the ratio $(\mu_H - \mu_L)/h$ the two tables line up, which suggests that the
+crossing point depends on the parameters only through that ratio.
+
+The numbers fall on a straight line with slope $-1/6$ through $1/2$.
+
+```{code-cell} ipython3
+print(f'{"(mu_H-mu_L)/h":>15s}{"bisection":>12s}{"1/2 - ratio/6":>16s}{"error":>12s}')
+for mu_L_, mu_H_, h_ in [(3.4, 4.6, 1.0), (3.1, 4.9, 1.0), (3.8, 4.2, 1.0),
+ (3.4, 4.6, 1.5), (3.4, 4.6, 0.8), (3.05, 4.95, 1.0)]:
+ m_ = Market(s=4, h=h_, mu_L=mu_L_, mu_H=mu_H_)
+ r = (mu_H_ - mu_L_) / h_
+ c, pred = crossing(m_), 0.5 - r / 6
+ print(f'{r:15.4f}{c:12.6f}{pred:16.6f}{c - pred:12.1e}')
+```
+
+So when the two quality levels straddle $s$ symmetrically, the switch occurs at
+
+$$
+\alpha^{\mathrm{cross}} = \frac12 - \frac{\mu_H - \mu_L}{6h} ,
+$$
+
+which condition {eq}`eq:md_condition4` keeps strictly inside $(1/6, 1/2)$, since that
+condition forces $\mu_H - \mu_L < 2h$.
+
+The region of excessive experimentation therefore *shrinks* as the quality spread
+widens relative to $h$.
+
+A wider spread means more is at stake in learning, and the efficient policy responds by
+experimenting a great deal; the equilibrium, driven by each firm's private revenue
+motive, does not keep up except at the most pessimistic beliefs.
+
+Raising $h$ works in the opposite direction, since strongly attached buyers blunt the
+price instrument and let the entrant expand more freely than a planner would choose.
+
+The symmetry is essential.
+
+```{code-cell} ipython3
+print('moving the quality midpoint away from s, with mu = (3.4, 4.6), h = 1')
+for s_ in [3.9, 4.0, 4.1]:
+ m_ = Market(s=s_, h=1, mu_L=3.4, mu_H=4.6)
+ mid = (3.4 + 4.6) / 2
+ print(f' s = {s_} (midpoint {mid}): crossing = {crossing(m_):.6f}'
+ f' formula = {0.5 - 1.2 / 6:.6f}')
+```
+
+Once the midpoint no longer equals $s$ the formula fails, so it is a knife-edge result
+rather than a general one.
+
+```{solution-end}
+```
+
+```{exercise-start}
+:label: md_ex3
+```
+
+This exercise makes the link with {doc}`blackwell_kihlstrom` precise.
+
+In that lecture, a decision maker gains from a more informative experiment exactly when
+the value of the decision problem is convex in the belief, because a more informative
+experiment produces a mean-preserving spread of the posterior.
+
+Here the belief is a martingale and experimentation controls the speed at which it
+spreads, so the same logic applies to each firm.
+
+1. Plot each firm's value of information, $v_i(\alpha)$ minus its current equilibrium
+ revenue, against $\alpha$.
+
+2. Confirm that both are positive everywhere in the interior and vanish at
+ $\alpha \in \{0, 1\}$, and explain why they must vanish there.
+
+3. The value of information also equals $\tfrac12 n(\alpha)\Sigma^2(\alpha)V_i''(\alpha)$.
+
+ Use this to recover $V_i''(\alpha)$ and confirm that both value functions are convex.
+
+```{exercise-end}
+```
+
+```{solution-start} md_ex3
+:class: dropdown
+```
+
+Here is one solution:
+
+```{code-cell} ipython3
+Ai = np.linspace(0.005, 0.995, 2001)
+voi_1 = v1(mkt, Ai) - (1 - n_eq(mkt, Ai)) * p1(mkt, Ai)
+voi_2 = v2(mkt, Ai) - n_eq(mkt, Ai) * p2(mkt, Ai)
+
+fig, axes = plt.subplots(1, 2, figsize=(12, 4.2))
+axes[0].plot(Ai, voi_1, lw=2, label='established firm')
+axes[0].plot(Ai, voi_2, lw=2, label='new firm')
+axes[0].axhline(0, color='0.3', lw=1)
+axes[0].set(xlabel=r'$\alpha$', ylabel='value of information',
+ title='both firms gain from experimentation')
+axes[0].legend(fontsize=9)
+
+V1pp = 2 * voi_1 / (n_eq(mkt, Ai) * Sigma2(mkt, Ai))
+V2pp = 2 * voi_2 / (n_eq(mkt, Ai) * Sigma2(mkt, Ai))
+axes[1].plot(Ai, V1pp, lw=2, label=r"$V_1''(\alpha)$")
+axes[1].plot(Ai, V2pp, lw=2, label=r"$V_2''(\alpha)$")
+axes[1].set(xlabel=r'$\alpha$', yscale='log',
+ title='second derivatives of the value functions')
+axes[1].legend(fontsize=9)
+fig.suptitle('The value of information to each firm')
+fig.tight_layout()
+plt.show()
+
+print(f'minimum value of information, established firm {voi_1.min():.3e}')
+print(f'minimum value of information, new firm {voi_2.min():.3e}')
+print(f'minimum of V1\'\' {V1pp.min():.4f} minimum of V2\'\' {V2pp.min():.4f}')
+```
+
+Both curves are strictly positive on the interior and both second derivatives are
+strictly positive, so both value functions are convex.
+
+The value of information vanishes at $\alpha \in \{0, 1\}$ for two reinforcing reasons.
+
+There is nothing left to learn, so the equilibrium coincides with the full-information
+equilibrium and the revenue gap closes.
+
+And the speed of learning $\Sigma^2(\alpha) \propto \alpha^2(1-\alpha)^2$ vanishes as
+well, so even a convex value function earns nothing from an experiment that reveals
+nothing.
+
+The second derivatives do *not* vanish at the endpoints, which is exactly the
+{doc}`blackwell_kihlstrom` point: the *willingness* to pay for information stays
+positive, but the *supply* of information dries up as beliefs become degenerate.
+
+```{solution-end}
+```
diff --git a/lectures/pricing_information.md b/lectures/pricing_information.md
new file mode 100644
index 000000000..938c4e41b
--- /dev/null
+++ b/lectures/pricing_information.md
@@ -0,0 +1,1128 @@
+---
+jupytext:
+ text_representation:
+ extension: .md
+ format_name: myst
+ format_version: 0.13
+ jupytext_version: 1.16.7
+kernelspec:
+ display_name: Python 3 (ipykernel)
+ language: python
+ name: python3
+---
+
+(pricing_information)=
+```{raw} jupyter
+
+```
+
+# The Design and Price of Information
+
+```{index} single: Information; pricing
+```
+
+```{index} single: Blackwell; and screening
+```
+
+```{contents} Contents
+:depth: 2
+```
+
+## Overview
+
+Earlier lectures in this section asked *which* statistical experiment a decision maker
+should prefer.
+
+{doc}`blackwell_kihlstrom` gave the classic answer: experiment $\mu$ is at least as
+informative as experiment $\nu$ when *every* Bayesian decision maker attains weakly
+higher expected utility with $\mu$.
+
+This lecture asks a different question.
+
+Suppose somebody *owns* the data and wants to sell it.
+
+What should she sell, and at what price?
+
+We study {cite:t}`BergemannBonattiSmolin2018`, who analyze a monopolist data seller
+facing a buyer who already has some private information of his own.
+
+The buyer's private information is exactly what he would like to hide, because it
+determines his willingness to pay.
+
+So the seller screens by offering a *menu* of statistical experiments, degrading the
+information sold to some buyers in order to charge more to others.
+
+The central finding is that degrading information is not simply a matter of adding
+noise.
+
+Blackwell's order is a *partial* order, so two experiments can be ranked differently
+by different decision makers.
+
+The seller exploits precisely those incomparable pairs: information has a **vertical**
+dimension, its quality, and a **horizontal** dimension, its position.
+
+That horizontal dimension has no counterpart in ordinary monopoly screening over
+quality or quantity, and it is what allows the seller to extract rents that would
+otherwise be impossible to reach.
+
+Along the way we will
+
+- compute the value of an arbitrary experiment to an arbitrary belief type,
+- verify numerically that Blackwell's order fails to rank the experiments the seller
+ wants to use,
+- solve the two-type screening problem by brute force and check it against the paper's
+ closed forms,
+- solve the continuum-of-types problem as a **linear program**, which reproduces the
+ paper's ironing and pooling results without any need to implement ironing by hand.
+
+Let's start with imports.
+
+```{code-cell} ipython3
+import matplotlib.pyplot as plt
+import numpy as np
+from scipy import stats
+from scipy.optimize import linprog
+
+plt.rcParams['figure.figsize'] = (10, 5)
+np.set_printoptions(precision=4, suppress=True)
+```
+
+## The decision problem
+
+A data buyer must choose an action $a$ from a finite set $A$ without knowing the state
+$\omega$, which lives in a finite set $\Omega$.
+
+We work throughout with the **matching** case in which the buyer wants his action to
+match the state,
+
+$$
+u(\omega_i, a_j) = \mathbb{1}[i = j] \cdot u_i ,
+$$ (eq:pi_matching)
+
+so that matching state $\omega_i$ pays $u_i > 0$ and any mismatch pays zero.
+
+From here on we take two states and two actions, $\Omega = \{\omega_1, \omega_2\}$ and
+$A = \{a_1, a_2\}$, which is the case {cite:t}`BergemannBonattiSmolin2018` solve
+completely.
+
+The buyer's **type** is his interim belief
+
+$$
+\theta = \Pr[\omega = \omega_1] \in [0, 1] ,
+$$
+
+which is private information.
+
+The seller knows only the distribution $F$ from which $\theta$ is drawn.
+
+Without extra information the buyer picks the better of two constant actions, so his
+reservation utility is
+
+$$
+u(\theta) = \max\{\theta u_1,\ (1 - \theta) u_2\} .
+$$ (eq:pi_outside)
+
+The type that is *least* sure what to do is the one where the two terms are equal,
+
+$$
+\theta^* = \frac{u_2}{u_1 + u_2} .
+$$ (eq:pi_thetastar)
+
+Types above $\theta^*$ would choose $a_1$ on their own, types below would choose $a_2$.
+
+```{note}
+The buyer's belief $\theta$ can be generated from a common prior together with a
+privately observed signal, exactly as in {doc}`likelihood_bayes`.
+
+A buyer with a very precise private signal has $\theta$ near $0$ or $1$; a buyer who
+has learned nothing sits near $\theta^*$.
+
+So "high type" in this lecture means *badly informed*, and it is the badly informed
+buyer who is willing to pay the most.
+```
+
+## Experiments and their value
+
+A statistical experiment is a stochastic matrix mapping states into signals.
+
+With two states and two actions it suffices to consider two signals, and we write
+
+$$
+E = \begin{pmatrix} \pi_1 & 1 - \pi_1 \\ 1 - \pi_2 & \pi_2 \end{pmatrix},
+$$ (eq:pi_experiment)
+
+where row $i$ gives the signal distribution in state $\omega_i$.
+
+Thus $\pi_1 = \Pr[s_1 \mid \omega_1]$ and $\pi_2 = \Pr[s_2 \mid \omega_2]$.
+
+We adopt the normalization $\pi_1 + \pi_2 \geq 1$, which just says that signal $s_1$ is
+relatively more likely in state $\omega_1$ than in state $\omega_2$.
+
+The **fully informative** experiment $\overline{E}$ has $\pi_1 = \pi_2 = 1$.
+
+After seeing signal $s_k$ the buyer picks the action with the highest expected payoff,
+so his gross value is obtained by summing the best he can do signal by signal.
+
+Subtracting his reservation utility {eq}`eq:pi_outside` gives the **net value of
+information**
+
+$$
+V(E, \theta)
+= \max\{\theta \pi_1 u_1,\ (1-\theta)(1-\pi_2) u_2\}
++ \max\{\theta (1-\pi_1) u_1,\ (1-\theta)\pi_2 u_2\}
+- \max\{\theta u_1,\ (1-\theta) u_2\} .
+$$ (eq:pi_value)
+
+```{code-cell} ipython3
+def value(pi1, pi2, theta, u1=1.0, u2=1.0):
+ """Net value of experiment (pi1, pi2) to a buyer with belief theta."""
+ theta = np.asarray(theta, dtype=float)
+ s1 = np.maximum(theta * pi1 * u1, (1 - theta) * (1 - pi2) * u2)
+ s2 = np.maximum(theta * (1 - pi1) * u1, (1 - theta) * pi2 * u2)
+ return s1 + s2 - np.maximum(theta * u1, (1 - theta) * u2)
+```
+
+If the buyer simply obeys the recommendation implicit in each signal, taking $a_1$
+after $s_1$ and $a_2$ after $s_2$, the value collapses to
+
+$$
+V(E, \theta) = \max\bigl\{\theta \pi_1 u_1 + (1-\theta)\pi_2 u_2
+- \max\{\theta u_1, (1-\theta)u_2\},\ 0\bigr\} ,
+$$ (eq:pi_value_obedient)
+
+which is the expression the paper works with.
+
+```{code-cell} ipython3
+def value_obedient(pi1, pi2, theta, u1=1.0, u2=1.0):
+ """Value when the buyer follows the recommendation, or ignores the signal."""
+ theta = np.asarray(theta, dtype=float)
+ return np.maximum(theta * pi1 * u1 + (1 - theta) * pi2 * u2
+ - np.maximum(theta * u1, (1 - theta) * u2), 0.0)
+```
+
+The two expressions agree exactly under the normalization $\pi_1 + \pi_2 \geq 1$ and
+can differ sharply without it, which is what the normalization is for.
+
+```{code-cell} ipython3
+grid = np.linspace(0, 1, 2001)
+worst_ok = worst_bad = 0.0
+for p1 in np.linspace(0, 1, 51):
+ for p2 in np.linspace(0, 1, 51):
+ gap = np.abs(value(p1, p2, grid) - value_obedient(p1, p2, grid)).max()
+ if p1 + p2 >= 1:
+ worst_ok = max(worst_ok, gap)
+ else:
+ worst_bad = max(worst_bad, gap)
+
+print(f'largest gap where pi1 + pi2 >= 1: {worst_ok:.2e}')
+print(f'largest gap where pi1 + pi2 < 1: {worst_bad:.4f}')
+```
+
+We use the general form {eq}`eq:pi_value` from here on, since a buyer who
+*misreports* his type will not in general want to obey the recommendations built into
+somebody else's experiment.
+
+Here is the value of information as a function of the buyer's type.
+
+```{code-cell} ipython3
+---
+mystnb:
+ figure:
+ caption: Value of full and partial information
+ name: fig-pi-value
+---
+theta = np.linspace(0, 1, 1001)
+
+fig, axes = plt.subplots(1, 2, figsize=(11, 4))
+for ax, (p1, p2), ttl in zip(
+ axes, [(1.0, 1.0), (0.5, 1.0)],
+ [r'fully informative $(\pi_1,\pi_2)=(1,1)$',
+ r'partially informative $(\pi_1,\pi_2)=(1/2,1)$']):
+ ax.plot(theta, value(p1, p2, theta), lw=2)
+ ax.axvline(0.5, color='0.6', ls='--', lw=1)
+ ax.set(xlabel=r'$\theta$', ylabel=r'$V(E,\theta)$', title=ttl)
+fig.suptitle('Value of information, $u_1 = u_2 = 1$')
+fig.tight_layout()
+plt.show()
+```
+
+Three features of these pictures drive everything that follows.
+
+The value is **piecewise linear** in $\theta$, because types are probabilities and
+expected utilities are linear in probabilities.
+
+The value is **highest at $\theta^*$** and falls to zero at $\theta \in \{0, 1\}$: the
+buyer who already knows the state will pay nothing, and the buyer who knows least will
+pay most.
+
+The partially informative experiment in the right panel is worth **nothing at all** to
+types above $2/3$, even though it is worth a great deal to types just below $1/2$.
+
+That last property is the seller's main tool.
+
+## Blackwell's order is only partial
+
+{doc}`blackwell_kihlstrom` establishes that experiment $E$ is at least as informative
+as $E'$ in Blackwell's sense exactly when $E'$ is a **garbling** of $E$, meaning there
+is a stochastic matrix $M$ with
+
+$$
+E' = E M .
+$$ (eq:pi_garbling)
+
+When $E$ is invertible this is easy to check: solve $M = E^{-1}E'$ and ask whether $M$
+is a stochastic matrix.
+
+```{code-cell} ipython3
+def experiment(pi1, pi2):
+ return np.array([[pi1, 1 - pi1], [1 - pi2, pi2]])
+
+
+def garbling(E, Ep, tol=1e-9):
+ """Return M with Ep = E @ M if Ep is a garbling of E, else None."""
+ if abs(np.linalg.det(E)) < tol:
+ return None
+ M = np.linalg.solve(E, Ep)
+ if (M > -tol).all() and np.allclose(M.sum(axis=1), 1, atol=tol):
+ return M
+ return None
+
+
+pairs = [((1, 1), (0.8, 1)), ((1, 1), (1, 0.8)),
+ ((0.9, 0.9), (0.8, 0.8)),
+ ((0.8, 1), (1, 0.8)), ((1, 0.8), (0.8, 1))]
+for a, b in pairs:
+ ok = garbling(experiment(*a), experiment(*b)) is not None
+ print(f' is {b} a garbling of {a}? {"yes" if ok else "no"}')
+```
+
+The fully informative experiment garbles into everything, and $(0.9, 0.9)$ garbles into
+the uniformly noisier $(0.8, 0.8)$.
+
+Those are the **vertical** comparisons, and Blackwell's theorem says every type agrees
+about them.
+
+But $(0.8, 1)$ and $(1, 0.8)$ garble into each other in neither direction.
+
+Blackwell's order simply does not rank them, and that means different types are free to
+rank them differently.
+
+```{code-cell} ipython3
+---
+mystnb:
+ figure:
+ caption: Two experiments that Blackwell's order does not rank
+ name: fig-pi-blackwell
+---
+va, vb = value(0.8, 1, theta), value(1, 0.8, theta)
+
+fig, ax = plt.subplots()
+ax.plot(theta, va, lw=2, label=r'$E_a = (0.8, 1)$')
+ax.plot(theta, vb, lw=2, label=r'$E_b = (1, 0.8)$')
+ax.fill_between(theta, va, vb, where=va > vb, alpha=0.15, color='C0')
+ax.fill_between(theta, va, vb, where=vb > va, alpha=0.15, color='C1')
+ax.axvline(0.5, color='0.4', ls='--', lw=1)
+ax.set(xlabel=r'$\theta$', ylabel=r'$V(E,\theta)$',
+ title='Types below $1/2$ prefer $E_a$, types above prefer $E_b$')
+ax.legend()
+fig.tight_layout()
+plt.show()
+
+for t in [0.2, 0.35, 0.65, 0.8]:
+ pref = 'E_a' if value(0.8, 1, t) > value(1, 0.8, t) else 'E_b'
+ print(f' theta = {t}: V(E_a) = {value(0.8, 1, t):.4f},'
+ f' V(E_b) = {value(1, 0.8, t):.4f} prefers {pref}')
+```
+
+$E_a$ is better at ruling out state $\omega_2$ and $E_b$ is better at ruling out state
+$\omega_1$.
+
+A buyer who already thinks $\omega_1$ is likely wants help distinguishing among the
+possibilities he has *not* ruled out, so he values $E_b$; a buyer who leans the other
+way values $E_a$.
+
+This is the **horizontal** dimension of information.
+
+In ordinary nonlinear pricing over quality or quantity, all types agree on the ranking
+of products and the seller can only move up and down a single ladder.
+
+Here the seller has a second dial, and turning it lets her hand one type something that
+is worthless to another.
+
+## The seller's problem
+
+The seller commits to a menu $\{E(\theta), t(\theta)\}$ assigning an experiment and a
+price to each reported type.
+
+Payments cannot be made contingent on the state, the signal, or the buyer's action, so
+the value of an experiment to a buyer is determined by his belief alone.
+
+Writing $V(\theta) = V(E(\theta), \theta) - t(\theta)$ for the buyer's rent, the seller
+solves
+
+$$
+\max_{\{E(\theta),\, t(\theta)\}} \int t(\theta) \, dF(\theta)
+$$ (eq:pi_sellerproblem)
+
+subject to incentive compatibility and individual rationality,
+
+$$
+V(\theta) \geq V(E(\theta'), \theta) - t(\theta') \ \ \forall \theta, \theta',
+\qquad
+V(\theta) \geq 0 \ \ \forall \theta .
+$$ (eq:pi_icir)
+
+{cite:t}`BergemannBonattiSmolin2018` establish two structural results that we will see
+confirmed in every menu we compute.
+
+```{prf:proposition}
+:label: pi_prop_structure
+
+In any optimal menu:
+
+1. the fully informative experiment $\overline{E}$ is offered;
+2. every experiment is **nondispersed**, meaning $\pi_{ij} = 0$ for some $i \neq j$;
+3. in the matching case every experiment is **concentrated**, meaning $\pi_{ii} = 1$
+ for some $i$.
+```
+
+Part 3 says that in our binary setting every experiment on the menu has $\pi_1 = 1$ or
+$\pi_2 = 1$.
+
+Optimal degradation never adds unbiased noise everywhere; it leaves one state perfectly
+detectable and blurs the other.
+
+## Two types
+
+Take two types $\theta^L$ and $\theta^H$, with $\theta^H$ the *high value* type in the
+sense that he values the fully informative experiment more,
+
+$$
+V(\overline{E}, \theta^H) \geq V(\overline{E}, \theta^L) .
+$$
+
+With $u_1 = u_2$ this says $|\theta^H - 1/2| \leq |\theta^L - 1/2|$, so the high type is
+the one who is *less* well informed to begin with.
+
+Let $\gamma = \Pr[\theta = \theta^H]$.
+
+The types are **congruent** if $\theta^* < \theta^H < \theta^L$, so both would take the
+same action without extra information, and **noncongruent** if
+$\theta^L < \theta^* < \theta^H$.
+
+An optimal menu has the familiar shape: the high type buys $\overline{E}$, the low
+type's participation constraint binds, and the high type's incentive constraint binds.
+
+Those three facts pin down both prices once the low type's experiment is chosen.
+
+```{code-cell} ipython3
+def two_type_revenue(pi1, pi2, tL, tH, gamma, u1=1.0, u2=1.0):
+ """Revenue when the high type buys E_bar and the low type buys (pi1, pi2)."""
+ VbarH, VbarL = value(1, 1, tH, u1, u2), value(1, 1, tL, u1, u2)
+ VL_L, VL_H = value(pi1, pi2, tL, u1, u2), value(pi1, pi2, tH, u1, u2)
+ t_low = VL_L # low type's IR binds
+ t_high = VbarH - VL_H + t_low # high type's IC binds
+ if t_high > VbarH + 1e-12: # high type must participate
+ return -np.inf
+ if VbarL - t_high > 1e-12: # low type must not deviate
+ return -np.inf
+ return gamma * t_high + (1 - gamma) * t_low
+```
+
+### Noncongruent types
+
+Set $\theta^L = 1/5$ and $\theta^H = 7/10$ with $u_1 = u_2 = 1$, so that $\theta^* = 1/2$
+lies between them.
+
+Because the two types would take *different* actions on their own, the seller can build
+an experiment that is valuable to one and worthless to the other.
+
+Choosing $\pi_2 = 1$ and
+
+$$
+\pi_1' = \frac{u_1 \theta^H - u_2 (1 - \theta^H)}{u_1 \theta^H}
+$$ (eq:pi_zerovalue)
+
+leaves the high type exactly indifferent between his two actions after signal $s_1$, so
+the experiment is worth nothing to him while the low type values it strictly.
+
+That is feasible but not optimal.
+
+The seller does better by making the high type's incentive constraint bind instead,
+which gives
+
+$$
+\pi_1'' = \frac{u_1 \theta^H - u_2 (1 - \theta^H)}{u_1 (\theta^H - \theta^L)} .
+$$ (eq:pi_optimal2type)
+
+```{code-cell} ipython3
+tL, tH, u1, u2 = 0.2, 0.7, 1.0, 1.0
+pi1_zero = (u1 * tH - u2 * (1 - tH)) / (u1 * tH)
+pi1_opt = (u1 * tH - u2 * (1 - tH)) / (u1 * (tH - tL))
+
+print(f'zero-value-to-high experiment pi1 = {pi1_zero:.4f} (= 4/7)')
+print(f'binding-IC experiment pi1 = {pi1_opt:.4f} (= 4/5)')
+print(f'\n V(E_zero, theta_H) = {value(pi1_zero, 1, tH):.4f}')
+print(f' V(E_opt, theta_L) = {value(pi1_opt, 1, tL):.4f}'
+ f' V(E_opt, theta_H) = {value(pi1_opt, 1, tH):.4f}')
+```
+
+The second experiment gives *both* types the same gross value, so the seller can charge
+each of them exactly what the information is worth and leave no rent at all.
+
+```{code-cell} ipython3
+---
+mystnb:
+ figure:
+ caption: Net value of the two menus as a function of the buyer's type
+ name: fig-pi-menus
+---
+fig, axes = plt.subplots(1, 2, figsize=(12, 4.2))
+for ax, p1, ttl in zip(axes, [pi1_zero, pi1_opt],
+ ['suboptimal menu: partial experiment worth zero to $\\theta^H$',
+ 'optimal menu: high type indifferent between the two items']):
+ t_hi = value(1, 1, tH) # price of E_bar
+ t_lo = value(p1, 1, tL) # price of partial item
+ ax.plot(theta, value(1, 1, theta) - t_hi, lw=2, label='fully informative')
+ ax.plot(theta, value(p1, 1, theta) - t_lo, lw=2, ls='--',
+ label=f'partial, $\\pi_1={p1:.3f}$')
+ ax.axhline(0, color='0.3', lw=1)
+ for t, nm in [(tL, r'$\theta^L$'), (tH, r'$\theta^H$')]:
+ ax.axvline(t, color='0.7', ls=':', lw=1)
+ ax.annotate(nm, (t, ax.get_ylim()[0]), fontsize=9)
+ ax.set(xlabel=r'$\theta$', ylabel=r'$V - t$', title=ttl, ylim=(-0.35, 0.25))
+ ax.legend(fontsize=8, loc='upper left')
+fig.tight_layout()
+plt.show()
+```
+
+In the left panel the high type's net value of the fully informative experiment lies
+strictly above his net value of the partial one, so his incentive constraint is slack
+and the seller is leaving money on the table.
+
+In the right panel the two curves meet exactly at $\theta^H$.
+
+Now we check the closed form {eq}`eq:pi_optimal2type` against a brute-force search over
+*all* experiments.
+
+```{code-cell} ipython3
+def brute_force(tL, tH, gamma, n=301, u1=1.0, u2=1.0):
+ """Search over all (pi1, pi2) for the best low-type experiment."""
+ g = np.linspace(0, 1, n)
+ best, arg = -np.inf, None
+ for p1 in g:
+ for p2 in g:
+ if p1 + p2 < 1:
+ continue
+ r = two_type_revenue(p1, p2, tL, tH, gamma, u1, u2)
+ if r > best:
+ best, arg = r, (p1, p2)
+ return best, arg
+
+
+print(f'{"gamma":>7s}{"brute force":>13s}{"argmax":>18s}'
+ f'{"eq (20) menu":>14s}{"E_bar to both":>15s}')
+for gamma in [0.10, 0.25, 0.30, 0.50, 0.90]:
+ best, arg = brute_force(tL, tH, gamma)
+ closed = two_type_revenue(pi1_opt, 1.0, tL, tH, gamma)
+ both = two_type_revenue(1.0, 1.0, tL, tH, gamma)
+ print(f'{gamma:7.2f}{best:13.5f} ({arg[0]:.3f}, {arg[1]:.3f})'
+ f'{closed:14.5f}{both:15.5f}')
+print(f'\nthe paper: discriminate iff gamma > theta_L / theta_H = {tL / tH:.4f}')
+```
+
+The brute-force optimum sits at $(\pi_1, \pi_2) = (0.8, 1)$ whenever discrimination
+pays, matching {eq}`eq:pi_optimal2type` exactly, and at $(1, 1)$ otherwise.
+
+The switch happens right at $\gamma = \theta^L / \theta^H$.
+
+When low types are common the seller prefers to sell everyone the fully informative
+experiment cheaply; when high types are common she prefers to protect the high price by
+degrading what the low type gets.
+
+Note also that both experiments in the optimal menu have $\pi_2 = 1$, confirming
+part 3 of {prf:ref}`pi_prop_structure`.
+
+## A continuum of types
+
+Now let $\theta$ be distributed on $[0,1]$ with density $f$ and distribution $F$.
+
+The key simplification is that the value of an experiment depends on $(\pi_1, \pi_2)$
+only through the scalar
+
+$$
+q = \pi_1 u_1 - \pi_2 u_2 \in [-u_2,\ u_1] ,
+$$ (eq:pi_q)
+
+which {cite:t}`BergemannBonattiSmolin2018` call the **differential informativeness** of
+the experiment.
+
+In terms of $q$ the value becomes
+
+$$
+V(q, \theta) = \max\bigl\{\theta q + u_2 + \min\{u_1 - u_2 - q,\ 0\}
+- \max\{\theta u_1,\ (1-\theta) u_2\},\ 0 \bigr\} .
+$$ (eq:pi_valueq)
+
+The fully informative experiment is $q = u_1 - u_2$.
+
+The two endpoints $q = -u_2$ and $q = u_1$ are the experiments in which one signal
+occurs with probability one in both states, so they convey nothing.
+
+```{code-cell} ipython3
+def value_q(q, theta, u1=1.0, u2=1.0):
+ """Value of the experiment with differential informativeness q."""
+ theta = np.asarray(theta, dtype=float)
+ gross = theta * q + u2 + np.minimum(u1 - u2 - q, 0.0)
+ return np.maximum(gross - np.maximum(theta * u1, (1 - theta) * u2), 0.0)
+
+
+def q_to_experiment(q, u1=1.0, u2=1.0):
+ """Recover (pi1, pi2) from q using pi1 = 1 or pi2 = 1."""
+ return (1.0, (u1 - q) / u2) if q >= u1 - u2 else ((q + u2) / u1, 1.0)
+
+
+for q in [-1.0, -0.5, 0.0, 0.5, 1.0]:
+ p1, p2 = q_to_experiment(q)
+ print(f' q = {q:+.2f} -> (pi1, pi2) = ({p1:.3f}, {p2:.3f}),'
+ f' max value over types = {value_q(q, theta).max():.4f}')
+```
+
+A menu is now a function $q(\theta)$, and incentive compatibility requires it to be
+non-decreasing.
+
+Types who think $\omega_1$ is more likely want experiments with higher $q$, which
+deliver sharper evidence about the state they consider *less* likely.
+
+There is a second, less familiar restriction.
+
+Because information is worthless to types $\theta \in \{0, 1\}$, applying the envelope
+theorem separately on $[0, \theta^*]$ and $[\theta^*, 1]$ and matching the two
+expressions for the rent of the pivotal type $\theta^*$ forces
+
+$$
+\int_0^1 q(\theta) \, d\theta = u_1 - u_2 .
+$$ (eq:pi_integral)
+
+Note that this integral is taken with respect to $d\theta$, not $dF(\theta)$.
+
+With those two constraints, the seller's problem reduces to
+
+$$
+\max_{q(\cdot)} \int_0^1
+\Bigl[\bigl(\theta f(\theta) + F(\theta)\bigr) q(\theta)
++ \min\bigl\{\bigl(u_1 - u_2 - q(\theta)\bigr) f(\theta),\ 0 \bigr\}\Bigr] d\theta
+$$ (eq:pi_reduced)
+
+subject to $q$ non-decreasing and {eq}`eq:pi_integral`.
+
+### Solving it as a linear program
+
+The integrand of {eq}`eq:pi_reduced` is **concave and piecewise linear** in $q$, since
+$\min\{(d - q) f, 0\} = -f \max\{q - d, 0\}$ with $d = u_1 - u_2$ and $f \geq 0$.
+
+Maximizing a concave piecewise-linear objective subject to linear constraints is a
+linear program.
+
+Introducing $z(\theta) \geq \max\{q(\theta) - d,\ 0\}$ and discretizing $\theta$ on a
+grid gives
+
+$$
+\max_{q, z} \ \sum_n w_n\Bigl[\bigl(\theta_n f_n + F_n\bigr) q_n - f_n z_n\Bigr]
+$$
+
+subject to $z_n \geq q_n - d$, $z_n \geq 0$, $q_{n+1} \geq q_n$,
+$-u_2 \leq q_n \leq u_1$, and $\sum_n w_n q_n = d$.
+
+```{code-cell} ipython3
+def solve_menu(theta, f, u1=1.0, u2=1.0):
+ """Solve the seller's problem on a grid of types by linear programming."""
+ N = len(theta)
+ dth = theta[1] - theta[0]
+ F = np.cumsum(f) * dth
+ F = F / F[-1]
+ w = np.full(N, dth)
+ d = u1 - u2
+
+ c = np.concatenate([-(theta * f + F) * w, f * w]) # linprog minimizes
+ A_ub = np.hstack([np.eye(N), -np.eye(N)]) # q - z <= d
+ b_ub = np.full(N, d)
+ D = np.zeros((N - 1, 2 * N)) # q_n - q_{n+1} <= 0
+ rows = np.arange(N - 1)
+ D[rows, rows], D[rows, rows + 1] = 1.0, -1.0
+ A_ub = np.vstack([A_ub, D])
+ b_ub = np.concatenate([b_ub, np.zeros(N - 1)])
+ A_eq = np.concatenate([w, np.zeros(N)])[None, :] # integral constraint
+ bounds = [(-u2, u1)] * N + [(0, None)] * N
+
+ res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=np.array([d]),
+ bounds=bounds, method='highs')
+ return res.x[:N], res
+```
+
+The linear program handles the monotonicity constraint automatically.
+
+This matters, because the alternative is to implement Myerson's **ironing** procedure
+by hand: form the virtual values
+
+$$
+\phi^-(\theta) = \theta f(\theta) + F(\theta),
+\qquad
+\phi^+(\theta) = (\theta - 1) f(\theta) + F(\theta) ,
+$$ (eq:pi_virtual)
+
+replace them by the derivatives of the convex hulls of their integrals, and then find
+the multiplier on {eq}`eq:pi_integral` (see {cite:t}`Myerson1981` and
+{cite:t}`Toikka2011`).
+
+The linear program does all of that implicitly.
+
+We also want the prices, which follow from the requirement that a buyer at the boundary
+between two items be indifferent between them.
+
+```{code-cell} ipython3
+def menu_items(theta, q, u1=1.0, u2=1.0, tol=1e-4, min_width=0.01):
+ """Distinct items in the menu, with the interval of types served and the price.
+
+ Values of q taken on a negligible set of types are transition artifacts of the
+ grid, not items on the menu, so we drop them.
+ """
+ qr = np.round(q / tol) * tol
+ vals = [v for v in np.unique(qr)
+ if theta[qr == v].max() - theta[qr == v].min() >= min_width]
+ items = sorted([(v, theta[qr == v].min(), theta[qr == v].max()) for v in vals],
+ key=lambda x: x[1])
+ out, prev_v, prev_t = [], None, 0.0
+ for v, lo, hi in items:
+ if value_q(v, theta, u1, u2).max() < 1e-9: # uninformative item
+ price = 0.0
+ elif prev_v is None:
+ price = 0.0
+ else:
+ price = float(value_q(v, lo, u1, u2)
+ - value_q(prev_v, lo, u1, u2) + prev_t)
+ out.append((v, lo, hi, price))
+ prev_v, prev_t = v, price
+ return out
+```
+
+### Uniformly distributed types
+
+With $u_1 = u_2 = 1$ and $\theta$ uniform, the virtual values are $\phi^-(\theta) = 2\theta$
+and $\phi^+(\theta) = 2\theta - 1$.
+
+Both are strictly increasing, so no ironing is required and the optimal menu should
+contain a single informative item.
+
+```{code-cell} ipython3
+N = 2001
+theta_g = np.linspace(0, 1, N)
+q_unif, res = solve_menu(theta_g, np.ones(N))
+
+print('LP status:', res.message)
+print('distinct values of q:', np.unique(np.round(q_unif, 4)))
+for v, lo, hi, p in menu_items(theta_g, q_unif):
+ p1, p2 = q_to_experiment(v)
+ print(f' q = {v:+.4f} (pi1, pi2) = ({p1:.3f}, {p2:.3f})'
+ f' types [{lo:.3f}, {hi:.3f}] price {p:.4f}')
+```
+
+The seller offers the fully informative experiment to the middle range of types at a
+single price and nothing to anyone else.
+
+The cutoffs and the price match the analytic solution of
+{cite:t}`BergemannBonattiSmolin2018` exactly: full information to $\theta \in [1/4, 3/4]$
+at a price of $1/4$.
+
+This is the "no-haggling" outcome of {cite:t}`RileyZeckhauser1983` adapted to
+information.
+
+```{code-cell} ipython3
+---
+mystnb:
+ figure:
+ caption: Optimal menu with uniformly distributed types
+ name: fig-pi-uniform
+---
+fig, axes = plt.subplots(1, 2, figsize=(12, 4))
+axes[0].plot(theta_g, 2 * theta_g, lw=2, label=r'$\phi^-(\theta) = 2\theta$')
+axes[0].plot(theta_g, 2 * theta_g - 1, lw=2, label=r'$\phi^+(\theta) = 2\theta - 1$')
+axes[0].axhline(0.5, color='0.4', ls='--', lw=1, label=r'$\lambda^* = 1/2$')
+axes[0].set(xlabel=r'$\theta$', title='virtual values, both strictly increasing')
+axes[0].legend(fontsize=9)
+
+axes[1].step(theta_g, q_unif, lw=2, where='mid')
+axes[1].set(xlabel=r'$\theta$', ylabel=r'$q^*(\theta)$', ylim=(-1.15, 1.15),
+ title='optimal menu: one informative item')
+axes[1].annotate('no information', (0.06, -0.85), fontsize=9)
+axes[1].annotate('full information', (0.38, 0.12), fontsize=9)
+axes[1].annotate('no information', (0.78, 0.85), fontsize=9)
+fig.tight_layout()
+plt.show()
+```
+
+### Bimodal types and the case for versioning
+
+Corollary 1 of {cite:t}`BergemannBonattiSmolin2018` says that a second experiment is
+offered only when the virtual values require ironing.
+
+Since types are *beliefs*, a natural way to break regularity is a population in which
+most buyers are already well informed, so that the density piles up near both ends.
+
+We follow the paper and take an equal mixture of $\text{Beta}(8, 30)$ and
+$\text{Beta}(60, 30)$.
+
+```{code-cell} ipython3
+f_bimodal = (0.5 * stats.beta(8, 30).pdf(theta_g)
+ + 0.5 * stats.beta(60, 30).pdf(theta_g))
+q_bi, res_bi = solve_menu(theta_g, f_bimodal)
+
+print('LP status:', res_bi.message)
+print('distinct values of q:', np.unique(np.round(q_bi, 3)))
+print()
+for v, lo, hi, p in menu_items(theta_g, q_bi):
+ p1, p2 = q_to_experiment(v)
+ label = 'no information' if abs(p) < 1e-9 else (
+ 'full information' if abs(v) < 1e-6 else 'partial information')
+ print(f' q = {v:+.4f} (pi1, pi2) = ({p1:.3f}, {p2:.3f})'
+ f' types [{lo:.3f}, {hi:.3f}] price {p:.4f} {label}')
+```
+
+Now the menu contains **two** informative items, in line with
+{prf:ref}`pi_prop_structure` and with the result that an optimal menu never contains
+more than two.
+
+The partial item has $\pi_2 = 1$, so signal $s_1$ occurs only in state $\omega_1$ and
+perfectly reveals it, while signal $s_2$ leaves the buyer uncertain.
+
+It is bought by a range of relatively well-informed types who would not pay the price
+the seller wants to charge the large mass of buyers near $\theta \approx 0.7$.
+
+```{code-cell} ipython3
+---
+mystnb:
+ figure:
+ caption: Bimodal type density and the resulting two-item menu
+ name: fig-pi-bimodal
+---
+items = menu_items(theta_g, q_bi)
+
+fig, axes = plt.subplots(1, 2, figsize=(12, 4))
+axes[0].plot(theta_g, f_bimodal, lw=2, color='C2')
+axes[0].fill_between(theta_g, f_bimodal, alpha=0.2, color='C2')
+axes[0].set(xlabel=r'$\theta$', ylabel='density',
+ title='most buyers are already well informed')
+
+axes[1].step(theta_g, q_bi, lw=2, where='mid')
+axes[1].set(xlabel=r'$\theta$', ylabel=r'$q^*(\theta)$', ylim=(-1.15, 1.15),
+ title='optimal menu: two informative items')
+for v, lo, hi, p in items:
+ if p > 1e-9:
+ axes[1].annotate(f'price {p:.3f}', ((lo + hi) / 2, v + 0.12),
+ ha='center', fontsize=9)
+fig.tight_layout()
+plt.show()
+```
+
+We can see directly why the seller bothers.
+
+```{code-cell} ipython3
+def revenue(theta, q, f, u1=1.0, u2=1.0):
+ """Expected revenue from the menu q under density f."""
+ dth = theta[1] - theta[0]
+ price = np.zeros_like(theta)
+ for v, lo, hi, p in menu_items(theta, q, u1, u2):
+ price[(theta >= lo) & (theta <= hi)] = p
+ return np.sum(price * f) * dth / (np.sum(f) * dth)
+
+
+q_single = np.where(q_bi < -0.5, -1.0, np.where(q_bi > 0.5, 1.0, 0.0))
+print(f'revenue, optimal two-item menu {revenue(theta_g, q_bi, f_bimodal):.5f}')
+print(f'revenue, best single-item menu '
+ f'{revenue(theta_g, q_single, f_bimodal):.5f}')
+```
+
+Removing the partial item and selling only full information costs the seller revenue.
+
+The partial experiment is not a noisier version of the same product; it is a
+*differently positioned* one, cheap enough for the well-informed types and useless
+enough to the ill-informed ones that it does not undercut the high price.
+
+## Concluding remarks
+
+Blackwell's theorem tells us when *all* decision makers agree that one experiment beats
+another.
+
+Read as a design principle, its real content is the size of the set where it is
+silent.
+
+{cite:t}`BergemannBonattiSmolin2018` show that a monopolist selling data lives in that
+set, since screening by belief requires products that different types rank differently.
+
+Two lessons carry beyond the model.
+
+First, optimal degradation of information is structured rather than random: every
+experiment on the menu keeps one state perfectly detectable and blurs the other, so a
+data product should never be built by adding unbiased noise to a database.
+
+Second, versioning becomes worthwhile precisely when buyers are already well informed,
+because that is when the distribution of willingness to pay is irregular enough to
+require ironing.
+
+Selling information to imperfectly informed buyers has a long history.
+
+{cite:t}`AdmatiPfleiderer1986` study a seller facing a continuum of *ex ante identical*
+traders who then trade a common-value asset, and find that the seller wants to supply
+noisy and *idiosyncratic* information, so that each trader retains a local monopoly on
+what he knows.
+
+The heterogeneity there is created by the seller; here it is the buyer's own prior
+information, and that is what turns the problem into one of screening.
+
+{cite:t}`BergemannBonatti2015` study the opposite side of the same market, a buyer
+deciding which queries to purchase when the price of data is set competitively.
+
+A useful contrast is {cite:t}`KamenicaGentzkow2011`, where a sender also commits to an
+information structure but has no monetary transfers and cares directly about the
+receiver's action; here the seller cares only about revenue and cannot condition
+payments on the state, the signal, or the buyer's action.
+
+Readers who want the statistical background can return to {doc}`blackwell_kihlstrom`
+for the equivalence between the economic, sufficiency, and uncertainty-reduction
+criteria, to {doc}`likelihood_bayes` for how private signals generate the interim
+beliefs that are the buyer types here, and to
+{doc}`information_market_equilibrium` for what happens when information is transmitted
+by prices rather than sold directly.
+
+## Exercises
+
+```{exercise-start}
+:label: pi_ex1
+```
+
+This exercise studies the **congruent** case, in which both types would take the same
+action without extra information.
+
+Set $u_1 = u_2 = 1$, $\theta^L = 0.9$ and $\theta^H = 0.7$, so that
+$\theta^* = 1/2 < \theta^H < \theta^L$.
+
+Because both types would choose $a_1$ on their own, the seller has no reason to degrade
+what the low type learns about $\omega_1$, so set $\pi_1 = 1$ and treat $\pi_2$ as the
+only choice variable.
+
+1. Plot the seller's revenue against $\pi_2 \in [0, 1]$ for several values of
+ $\gamma$, and confirm that it is *linear*.
+
+2. Conclude that the optimum is always at an endpoint, so the low type receives either
+ full information or none.
+
+3. {cite:t}`BergemannBonattiSmolin2018` show that the low type receives the fully
+ informative experiment if and only if
+ $\gamma \leq (1 - \theta^L)/(1 - \theta^H)$.
+
+ Locate the switch point numerically by bisection and compare.
+
+Why is the answer extremal here, when the noncongruent case in the lecture produced an
+interior $\pi_1 = 4/5$?
+
+```{exercise-end}
+```
+
+```{solution-start} pi_ex1
+:class: dropdown
+```
+
+Here is one solution:
+
+```{code-cell} ipython3
+tL_c, tH_c = 0.9, 0.7
+p2_grid = np.linspace(0, 1, 401)
+
+fig, ax = plt.subplots()
+for gamma in [0.1, 0.25, 1/3, 0.5, 0.7]:
+ r = np.array([two_type_revenue(1.0, p2, tL_c, tH_c, gamma) for p2 in p2_grid])
+ dev = np.abs(r - np.interp(p2_grid, [0, 1], [r[0], r[-1]])).max()
+ ax.plot(p2_grid, r, lw=2, label=rf'$\gamma = {gamma:.3f}$')
+ print(f'gamma = {gamma:.3f}: revenue at pi2=0 is {r[0]:.5f}, '
+ f'at pi2=1 is {r[-1]:.5f}, deviation from linear {dev:.1e}')
+ax.set(xlabel=r'$\pi_2$', ylabel='revenue',
+ title='revenue is linear in $\pi_2$, so the optimum is at an endpoint')
+ax.legend(fontsize=9)
+fig.tight_layout()
+plt.show()
+```
+
+```{code-cell} ipython3
+lo, hi = 0.0, 1.0
+for _ in range(60):
+ mid = (lo + hi) / 2
+ if two_type_revenue(1, 1, tL_c, tH_c, mid) >= two_type_revenue(1, 0, tL_c, tH_c, mid):
+ lo = mid
+ else:
+ hi = mid
+
+print(f'numerical switch point gamma = {lo:.6f}')
+print(f'(1 - theta_L) / (1 - theta_H) = {(1 - tL_c) / (1 - tH_c):.6f}')
+```
+
+Revenue is linear in $\pi_2$ to machine precision, so the optimum is always at
+$\pi_2 \in \{0, 1\}$, and the switch occurs exactly at $\gamma = 1/3$ as predicted.
+
+The reason for the extremal answer is that with congruent beliefs both types would
+choose $a_1$ anyway, so the only question is how much the seller reveals about
+$\omega_2$.
+
+Both types then value the experiment through the same term $(1 - \theta)\pi_2 u_2$,
+which is why the objective and constraints are linear in the single variable $\pi_2$
+and why the no-haggling logic of {cite:t}`RileyZeckhauser1983` applies.
+
+With noncongruent beliefs the two types take different actions on their own, the kink
+in the value function lies between them, and the seller can position an experiment so
+that it is worth much to one type and little to the other.
+
+That possibility is what makes an interior distortion optimal.
+
+```{solution-end}
+```
+
+```{exercise-start}
+:label: pi_ex2
+```
+
+Corollary 1 of {cite:t}`BergemannBonattiSmolin2018` states that the optimal menu
+contains a single item whenever both virtual values {eq}`eq:pi_virtual` are strictly
+increasing, and that for uniformly distributed types this holds **irrespective of the
+payoffs** $(u_1, u_2)$.
+
+1. Verify this by solving the seller's problem with uniform types for several
+ asymmetric payoff pairs, for instance $(u_1, u_2) \in \{(1, 1), (2, 1), (1, 3),
+ (5, 1)\}$.
+
+2. For each case report $\theta^*$, the interval of types served, and the price.
+
+3. Confirm that the fully informative experiment is always the item offered, as
+ {prf:ref}`pi_prop_structure` requires.
+
+```{exercise-end}
+```
+
+```{solution-start} pi_ex2
+:class: dropdown
+```
+
+Here is one solution:
+
+```{code-cell} ipython3
+print(f'{"u1":>4s}{"u2":>4s}{"theta*":>9s}{"q offered":>12s}'
+ f'{"types served":>22s}{"price":>9s}')
+for u1_, u2_ in [(1, 1), (2, 1), (1, 3), (5, 1)]:
+ q_a, _ = solve_menu(theta_g, np.ones(N), u1_, u2_)
+ star = u2_ / (u1_ + u2_)
+ served = [it for it in menu_items(theta_g, q_a, u1_, u2_) if it[3] > 1e-9]
+ v, lo, hi, p = served[0]
+ print(f'{u1_:4d}{u2_:4d}{star:9.4f}{v:12.4f}'
+ f'{f"[{lo:.3f}, {hi:.3f}]":>22s}{p:9.4f}')
+ assert abs(v - (u1_ - u2_)) < 1e-3 # the item is fully informative
+print('\nevery menu contains exactly one informative item, '
+ 'and it is the fully informative one')
+```
+
+The virtual values for a uniform density are $\phi^-(\theta) = 2\theta$ and
+$\phi^+(\theta) = 2\theta - 1$ whatever the payoffs, because $u_1$ and $u_2$ enter the
+seller's problem only through $d = u_1 - u_2$ and the bounds on $q$, not through
+$f$ or $F$.
+
+Both are strictly increasing, so no ironing is needed and a single item is optimal.
+
+The payoffs do move $\theta^*$ and hence which types are served and at what price, but
+they never make versioning worthwhile under a uniform density.
+
+```{solution-end}
+```
+
+```{exercise-start}
+:label: pi_ex3
+```
+
+This exercise connects the lecture back to {doc}`blackwell_kihlstrom`.
+
+Blackwell's theorem says that if $E'$ is a garbling of $E$ then *every* decision maker
+weakly prefers $E$.
+
+1. Draw many random pairs of binary experiments with $\pi_1 + \pi_2 \geq 1$.
+
+2. For each pair, use `garbling` to decide whether one is a garbling of the other, and
+ separately compute whether one dominates the other in value at every type on a fine
+ grid.
+
+3. Confirm that garbling implies unanimous preference, and report what fraction of
+ random pairs Blackwell's order fails to rank.
+
+4. Among the unranked pairs, verify that some types prefer one experiment and some the
+ other.
+
+```{exercise-end}
+```
+
+```{solution-start} pi_ex3
+:class: dropdown
+```
+
+Here is one solution:
+
+```{code-cell} ipython3
+rng = np.random.default_rng(0)
+grid_t = np.linspace(0.001, 0.999, 999)
+
+n_pairs, n_garble, n_unranked, n_disagree, violations = 4000, 0, 0, 0, 0
+for _ in range(n_pairs):
+ (a1, a2), (b1, b2) = rng.uniform(0, 1, 2), rng.uniform(0, 1, 2)
+ if a1 + a2 < 1 or b1 + b2 < 1:
+ continue
+ Ea, Eb = experiment(a1, a2), experiment(b1, b2)
+ va, vb = value(a1, a2, grid_t), value(b1, b2, grid_t)
+
+ a_garbles_b = garbling(Ea, Eb) is not None # Eb is a garbling of Ea
+ b_garbles_a = garbling(Eb, Ea) is not None
+ a_dominates = np.all(va >= vb - 1e-9)
+ b_dominates = np.all(vb >= va - 1e-9)
+
+ if a_garbles_b:
+ n_garble += 1
+ if not a_dominates:
+ violations += 1
+ if b_garbles_a:
+ n_garble += 1
+ if not b_dominates:
+ violations += 1
+ if not (a_garbles_b or b_garbles_a):
+ n_unranked += 1
+ if not (a_dominates or b_dominates):
+ n_disagree += 1
+
+print(f'garbling relations found {n_garble}')
+print(f'violations of Blackwell {violations}')
+print(f'pairs unranked by Blackwell {n_unranked}')
+print(f' of which types disagree {n_disagree} '
+ f'({100 * n_disagree / n_unranked:.1f}%)')
+```
+
+Blackwell's theorem is never violated: whenever one experiment garbles into the other,
+every type prefers the garbling source.
+
+A large share of random pairs is left unranked, and for essentially all of those the
+types genuinely disagree, with some preferring one experiment and some the other.
+
+That unranked region is exactly the room the data seller needs.
+
+If Blackwell's order were complete, every buyer would agree on the ranking of all
+information products, the seller's problem would collapse to standard nonlinear pricing
+over a single quality index, and the horizontal screening described in this lecture
+would be impossible.
+
+```{solution-end}
+```