mergeron: Python for analyzing merger enforcement policy¶
Visualize the sets of mergers falling within specified concentration and diversion-ratio thresholds. Analyze merger investigations data published by the U.S. Federal Trade Commission in various reports on extended merger investigations (Second Requests) during 1996 to 2011. Generate data under specified distributions of firm counts, market shares, price-cost margins, and prices, optionally imposing equilibrium conditions for Bertrand oligopoly with MNL demand and restrictions implied by statutory filing thresholds. Compute intrinsic enforcement rates or intrinsic clearance rates using generated data, with bounds for: concentration; diversion ratio; gross upward pricing pressure (GUPPI); critical marginal cost reduction (CMCR); and illustrative price rise (IPR).
Installation¶
To install mergeron, execute the following shell command:
python -m pip install mergeron
Usage¶
Visualizing Guidelines boundaries¶
from math import sqrt
from mergeron.core import guidelines_boundaries as gbl
_h_bar = 0.01
conc_boundary = gbl.ConcentrationBoundary(_h_bar, "ΔHHI")
share_boundary = gbl.ConcentrationBoundary(sqrt(2 * _h_bar), "Combined share")
divr_boundary_a = gbl.DiversionRatioBoundary(
gbl.guppi_from_delta(_h_bar, m_star=1.0, r_bar=0.85),
agg_method=gbl.UPPAggrSelector.AVG,
)
divr_boundary_i = gbl.DiversionRatioBoundary(
gbl.guppi_from_delta(_h_bar, m_star=1.0, r_bar=0.85),
agg_method=gbl.UPPAggrSelector.MIN,
)
divr_boundary_x = gbl.DiversionRatioBoundary(
gbl.guppi_from_delta(_h_bar, m_star=1.0, r_bar=0.85),
agg_method=gbl.UPPAggrSelector.MAX,
)
Boundary plots, typically, are written to PDF with backend=”pgf” as the default Matplotlib backend. In Jupyter or Marimo notebooks, use backend=”inline” for inline rendering.
from matplotlib import pyplot as plt
from mergeron.core import guidelines_boundary_functions as gbf
fig, _ = gbf.boundary_plot(plt, backend="inline")
ax = fig.gca()
ax.set_title("Concentration and Diversion Ratio Boundaries")
ax.plot(
conc_boundary.coordinates[:, 0],
conc_boundary.coordinates[:, 1],
color="black",
linestyle="-",
label="ΔHHI",
)
ax.plot(
share_boundary.coordinates[:, 0],
share_boundary.coordinates[:, 1],
color="black",
linestyle=":",
label="Combined share",
)
ax.plot(
divr_boundary_a.coordinates[:, 0],
divr_boundary_a.coordinates[:, 1],
"b-",
label="Average Diversion Ratio",
)
ax.plot(
divr_boundary_i.coordinates[:, 0],
divr_boundary_i.coordinates[:, 1],
"r-",
label="Minimum Diversion Ratio",
)
ax.plot(
divr_boundary_x.coordinates[:, 0],
divr_boundary_x.coordinates[:, 1],
"g-",
label="Maximum Diversion Ratio",
)
_ = fig.legend(loc="upper right", bbox_to_anchor=(0.85, 0.85), frameon=False)
plt.show()

Analyzing FTC Merger Investigations Data¶
Analyze observed enforcement rates reported in various tables presented in published FTC merger investigations data, and in the table aggregates constructed in this package. Note that odd-numbered tables report FTC investigations data organized by HHI and ΔHHI; and even-numbered tables report by firm-count.
from mergeron.core import ftc_merger_investigations_data as fid
from mergeron.gen import enforcement_stats as esl
inv_data = fid.construct_data(fid.INVDATA_ARCHIVE_PATH)
invdata_table_1, invdata_table_2 = (
inv_data[_p]["ByHHIandDelta"]["Table 9.2"]
for _p in ("1996-2003", "2004-2011")
)
counts_by_delta_1, counts_by_delta_2 = (
esl.enf_cnts_bydelta(_t.data_array)
for _t in (invdata_table_1, invdata_table_2)
)
Estimate enforcement rates from reported counts of investigated mergers and enforced mergers.
observed_enforcement_rates = list(
zip(
(
{_v: _k for _k, _v in fid.CONC_DELTA_DICT.items()}[i]
for i in counts_by_delta_1[:, 0]
),
(
f"{_e[1] / _e[-1]:3.2%}" if _e[-1] else "---"
for _e in counts_by_delta_1
),
(
f"{_t[1] / _t[-1]:3.2%}" if _t[-1] else "---"
for _t in counts_by_delta_2
),
)
)
observed_enforcement_rates.append([
"Total",
f"{counts_by_delta_1[:, 1].sum() / counts_by_delta_1[:, -1].sum():3.2%}",
f"{counts_by_delta_2[:, 1].sum() / counts_by_delta_2[:, -1].sum():3.2%}",
])
import tabulate
print(
"Enforcement Rates for Investigated Mergers",
"U. S. Federal Trade Commission",
"1996-2003 vs 2004-2011",
f'Markets with Entry Barriers ("{invdata_table_1.additional_evidence}")',
sep="\n",
)
print()
print(
tabulate.tabulate(
observed_enforcement_rates,
tablefmt="rst",
# tablefmt="html", stralign=None, numalign=None,
maxheadercolwidths=12,
headers=("ΔHHI", "1996-2003", "2004-2011"),
)
)
ΔHHI | 1996-2003 | 2004-2011 |
---|---|---|
0 - 100 | --- | 100.00% |
100 - 200 | 33.33% | 50.00% |
200 - 300 | 33.33% | 50.00% |
300 - 500 | 75.00% | 77.78% |
500 - 800 | 59.09% | 54.55% |
800 - 1,200 | 93.33% | 81.82% |
1,200 - 2,500 | 90.91% | 84.38% |
2,500 + | 96.00% | 100.00% |
Total | 81.65% | 82.86% |
Note
Tables shown here are produced by calling, tabulate.tabulate() with tablefmt=”html”, adding a style sheet, and tagging the printed headings as a caption.
Generating synthetic market data and computing intrinsic enforcement rates¶
Intrinsic clearance rates are deterministic and computed to a high degree of precision by numerical integration with a sufficiently large number of draws. In the source data, only a small proportion of the total falls in certain ranges. Accordingly, 100 million draws provide precision to approximately three (3) decimal places including on ranges within which a small proportion of the sample falls (subject to theoretical numerical precision and the numerical accuracy of modern computers). CPU and wall clock times are reported below for selected examples of enforcement rates.
Table 10.2 reports counts of investigated, “enforced”, and “closed” mergers in markets with barriers to entry categorized by pre-merger firm count, as reported in FTC merger investigations data for 1996-2003. Simulated markets in the examples below are initially drawn such that the relative frequency of draws (simulated markets) by pr-merger firm count matches the relative frequency of markets in Table 10.2 of the report covering FTC merger investigations during 1996-2003 (dropping the “11+” category).
A HSR filing is assumed if the smaller firm is no smaller than the \(n^{th}\) firm in a \(n\)-firm market, and the larger firm is 10 times as large as the \(n^{th}\) firm in the market, or, alternatively, if the smaller merging firm’s share exceeds 10 percent. An alternative specification, mergeron.gen.SSZConstant.HSR_TEN
, maintaining that the smaller merging firm meets the lower threshold in the HSR minimum-size test, is also available. The first approach above, mergeron.gen.SSZConstant.HSR_NTH
, avoids the restriction that the larger merging firm’s revenue share is at least 10 times as large as the smaller merging firm’s revenue share, which is the (unrealistic) implication in the alternative approach, mergeron.gen.SSZConstant.HSR_TEN
, of assuming that always exactly meets the lower threshold in the HSR size test.
from mergeron import RECForm, UPPAggrSelector
from mergeron.gen import (
INVResolution,
PCMDistribution,
PCMRestriction,
PCMSpec,
PriceSpec,
ShareSpec,
SHRDistribution,
SSZConstant,
UPPTestRegime,
)
from mergeron.gen import data_generation as dgl
firm_counts = inv_data["1996-2003"]["ByFirmCount"]["Table 10.2"].data_array
market_sample = dgl.MarketSample(
share_spec=ShareSpec(
dist_type=SHRDistribution.DIR_FLAT,
firm_counts_weights=firm_counts[:, -1][:9],
recapture_form=RECForm.OUTIN,
),
pcm_spec=PCMSpec(
PCMDistribution.EMPR, pcm_restriction=PCMRestriction.MNL
),
price_spec=PriceSpec.SYM,
hsr_filing_test_type=SSZConstant.HSR_NTH,
sample_size=10**8,
)
NOTE: For consistency of generated Firm 2 margins with source data,
respecify PCMSpec with pcm_restriction=PCMRestriction.IID.
In this package, diversion ratios, GUPPI, CMCR, and IPR are all regarded as alternative measures of upward pricing pressure (UPP). This differs from definition of UPP in Farrell-Shapiro, recognizing that antitrust enforcers may use one or more of these measures to estimate the potential that a proposed merger induces a price increase, i.e., that the propose merger leads to a substantially lessening of competition (SLC).
Although the HMG only quantify standards for concentration and combined-share, it can be useful to analyze intrinsic clearance rates for UPP criteria operationalized from Guidelines standards or those suggested in the literature. Below, we use a threshold of 5% for the GUPPI, CMCR, and IPR. The market recapture ratio and diversion threshold are derived from the numbers-equivalent of the post-merger HHI threshold —1800 points—in the 2023 U.S. Merger Guidelines.
guidelines_thresholds = gbl.HMGThresholds(
delta=0.01, fc=6, rec=0.85, guppi=(_g := 0.05), divr=0.15, cmcr=_g, ipr=_g
)
Specify whether analyzing enforcement or clearance rates, and aggregators for the merging firms’ GUPPI and diversion-ratio estimates.
Intrinsic clearance rates do not equal 1 - (intrinsic enforcement rate), as past Guidelines have allowed for a “yellow zone” between so called, “safeharbors” and presumptions of harm. For example, a presumption of harm may trigger if the minimum UPP estimate is greater than a given threshold, whereas the agencies may treat mergers in which the maximum UPP estimate is less than the given threshold.
test_regime = UPPTestRegime(
INVResolution.ENFT, UPPAggrSelector.MIN, UPPAggrSelector.AVG
)
When estimating enforcement rates for a large number of draws (hypothetical mergers), this package allows the user to compute enforcement counts and discard the generated data. Under the latter option, when the specified sample size exceeds 1 million draws, enforcement rate computation is done in parallel over multiple threads, with the data generated in each thread being discarded upon computation of enforcement counts over that (sub)set of draws. This procedure provides memory savings and high performance. The random number generator is configured for repeatability and identically-distributed, non-repeating draws for firm-counts, market shares, margins, and prices, respectively, under the specified distributions.
%%time
market_sample.estimate_enf_counts(guidelines_thresholds, test_regime)
CPU times: user 10h 35min 28s, sys: 8h 56min 31s, total: 19h 32min
Wall time: 4h 29min 35s
import numpy as np
def tabulate_intrinsic_enforcement_rates(
_market_sample: dgl.MarketSample, _guidelines_thresholds: gbl.HMGThresholds
) -> None:
"""Analyze generated data and print intrinsic enforcement rates."""
_enf_count_bydelta = _market_sample.enf_counts.by_delta
_range_counts = _enf_count_bydelta[:, [1]]
intrinsic_enforcement_rates = [
[*_r[:2], *_r[2]]
for _r in zip(
(
{_v: _k for _k, _v in fid.CONC_DELTA_DICT.items()}[_h]
for _h in _enf_count_bydelta[:, 0]
),
(_range_counts.T[0] / _range_counts.sum()).tolist(),
np.divide(_enf_count_bydelta[:, 2:], _range_counts).tolist(),
)
]
intrinsic_enforcement_rates.append([
"Total",
1.00,
*np.divide(
_enf_count_bydelta[:, 2:].sum(axis=0),
_range_counts.sum()).tolist(),
])
print(
tabulate.tabulate(
intrinsic_enforcement_rates,
tablefmt="rst",
# tablefmt="html", stralign=None, numalign=None,
floatfmt="3.2%",
maxheadercolwidths=(_hw := 36),
headers=(
f"{(_hs := f'\0{" " * _hw}')}ΔHHI",
f"Relative {_hs}Frequency",
f"{_hs}GUPPI >= {_guidelines_thresholds.guppi:>1.1%}",
f"GUPPI >= {_guidelines_thresholds.guppi:>1.1%} or {
_hs
}Div. Ratio >= {_guidelines_thresholds.divr:>2.0%}",
f"{_hs}CMCR >= {_guidelines_thresholds.cmcr:>1.1%}",
f"{_hs}IPR >= {_guidelines_thresholds.ipr:>1.1%}",
),
)
)
print(
"Intrinsic Enforcement Rates",
"Hypothetical Mergers in Simulated Product Markets",
"Supplier Price-Cost Margins Drawn from Empirical Distribution",
"Under First-Order Conditions for Nash-Bertrand Equilibrium with MNL Demand",
sep="\n",
)
print()
tabulate_intrinsic_enforcement_rates(market_sample, guidelines_thresholds)
ΔHHI |
Relative Frequency |
GUPPI >= 5.0% |
GUPPI >= 5.0% or Div. Ratio >= 15% |
CMCR >= 5.0% |
IPR >= 5.0% |
---|---|---|---|---|---|
0 - 100 | 0.19% | 0.00% | 11.31% | 14.14% | 0.07% |
100 - 200 | 0.26% | 1.13% | 30.31% | 35.48% | 2.65% |
200 - 300 | 0.75% | 24.16% | 41.93% | 61.67% | 31.15% |
300 - 500 | 3.20% | 38.13% | 61.28% | 73.52% | 50.21% |
500 - 800 | 6.47% | 49.90% | 83.28% | 81.71% | 66.41% |
800 - 1,200 | 9.17% | 59.71% | 91.92% | 87.59% | 77.91% |
1,200 - 2,500 | 26.69% | 66.50% | 95.14% | 91.74% | 85.66% |
2,500 + | 53.27% | 82.93% | 94.67% | 94.76% | 91.10% |
Total | 100.00% | 72.03% | 92.02% | 91.22% | 84.68% |
Merger policy analysis based on share-proportional diversion ratios is generally applicable to differentiated-products mergers, even where customer preferences are not multinomial logit (MNL) in form. This is because implied market shares can be derived from unrestricted diversion ratios by solving the below for \(s_1, s_2\) in terms of diversion shares \(\delta_{ij}, \delta_{ji}\)
Relaxing assumptions from MNL demand, re-compute intrinsic enforcement rates as follows:
market_sample_2 = dgl.MarketSample(
share_spec=ShareSpec(
dist_type=SHRDistribution.UNI, recapture_form=RECForm.FIXED
),
pcm_spec=PCMSpec(
PCMDistribution.EMPR, pcm_restriction=PCMRestriction.IID
),
price_spec=PriceSpec.SYM,
sample_size=10**8,
)
%%time
market_sample_2.estimate_enf_counts(guidelines_thresholds, test_regime)
CPU times: user 5h 36min 11s, sys: 46min 55s, total: 6h 23min 7s
Wall time: 46min 50s
print(
"Intrinsic Enforcement Rates",
"Hypothetical Mergers in Simulated Product Markets",
"Supplier Price-Cost Margins Drawn from Empirical Distribution",
"Independent and Identically Distributed Supplier Margins",
sep='\n'
)
print()
tabulate_intrinsic_enforcement_rates(market_sample_2, guidelines_thresholds)
ΔHHI |
Relative Frequency |
GUPPI >= 5.0% |
GUPPI >= 5.0% or Div. Ratio >= 15% |
CMCR >= 5.0% |
IPR >= 5.0% |
---|---|---|---|---|---|
0 - 100 | 6.29% | 0.54% | 34.29% | 5.20% | 0.61% |
100 - 200 | 4.90% | 2.65% | 47.93% | 28.48% | 3.43% |
200 - 300 | 4.36% | 8.37% | 61.93% | 47.75% | 11.29% |
300 - 500 | 7.76% | 26.64% | 87.19% | 63.54% | 34.58% |
500 - 800 | 10.10% | 57.11% | 100.00% | 81.85% | 66.80% |
800 - 1,200 | 11.58% | 78.85% | 100.00% | 92.04% | 87.61% |
1,200 - 2,500 | 28.36% | 92.88% | 100.00% | 98.43% | 97.68% |
2,500 + | 26.64% | 98.87% | 100.00% | 99.96% | 99.95% |
Total | 100.00% | 70.18% | 90.66% | 82.21% | 74.61% |
Caveat
Intrinsic enforcement rates are not directly comparable to observed enforcement rates in investigated mergers. In practice, if merger screening were effective then proposed mergers in markets with low concentration are not usually investigated unless the agency has evidence or prior experience to believe that a proposed merger is likely to harm competition despite being “cleared” by the screen. Consequently, enforcement rates for investigated mergers in markets with relatively low concentration and change in concentration will be higher than intrinsic enforcement rates for such markets.
On the other hand, when merger enforcement results in effective deterrence, parties only propose presumptively harmful mergers when confident that the presumption is rebutted by the specific facts of their merger. Thus, observed enforcement rates will be lower than intrinsic enforcement rates for proposed mergers that screen as presumptively harmful.
The magnitude of divergence between observed and intrinsic diversion rates is affected not only by the effectiveness of merger screening and deterrence, but also by agency loss aversion, parties’ risk tolerance, litigation risk, and, of course, whether the facts in evidence in respective merger investigations likely rebut a presumption.