mergeron 2024.739104.1__tar.gz → 2024.739105.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mergeron might be problematic. Click here for more details.
- mergeron-2024.739105.2/PKG-INFO +115 -0
- mergeron-2024.739105.2/README.rst +73 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/pyproject.toml +1 -1
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/__init__.py +2 -2
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/core/guidelines_boundaries.py +11 -11
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/gen/__init__.py +26 -26
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/gen/data_generation.py +42 -33
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/gen/data_generation_functions.py +43 -40
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/gen/enforcement_stats.py +12 -12
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/gen/upp_tests.py +9 -10
- mergeron-2024.739104.1/PKG-INFO +0 -102
- mergeron-2024.739104.1/README.rst +0 -60
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/License.txt +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/core/__init__.py +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/core/damodaran_margin_data.py +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/core/ftc_merger_investigations_data.py +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/core/guidelines_boundary_functions.py +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/core/guidelines_boundary_functions_extra.py +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/core/pseudorandom_numbers.py +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/__init__.py +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/damodaran_margin_data.xls +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/damodaran_margin_data_dict.msgpack +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/ftc_invdata.msgpack +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/jinja2_LaTeX_templates/clrrate_cis_summary_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_byhhianddelta_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summary_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summarypaired_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/jinja2_LaTeX_templates/mergeron.cls +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/jinja2_LaTeX_templates/mergeron_table_collection_template.tex.jinja2 +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/data/jinja2_LaTeX_templates/setup_tikz_tables.tex +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/demo/__init__.py +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/demo/visualize_empirical_margin_distribution.py +0 -0
- {mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/py.typed +0 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: mergeron
|
|
3
|
+
Version: 2024.739105.2
|
|
4
|
+
Summary: Merger Policy Analysis using Python
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: merger policy analysis,merger guidelines,merger screening,policy presumptions,concentration standards,upward pricing pressure,GUPPI
|
|
7
|
+
Author: Murthy Kambhampaty
|
|
8
|
+
Author-email: smk@capeconomics.com
|
|
9
|
+
Requires-Python: >=3.12,<4.0
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
21
|
+
Requires-Dist: aenum (>=3.1.15,<4.0.0)
|
|
22
|
+
Requires-Dist: attrs (>=23.2)
|
|
23
|
+
Requires-Dist: bs4 (>=0.0.1)
|
|
24
|
+
Requires-Dist: certifi (>=2023.11.17)
|
|
25
|
+
Requires-Dist: google-re2 (>=1.1)
|
|
26
|
+
Requires-Dist: jinja2 (>=3.1)
|
|
27
|
+
Requires-Dist: joblib (>=1.3)
|
|
28
|
+
Requires-Dist: matplotlib (>=3.8)
|
|
29
|
+
Requires-Dist: mpmath (>=1.3)
|
|
30
|
+
Requires-Dist: msgpack (>=1.0)
|
|
31
|
+
Requires-Dist: msgpack-numpy (>=0.4)
|
|
32
|
+
Requires-Dist: numpy (>=1.26,<2)
|
|
33
|
+
Requires-Dist: scipy (>=1.12)
|
|
34
|
+
Requires-Dist: sympy (>=1.12)
|
|
35
|
+
Requires-Dist: tables (>=3.8)
|
|
36
|
+
Requires-Dist: types-beautifulsoup4 (>=4.11.2)
|
|
37
|
+
Requires-Dist: urllib3 (>=2.2.2,<3.0.0)
|
|
38
|
+
Requires-Dist: xlrd (>=2.0.1,<3.0.0)
|
|
39
|
+
Requires-Dist: xlsxwriter (>=3.1)
|
|
40
|
+
Description-Content-Type: text/x-rst
|
|
41
|
+
|
|
42
|
+
mergeron: Merger Policy Analysis using Python
|
|
43
|
+
=============================================
|
|
44
|
+
|
|
45
|
+
Analyze the sets of mergers conforming to concentration and diversion ratio bounds. Analyze intrinsic enforcement rates, and intrinsic clearance rates, under concentration, diversion ratio, GUPPI, CMCR, and IPR bounds using generated data with specified distributions of market shares, price-cost margins, firm counts, and prices, optionally imposing restrictions implied by statutory filing thresholds and/or Bertrand-Nash oligopoly with MNL demand. Download and 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.
|
|
46
|
+
|
|
47
|
+
Here, enforcement rates derived with merger enforcement as being exogenous to firm conduct are defined as intrinsic enforcement rates, and similarly intrinsic clearance rates. Depending on the merger enforcement regime, or merger control regime, intrinsic enforcement rates may also not be the complement of intrinsic clearance rates, i.e, it is not necessarily true that the intrinsic clearance rate estimate for a given enforcement regime is 1 minus the intrinsic enforcement rate. In contrast, observed enforcement rates reflect the deterrent effects of merger enforcement on firm conduct as well as the effects of merger screening on the level of enforcement; and, by definition, the observed clearance rate is 1 minus the observed enforcement rate.
|
|
48
|
+
|
|
49
|
+
Introduction
|
|
50
|
+
------------
|
|
51
|
+
|
|
52
|
+
Module :code:`.core.guidelines_boundaries` includes classes for specifying concentration bounds (:code:`..core.guidelines_boundaries.ConcentrationBoundary`) and diversion-ratio bounds (:code:`..core.guidelines_boundaries.DiversionRatioBoundary`), with automatic generation of boundary (as an array of share-pairs) and area. This module also includes a function for generating plots of concentration and diversion-ratio boundaries, and functions for mapping GUPPI standards to concentration (ΔHHI) standards, and vice-versa.
|
|
53
|
+
|
|
54
|
+
Module :code:`.gen.data_generation` includes the :code:`.gen.data_generation.MarketSample` which provides for a rich specification of shares and diversion ratios (:code:`.gen.data_generation.MarketSample.share_spec`), margins (:code:`.gen.data_generation.MarketSample.pcm_spec`, prices (:code:`.gen.data_generation.MarketSample.price_spec`), and HSR filing requirements (:code:`.gen.data_generation.MarketSample.hsr_filing_test_type`), and with methods for, (i) generating sample data (:code:`.gen.data_generation.MarketSample.generate_sample`), and (ii) estimating enforcement or clearance rates under specified enforcement regimes given a method of aggregating diversion ratio or GUPPI estimates for the firms in a merger (:code:`.gen.data_generation.MarketSample.estimate_enf_counts`). While the latter populate the properties, :code:`.gen.data_generation.MarketSample.data`
|
|
55
|
+
and :code:`.gen.data_generation.MarketSample.enf_counts`, respectively, the underlying methods for generating standalone :code:`MarketDataSample` and :code:`UPPTestCounts` objects are included in the class definition, with helper functions defined in the modules, :code:`.gen.data_generation_functions` and :code:`.gen.upp_tests`. Notably, market shares are generated for a sample of markets with firm-count distributed as specified in :code:`.gen.data_generation.MarketSample.ShareSpec.firm_count_weights`, with defaults as discussed below (also see, :code:`.gen.ShareSpec.firm_count_weights`.
|
|
56
|
+
|
|
57
|
+
By default, merging-firm shares are drawn with uniform distribution over the space :math:`s_1 + s_2 \leqslant 1` for an unspecified number of firms. Alternatively, shares may be drawn from the Dirichlet distribution, with specified shape parameters (see :code:`.gen.data_generation.MarketSample.ShareSpec`, and, specifically, :code:`.gen.SHRDistribution`). When drawing shares from the Dirichlet distribution, the user passes, using :code:`.gen.data_generation.MarketSample.ShareSpec.firm_count_weights`, a vector of weights specifying the frequency distribution over sequential firm counts, e.g., :code:`[133, 184, 134, 52, 32, 10, 12, 4, 3]` to specify shares drawn from Dirichlet distributions with 2 to 10 pre-merger firms distributed as in data for FTC merger investigations during 1996--2003 (See, for example, Table 4.1 of `FTC, Horizontal Merger Investigations Data, Fiscal Years 1996--2003 (Revised: August 31, 2004) <https://www.ftc.gov/sites/default/files/documents/reports/horizontal-merger-investigation-data-fiscal-years-1996-2003/040831horizmergersdata96-03.pdf>`_). If :code:`.gen.data_generation.MarketSample.ShareSpec.firm_count_weights` is not explicitly assigned a value when defining :code:`.gen.data_generation.MarketSample.ShareSpec`, the default values is used, which results in a sample of markets with 2 to 7 firms with relative frequency in inverse proportion to firm-count, with 2-firm markets being 6 times as likely to be drawn as 7-firm markets.
|
|
58
|
+
|
|
59
|
+
Recapture rates can be specified as, "proportional", "inside-out", "outside-in" (see :code:`.RECForm`. The "inside-out" specification (:code:`.gen.data_generation.MarketSample.ShareSpec.recapture_form`:code:` = `:code:`.RECForm.INOUT`) results in recapture ratios consistent with merging-firms' in-market shares and a default recapture rate. The "outside-in" specification (:code:`.gen.data_generation.MarketSample.ShareSpec.recapture_form`:code:` = `:code:`.RECForm.INOUT`) yields diversion ratios from purchase probabilities drawn at random for :math:`N+1` goods, from which are derived market shares and recapture rates for the :math:`N` goods in the putative market (see, :code:`.gen.ShareSpec`). The "outside-in" specification is invalid when the distribution of markets over firm-count is unspecified, i.e., when :code:`.gen.data_generation.MarketSample.ShareSpec.dist_type`:code:` ==`:code:`.gen.ShareDistributions.UNI`, thus raising a :code:`ValueError` exception. The "proportional" form (:code:`.gen.data_generation.MarketSample.ShareSpec.recapture_form`:code:` = `:code:`.RECForm.FIXED`) is often used in the literature, as an approximation to the "inside-out" form. See, for example, Coate (2011).
|
|
60
|
+
|
|
61
|
+
Price-cost-margins may be specified as having uniform distribution, Beta distribution (including a bounded Beta distribution with specified mean and variance), or an empirical distribution (see, :code:`.gen.PCMSpec`). The empirical margin distribution is based on resampling margin data published by Prof. Damodaran of NYU Stern School of Business (see Notes), using an estimated Gaussian KDE. The second merging firm's margin (:code:`.gen.data_generation.MarketSample.PCMSpec.firm2_pcm_constraint`) may be specified as symmetric, i.i.d., or subject to equilibrium conditions for (profit-maximization in) Bertrand-Nash oligopoly with MNL demand (:code:`.gen.FM2Constraint`).
|
|
62
|
+
|
|
63
|
+
Prices may be specified as symmetric or asymmetric, and in the latter case, the direction of correlation between merging firm prices, if any, can also be specified (see, :code:`.gen.PriceSpec`). Prices may also be defined by imposing cost symmetry on firms in the sample, with fixed unit marginal costs normalized to 1 unit, such that price equal :math:`1 / (1 - \pmb{m})`, where :math:`\pmb{m}` represents the array of margins for firms in the sample.
|
|
64
|
+
|
|
65
|
+
The market sample may be restricted to mergers meeting the HSR filing requirement under two alternative approaches: in the one, the smaller of the two merging firms meets the lower HSR size threshold ($10 million, as adjusted) and the larger of the two merging firms meets the size test if it's share is no less than 10 times the share of the smaller firm. In the other, the :math:`n`-th firm's size is maintained as $10 million, as adjusted (see, :code:`.gen.SSZConstant`), and a merger meets the HSR filing test if either, (a.) the smaller merging firm is no smaller than the n-th firm and the larger merging firm is at 10-times as large as the n-th firm, or (b.) the smaller merging firm's market share is in excess of 10%; in effect this version of the test maintains that if the smaller merging firm's market share exceeds 10%, the value of the transaction exceeds $200 million, as adjusted, and the size-of-person test is eliminated (see, FTC (2008, p. 12); the above are simplifications of the statutory HSR filing requirements). The second assumption avoids the unfortunate assumption in the first that, within the resulting sample, the larger merging firm be at least 10 times as large as the smaller merging firm, as a consequence of the full definition of the HSR filing requirement.
|
|
66
|
+
|
|
67
|
+
The full specification of a market sample is given in a :code:`.gen.data_generation.MarketSample` object, including the above parameters. Data are drawn by invoking :code:`.gen.data_generation.MarketSample.generate_sample` which adds a :code:`data` property of class, :code:`.gen.MarketDataSample`. Enforcement or clearance counts are computed by invoking :code:`.gen.data_generation.MarketSample.estimate_enf_counts`, which adds an :code:`enf_counts` property of class :code:`.gen.UPPTestsCounts`. For fast, parallel generation of enforcement or clearance counts over large market data samples that ordinarily would exceed available limits on machine memory, the user can invoke the method :code:`.gen.data_generation.MarketSample.estimate_enf_counts` on a :code:`.gen.data_generation.MarketSample` object without first invoking :code:`.gen.data_generation.MarketSample.generate_sample`. Note, however, that this strategy does not retain the market sample in memory in the interests of conserving memory and maintaining high performance (the user can specify that the market sample and enforcement statistics be stored to permanent storage; when saving to current PCIe NVMe storage, the performance penalty is slight, but can be considerable if saving to SATA storage).
|
|
68
|
+
|
|
69
|
+
Enforcement statistics based on FTC investigations data and test data are printed to screen or rendered to LaTex files (for processing into publication-quality tables) using methods provided in :code:`.gen.enforcement_stats`.
|
|
70
|
+
|
|
71
|
+
Programs demonstrating the use of this package are included in the sub-package, :code:`.demo`.
|
|
72
|
+
|
|
73
|
+
This package includes a class, :code:`.core.pseudorandom_numbers.MulithreadedRNG` for generating random numbers with selected continuous distribution over specified parameters, and with CPU multithreading on machines with multiple virtual, logical, or physical CPU cores. This class is an adaptation from the documentation of the :code:`numpy` package, from the discussion on `multithreaded random-number generation <https://numpy.org/doc/stable/reference/random/multithreading.html>_`; the version included here permits selection of the distribution with pre-tests to catch and inform on common errors. To access these directly:
|
|
74
|
+
|
|
75
|
+
.. code-block:: python
|
|
76
|
+
|
|
77
|
+
import mergeron.core.pseudorandom_numbers as prng
|
|
78
|
+
|
|
79
|
+
Documentation for this package is in the form of the API Reference. Documentation for individual functions and classes is accessible within a python shell. For example:
|
|
80
|
+
|
|
81
|
+
.. code-block:: python
|
|
82
|
+
|
|
83
|
+
import mergeron.core.market_sample as market_sample
|
|
84
|
+
|
|
85
|
+
help(market_sample.MarketSample)
|
|
86
|
+
|
|
87
|
+
.. rubric:: References
|
|
88
|
+
|
|
89
|
+
.. _coate2011:
|
|
90
|
+
|
|
91
|
+
Coate, M. B. (2011). Benchmarking the upward pricing pressure model with Federal Trade
|
|
92
|
+
Commission evidence. Journal of Competition Law & Economics, 7(4), 825--846. URL: https://doi.org/10.1093/joclec/nhr014.
|
|
93
|
+
|
|
94
|
+
.. _ftc_premerger_guide2:
|
|
95
|
+
|
|
96
|
+
FTC Premerger Notification Office. “To File or Not to File: When You Must File a Premerger Notification Report Form”. 2008 (September, revised). URL: https://www.ftc.gov/sites/default/files/attachments/premerger-introductory-guides/guide2.pdf
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
.. image:: https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json
|
|
100
|
+
:alt: Poetry
|
|
101
|
+
:target: https://python-poetry.org/
|
|
102
|
+
|
|
103
|
+
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
|
104
|
+
:alt: Ruff
|
|
105
|
+
:target: https://github.com/astral-sh/ruff
|
|
106
|
+
|
|
107
|
+
.. image:: https://www.mypy-lang.org/static/mypy_badge.svg
|
|
108
|
+
:alt: Checked with mypy
|
|
109
|
+
:target: https://mypy-lang.org/
|
|
110
|
+
|
|
111
|
+
.. image:: https://img.shields.io/badge/License-MIT-yellow.svg
|
|
112
|
+
:alt: License: MIT
|
|
113
|
+
:target: https://opensource.org/licenses/MIT
|
|
114
|
+
|
|
115
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
mergeron: Merger Policy Analysis using Python
|
|
2
|
+
=============================================
|
|
3
|
+
|
|
4
|
+
Analyze the sets of mergers conforming to concentration and diversion ratio bounds. Analyze intrinsic enforcement rates, and intrinsic clearance rates, under concentration, diversion ratio, GUPPI, CMCR, and IPR bounds using generated data with specified distributions of market shares, price-cost margins, firm counts, and prices, optionally imposing restrictions implied by statutory filing thresholds and/or Bertrand-Nash oligopoly with MNL demand. Download and 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.
|
|
5
|
+
|
|
6
|
+
Here, enforcement rates derived with merger enforcement as being exogenous to firm conduct are defined as intrinsic enforcement rates, and similarly intrinsic clearance rates. Depending on the merger enforcement regime, or merger control regime, intrinsic enforcement rates may also not be the complement of intrinsic clearance rates, i.e, it is not necessarily true that the intrinsic clearance rate estimate for a given enforcement regime is 1 minus the intrinsic enforcement rate. In contrast, observed enforcement rates reflect the deterrent effects of merger enforcement on firm conduct as well as the effects of merger screening on the level of enforcement; and, by definition, the observed clearance rate is 1 minus the observed enforcement rate.
|
|
7
|
+
|
|
8
|
+
Introduction
|
|
9
|
+
------------
|
|
10
|
+
|
|
11
|
+
Module :code:`.core.guidelines_boundaries` includes classes for specifying concentration bounds (:code:`..core.guidelines_boundaries.ConcentrationBoundary`) and diversion-ratio bounds (:code:`..core.guidelines_boundaries.DiversionRatioBoundary`), with automatic generation of boundary (as an array of share-pairs) and area. This module also includes a function for generating plots of concentration and diversion-ratio boundaries, and functions for mapping GUPPI standards to concentration (ΔHHI) standards, and vice-versa.
|
|
12
|
+
|
|
13
|
+
Module :code:`.gen.data_generation` includes the :code:`.gen.data_generation.MarketSample` which provides for a rich specification of shares and diversion ratios (:code:`.gen.data_generation.MarketSample.share_spec`), margins (:code:`.gen.data_generation.MarketSample.pcm_spec`, prices (:code:`.gen.data_generation.MarketSample.price_spec`), and HSR filing requirements (:code:`.gen.data_generation.MarketSample.hsr_filing_test_type`), and with methods for, (i) generating sample data (:code:`.gen.data_generation.MarketSample.generate_sample`), and (ii) estimating enforcement or clearance rates under specified enforcement regimes given a method of aggregating diversion ratio or GUPPI estimates for the firms in a merger (:code:`.gen.data_generation.MarketSample.estimate_enf_counts`). While the latter populate the properties, :code:`.gen.data_generation.MarketSample.data`
|
|
14
|
+
and :code:`.gen.data_generation.MarketSample.enf_counts`, respectively, the underlying methods for generating standalone :code:`MarketDataSample` and :code:`UPPTestCounts` objects are included in the class definition, with helper functions defined in the modules, :code:`.gen.data_generation_functions` and :code:`.gen.upp_tests`. Notably, market shares are generated for a sample of markets with firm-count distributed as specified in :code:`.gen.data_generation.MarketSample.ShareSpec.firm_count_weights`, with defaults as discussed below (also see, :code:`.gen.ShareSpec.firm_count_weights`.
|
|
15
|
+
|
|
16
|
+
By default, merging-firm shares are drawn with uniform distribution over the space :math:`s_1 + s_2 \leqslant 1` for an unspecified number of firms. Alternatively, shares may be drawn from the Dirichlet distribution, with specified shape parameters (see :code:`.gen.data_generation.MarketSample.ShareSpec`, and, specifically, :code:`.gen.SHRDistribution`). When drawing shares from the Dirichlet distribution, the user passes, using :code:`.gen.data_generation.MarketSample.ShareSpec.firm_count_weights`, a vector of weights specifying the frequency distribution over sequential firm counts, e.g., :code:`[133, 184, 134, 52, 32, 10, 12, 4, 3]` to specify shares drawn from Dirichlet distributions with 2 to 10 pre-merger firms distributed as in data for FTC merger investigations during 1996--2003 (See, for example, Table 4.1 of `FTC, Horizontal Merger Investigations Data, Fiscal Years 1996--2003 (Revised: August 31, 2004) <https://www.ftc.gov/sites/default/files/documents/reports/horizontal-merger-investigation-data-fiscal-years-1996-2003/040831horizmergersdata96-03.pdf>`_). If :code:`.gen.data_generation.MarketSample.ShareSpec.firm_count_weights` is not explicitly assigned a value when defining :code:`.gen.data_generation.MarketSample.ShareSpec`, the default values is used, which results in a sample of markets with 2 to 7 firms with relative frequency in inverse proportion to firm-count, with 2-firm markets being 6 times as likely to be drawn as 7-firm markets.
|
|
17
|
+
|
|
18
|
+
Recapture rates can be specified as, "proportional", "inside-out", "outside-in" (see :code:`.RECForm`. The "inside-out" specification (:code:`.gen.data_generation.MarketSample.ShareSpec.recapture_form`:code:` = `:code:`.RECForm.INOUT`) results in recapture ratios consistent with merging-firms' in-market shares and a default recapture rate. The "outside-in" specification (:code:`.gen.data_generation.MarketSample.ShareSpec.recapture_form`:code:` = `:code:`.RECForm.INOUT`) yields diversion ratios from purchase probabilities drawn at random for :math:`N+1` goods, from which are derived market shares and recapture rates for the :math:`N` goods in the putative market (see, :code:`.gen.ShareSpec`). The "outside-in" specification is invalid when the distribution of markets over firm-count is unspecified, i.e., when :code:`.gen.data_generation.MarketSample.ShareSpec.dist_type`:code:` ==`:code:`.gen.ShareDistributions.UNI`, thus raising a :code:`ValueError` exception. The "proportional" form (:code:`.gen.data_generation.MarketSample.ShareSpec.recapture_form`:code:` = `:code:`.RECForm.FIXED`) is often used in the literature, as an approximation to the "inside-out" form. See, for example, Coate (2011).
|
|
19
|
+
|
|
20
|
+
Price-cost-margins may be specified as having uniform distribution, Beta distribution (including a bounded Beta distribution with specified mean and variance), or an empirical distribution (see, :code:`.gen.PCMSpec`). The empirical margin distribution is based on resampling margin data published by Prof. Damodaran of NYU Stern School of Business (see Notes), using an estimated Gaussian KDE. The second merging firm's margin (:code:`.gen.data_generation.MarketSample.PCMSpec.firm2_pcm_constraint`) may be specified as symmetric, i.i.d., or subject to equilibrium conditions for (profit-maximization in) Bertrand-Nash oligopoly with MNL demand (:code:`.gen.FM2Constraint`).
|
|
21
|
+
|
|
22
|
+
Prices may be specified as symmetric or asymmetric, and in the latter case, the direction of correlation between merging firm prices, if any, can also be specified (see, :code:`.gen.PriceSpec`). Prices may also be defined by imposing cost symmetry on firms in the sample, with fixed unit marginal costs normalized to 1 unit, such that price equal :math:`1 / (1 - \pmb{m})`, where :math:`\pmb{m}` represents the array of margins for firms in the sample.
|
|
23
|
+
|
|
24
|
+
The market sample may be restricted to mergers meeting the HSR filing requirement under two alternative approaches: in the one, the smaller of the two merging firms meets the lower HSR size threshold ($10 million, as adjusted) and the larger of the two merging firms meets the size test if it's share is no less than 10 times the share of the smaller firm. In the other, the :math:`n`-th firm's size is maintained as $10 million, as adjusted (see, :code:`.gen.SSZConstant`), and a merger meets the HSR filing test if either, (a.) the smaller merging firm is no smaller than the n-th firm and the larger merging firm is at 10-times as large as the n-th firm, or (b.) the smaller merging firm's market share is in excess of 10%; in effect this version of the test maintains that if the smaller merging firm's market share exceeds 10%, the value of the transaction exceeds $200 million, as adjusted, and the size-of-person test is eliminated (see, FTC (2008, p. 12); the above are simplifications of the statutory HSR filing requirements). The second assumption avoids the unfortunate assumption in the first that, within the resulting sample, the larger merging firm be at least 10 times as large as the smaller merging firm, as a consequence of the full definition of the HSR filing requirement.
|
|
25
|
+
|
|
26
|
+
The full specification of a market sample is given in a :code:`.gen.data_generation.MarketSample` object, including the above parameters. Data are drawn by invoking :code:`.gen.data_generation.MarketSample.generate_sample` which adds a :code:`data` property of class, :code:`.gen.MarketDataSample`. Enforcement or clearance counts are computed by invoking :code:`.gen.data_generation.MarketSample.estimate_enf_counts`, which adds an :code:`enf_counts` property of class :code:`.gen.UPPTestsCounts`. For fast, parallel generation of enforcement or clearance counts over large market data samples that ordinarily would exceed available limits on machine memory, the user can invoke the method :code:`.gen.data_generation.MarketSample.estimate_enf_counts` on a :code:`.gen.data_generation.MarketSample` object without first invoking :code:`.gen.data_generation.MarketSample.generate_sample`. Note, however, that this strategy does not retain the market sample in memory in the interests of conserving memory and maintaining high performance (the user can specify that the market sample and enforcement statistics be stored to permanent storage; when saving to current PCIe NVMe storage, the performance penalty is slight, but can be considerable if saving to SATA storage).
|
|
27
|
+
|
|
28
|
+
Enforcement statistics based on FTC investigations data and test data are printed to screen or rendered to LaTex files (for processing into publication-quality tables) using methods provided in :code:`.gen.enforcement_stats`.
|
|
29
|
+
|
|
30
|
+
Programs demonstrating the use of this package are included in the sub-package, :code:`.demo`.
|
|
31
|
+
|
|
32
|
+
This package includes a class, :code:`.core.pseudorandom_numbers.MulithreadedRNG` for generating random numbers with selected continuous distribution over specified parameters, and with CPU multithreading on machines with multiple virtual, logical, or physical CPU cores. This class is an adaptation from the documentation of the :code:`numpy` package, from the discussion on `multithreaded random-number generation <https://numpy.org/doc/stable/reference/random/multithreading.html>_`; the version included here permits selection of the distribution with pre-tests to catch and inform on common errors. To access these directly:
|
|
33
|
+
|
|
34
|
+
.. code-block:: python
|
|
35
|
+
|
|
36
|
+
import mergeron.core.pseudorandom_numbers as prng
|
|
37
|
+
|
|
38
|
+
Documentation for this package is in the form of the API Reference. Documentation for individual functions and classes is accessible within a python shell. For example:
|
|
39
|
+
|
|
40
|
+
.. code-block:: python
|
|
41
|
+
|
|
42
|
+
import mergeron.core.market_sample as market_sample
|
|
43
|
+
|
|
44
|
+
help(market_sample.MarketSample)
|
|
45
|
+
|
|
46
|
+
.. rubric:: References
|
|
47
|
+
|
|
48
|
+
.. _coate2011:
|
|
49
|
+
|
|
50
|
+
Coate, M. B. (2011). Benchmarking the upward pricing pressure model with Federal Trade
|
|
51
|
+
Commission evidence. Journal of Competition Law & Economics, 7(4), 825--846. URL: https://doi.org/10.1093/joclec/nhr014.
|
|
52
|
+
|
|
53
|
+
.. _ftc_premerger_guide2:
|
|
54
|
+
|
|
55
|
+
FTC Premerger Notification Office. “To File or Not to File: When You Must File a Premerger Notification Report Form”. 2008 (September, revised). URL: https://www.ftc.gov/sites/default/files/attachments/premerger-introductory-guides/guide2.pdf
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
.. image:: https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json
|
|
59
|
+
:alt: Poetry
|
|
60
|
+
:target: https://python-poetry.org/
|
|
61
|
+
|
|
62
|
+
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
|
63
|
+
:alt: Ruff
|
|
64
|
+
:target: https://github.com/astral-sh/ruff
|
|
65
|
+
|
|
66
|
+
.. image:: https://www.mypy-lang.org/static/mypy_badge.svg
|
|
67
|
+
:alt: Checked with mypy
|
|
68
|
+
:target: https://mypy-lang.org/
|
|
69
|
+
|
|
70
|
+
.. image:: https://img.shields.io/badge/License-MIT-yellow.svg
|
|
71
|
+
:alt: License: MIT
|
|
72
|
+
:target: https://opensource.org/licenses/MIT
|
|
73
|
+
|
|
@@ -9,7 +9,7 @@ from numpy.typing import NDArray
|
|
|
9
9
|
|
|
10
10
|
_PKG_NAME: str = Path(__file__).parent.stem
|
|
11
11
|
|
|
12
|
-
VERSION = "2024.
|
|
12
|
+
VERSION = "2024.739105.2"
|
|
13
13
|
|
|
14
14
|
__version__ = VERSION
|
|
15
15
|
|
|
@@ -36,7 +36,7 @@ ArrayBIGINT: TypeAlias = NDArray[np.int64]
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
@enum.unique
|
|
39
|
-
class
|
|
39
|
+
class RECForm(enum.StrEnum):
|
|
40
40
|
"""Recapture rate - derivation methods."""
|
|
41
41
|
|
|
42
42
|
INOUT = "inside-out"
|
{mergeron-2024.739104.1 → mergeron-2024.739105.2}/src/mergeron/core/guidelines_boundaries.py
RENAMED
|
@@ -13,7 +13,7 @@ import numpy as np
|
|
|
13
13
|
from attrs import Attribute, field, frozen, validators
|
|
14
14
|
from mpmath import mp, mpf # type: ignore
|
|
15
15
|
|
|
16
|
-
from .. import VERSION, ArrayDouble,
|
|
16
|
+
from .. import VERSION, ArrayDouble, RECForm, UPPAggrSelector # noqa: TID252
|
|
17
17
|
from . import guidelines_boundary_functions as gbfn
|
|
18
18
|
|
|
19
19
|
__version__ = VERSION
|
|
@@ -223,14 +223,14 @@ def _divr_value_validator(
|
|
|
223
223
|
|
|
224
224
|
def _rec_spec_validator(
|
|
225
225
|
_instance: DiversionRatioBoundary,
|
|
226
|
-
_attribute: Attribute[
|
|
227
|
-
_value:
|
|
226
|
+
_attribute: Attribute[RECForm],
|
|
227
|
+
_value: RECForm,
|
|
228
228
|
/,
|
|
229
229
|
) -> None:
|
|
230
|
-
if _value ==
|
|
230
|
+
if _value == RECForm.OUTIN and _instance.recapture_rate:
|
|
231
231
|
raise ValueError(
|
|
232
232
|
f"Invalid recapture specification, {_value!r}. "
|
|
233
|
-
"You may consider specifying `mergeron.
|
|
233
|
+
"You may consider specifying `mergeron.RECForm.INOUT` here, and "
|
|
234
234
|
'assigning the default recapture rate as attribute, "recapture_rate" of '
|
|
235
235
|
"this `DiversionRatioBoundarySpec` object."
|
|
236
236
|
)
|
|
@@ -265,24 +265,24 @@ class DiversionRatioBoundary:
|
|
|
265
265
|
kw_only=False, default=0.85, validator=validators.instance_of(float)
|
|
266
266
|
)
|
|
267
267
|
|
|
268
|
-
recapture_form:
|
|
268
|
+
recapture_form: RECForm | None = field(
|
|
269
269
|
kw_only=True,
|
|
270
|
-
default=
|
|
270
|
+
default=RECForm.INOUT,
|
|
271
271
|
validator=(
|
|
272
|
-
validators.instance_of((type(None),
|
|
272
|
+
validators.instance_of((type(None), RECForm)),
|
|
273
273
|
_rec_spec_validator,
|
|
274
274
|
),
|
|
275
275
|
)
|
|
276
276
|
"""
|
|
277
277
|
The form of the recapture rate.
|
|
278
278
|
|
|
279
|
-
When :attr:`mergeron.
|
|
279
|
+
When :attr:`mergeron.RECForm.INOUT`, the recapture rate for
|
|
280
280
|
he product having the smaller market-share is assumed to equal the default,
|
|
281
281
|
and the recapture rate for the product with the larger market-share is
|
|
282
282
|
computed assuming MNL demand. Fixed recapture rates are specified as
|
|
283
|
-
:attr:`mergeron.
|
|
283
|
+
:attr:`mergeron.RECForm.FIXED`. (To specify that recapture rates be
|
|
284
284
|
constructed from the generated purchase-probabilities for products in
|
|
285
|
-
the market and for the outside good, specify :attr:`mergeron.
|
|
285
|
+
the market and for the outside good, specify :attr:`mergeron.RECForm.OUTIN`.)
|
|
286
286
|
|
|
287
287
|
The GUPPI boundary is a continuum of diversion ratio boundaries conditional on
|
|
288
288
|
price-cost margins, :math:`d_{ij} = g_i * p_i / (m_j * p_j)`,
|
|
@@ -21,7 +21,7 @@ from .. import ( # noqa: TID252
|
|
|
21
21
|
ArrayDouble,
|
|
22
22
|
ArrayFloat,
|
|
23
23
|
ArrayINT,
|
|
24
|
-
|
|
24
|
+
RECForm,
|
|
25
25
|
UPPAggrSelector,
|
|
26
26
|
)
|
|
27
27
|
from ..core.pseudorandom_numbers import DIST_PARMS_DEFAULT # noqa: TID252
|
|
@@ -57,7 +57,7 @@ class PriceSpec(tuple[bool, str | None], enum.ReprEnum):
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
@enum.unique
|
|
60
|
-
class
|
|
60
|
+
class SHRDistribution(enum.StrEnum):
|
|
61
61
|
"""Market share distributions."""
|
|
62
62
|
|
|
63
63
|
UNI = "Uniform"
|
|
@@ -98,26 +98,26 @@ class ShareSpec:
|
|
|
98
98
|
A key feature of market-share specification in this package is that
|
|
99
99
|
the draws represent markets with multiple different firm-counts.
|
|
100
100
|
Firm-counts are unspecified if the share distribution is
|
|
101
|
-
:attr:`mergeron.
|
|
101
|
+
:attr:`mergeron.SHRDistribution.UNI`, for Dirichlet-distributed market-shares,
|
|
102
102
|
the default specification is that firm-counts vary between
|
|
103
103
|
2 and 7 firms with each value equally likely.
|
|
104
104
|
|
|
105
105
|
Notes
|
|
106
106
|
-----
|
|
107
|
-
If :attr:`mergeron.gen.ShareSpec.dist_type`:code:` == `:attr:`mergeron.gen.
|
|
107
|
+
If :attr:`mergeron.gen.ShareSpec.dist_type`:code:` == `:attr:`mergeron.gen.SHRDistribution.UNI`,
|
|
108
108
|
then it is infeasible that
|
|
109
|
-
:attr:`mergeron.gen.ShareSpec.recapture_form`:code:` == `:attr:`mergeron.
|
|
109
|
+
:attr:`mergeron.gen.ShareSpec.recapture_form`:code:` == `:attr:`mergeron.RECForm.OUTIN`.
|
|
110
110
|
In other words, if firm-counts are unspecified, the recapture rate cannot be
|
|
111
111
|
estimated using outside good choice probabilities.
|
|
112
112
|
|
|
113
113
|
For a sample with explicit firm counts, market shares must
|
|
114
114
|
be specified as having a supported Dirichlet distribution
|
|
115
|
-
(see :class:`mergeron.gen.
|
|
115
|
+
(see :class:`mergeron.gen.SHRDistribution`).
|
|
116
116
|
|
|
117
117
|
"""
|
|
118
118
|
|
|
119
|
-
dist_type:
|
|
120
|
-
"""See :class:`
|
|
119
|
+
dist_type: SHRDistribution
|
|
120
|
+
"""See :class:`SHRDistribution`"""
|
|
121
121
|
|
|
122
122
|
dist_parms: ArrayDouble | None = field(
|
|
123
123
|
default=None, eq=cmp_using(eq=np.array_equal)
|
|
@@ -143,22 +143,22 @@ class ShareSpec:
|
|
|
143
143
|
|
|
144
144
|
@firm_counts_weights.validator
|
|
145
145
|
def _check_fcw(_i: ShareSpec, _a: Attribute[ArrayDouble], _v: ArrayDouble) -> None:
|
|
146
|
-
if _v is not None and _i.dist_type ==
|
|
146
|
+
if _v is not None and _i.dist_type == SHRDistribution.UNI:
|
|
147
147
|
raise ValueError(
|
|
148
148
|
"Generated data for markets with specified firm-counts or "
|
|
149
149
|
"varying firm counts are not feasible for market shares "
|
|
150
150
|
"with Uniform distribution. Consider revising the "
|
|
151
|
-
r"distribution type to {
|
|
151
|
+
r"distribution type to {SHRDistribution.DIR_FLAT}, which gives "
|
|
152
152
|
"uniformly distributed draws on the :math:`n+1` simplex "
|
|
153
153
|
"for firm-count, :math:`n`."
|
|
154
154
|
)
|
|
155
155
|
|
|
156
|
-
recapture_form:
|
|
157
|
-
"""See :class:`mergeron.
|
|
156
|
+
recapture_form: RECForm = field(default=RECForm.INOUT)
|
|
157
|
+
"""See :class:`mergeron.RECForm`"""
|
|
158
158
|
|
|
159
159
|
@recapture_form.validator
|
|
160
|
-
def _check_rf(_i: ShareSpec, _a: Attribute[
|
|
161
|
-
if _v ==
|
|
160
|
+
def _check_rf(_i: ShareSpec, _a: Attribute[RECForm], _v: RECForm) -> None:
|
|
161
|
+
if _v == RECForm.OUTIN and _i.dist_type == SHRDistribution.UNI:
|
|
162
162
|
raise ValueError(
|
|
163
163
|
"Market share specification requires estimation of recapture rate from "
|
|
164
164
|
"generated data. Either delete recapture rate specification or set it to None."
|
|
@@ -168,7 +168,7 @@ class ShareSpec:
|
|
|
168
168
|
"""A value between 0 and 1, typically 0.8.
|
|
169
169
|
|
|
170
170
|
:code:`None` if market share specification requires direct generation of
|
|
171
|
-
outside good choice probabilities (:attr:`mergeron.
|
|
171
|
+
outside good choice probabilities (:attr:`mergeron.RECForm.OUTIN`).
|
|
172
172
|
|
|
173
173
|
The recapture rate is usually calibrated to the numbers-equivalent of the
|
|
174
174
|
HHI threshold for the presumtion of harm from unilateral competitive effects
|
|
@@ -191,7 +191,7 @@ class ShareSpec:
|
|
|
191
191
|
def _check_rr(_i: ShareSpec, _a: Attribute[float], _v: float) -> None:
|
|
192
192
|
if _v and not (0 < _v <= 1):
|
|
193
193
|
raise ValueError("Recapture rate must lie in the interval, [0, 1).")
|
|
194
|
-
elif _v is None and _i.recapture_form !=
|
|
194
|
+
elif _v is None and _i.recapture_form != RECForm.OUTIN:
|
|
195
195
|
raise ValueError(
|
|
196
196
|
f"Recapture specification, {_i.recapture_form!r} requires that "
|
|
197
197
|
"the market sample specification inclues a recapture rate in the "
|
|
@@ -200,7 +200,7 @@ class ShareSpec:
|
|
|
200
200
|
|
|
201
201
|
|
|
202
202
|
@enum.unique
|
|
203
|
-
class
|
|
203
|
+
class PCMDistribution(enum.StrEnum):
|
|
204
204
|
"""Margin distributions."""
|
|
205
205
|
|
|
206
206
|
UNI = "Uniform"
|
|
@@ -210,7 +210,7 @@ class PCMDistributions(enum.StrEnum):
|
|
|
210
210
|
|
|
211
211
|
|
|
212
212
|
@enum.unique
|
|
213
|
-
class
|
|
213
|
+
class FM2Constraint(enum.StrEnum):
|
|
214
214
|
"""Firm 2 margins - derivation methods."""
|
|
215
215
|
|
|
216
216
|
IID = "i.i.d"
|
|
@@ -234,8 +234,8 @@ class PCMSpec:
|
|
|
234
234
|
|
|
235
235
|
"""
|
|
236
236
|
|
|
237
|
-
dist_type:
|
|
238
|
-
"""See :class:`
|
|
237
|
+
dist_type: PCMDistribution = field(kw_only=False, default=PCMDistribution.UNI)
|
|
238
|
+
"""See :class:`PCMDistribution`"""
|
|
239
239
|
|
|
240
240
|
dist_parms: ArrayDouble | None = field(kw_only=False, default=None)
|
|
241
241
|
"""Parameter specification for tailoring PCM distribution
|
|
@@ -260,9 +260,9 @@ class PCMSpec:
|
|
|
260
260
|
"are not valid with margin distribution, {_dist_type_pcm!r}"
|
|
261
261
|
)
|
|
262
262
|
elif (
|
|
263
|
-
_i.dist_type ==
|
|
263
|
+
_i.dist_type == PCMDistribution.BETA and len(_v) != len(("a", "b"))
|
|
264
264
|
) or (
|
|
265
|
-
_i.dist_type ==
|
|
265
|
+
_i.dist_type == PCMDistribution.BETA_BND
|
|
266
266
|
and len(_v) != len(("mu", "sigma", "max", "min"))
|
|
267
267
|
):
|
|
268
268
|
raise ValueError(
|
|
@@ -270,18 +270,18 @@ class PCMSpec:
|
|
|
270
270
|
f'for PCM with distribution, "{_i.dist_type}" is incorrect.'
|
|
271
271
|
)
|
|
272
272
|
|
|
273
|
-
elif _i.dist_type ==
|
|
273
|
+
elif _i.dist_type == PCMDistribution.EMPR and _v is not None:
|
|
274
274
|
raise ValueError(
|
|
275
275
|
f"Empirical distribution does not require additional parameters; "
|
|
276
276
|
f'"given value, {_v!r} is ignored."'
|
|
277
277
|
)
|
|
278
278
|
|
|
279
|
-
firm2_pcm_constraint:
|
|
280
|
-
"""See :class:`
|
|
279
|
+
firm2_pcm_constraint: FM2Constraint = field(kw_only=False, default=FM2Constraint.IID)
|
|
280
|
+
"""See :class:`FM2Constraint`"""
|
|
281
281
|
|
|
282
282
|
|
|
283
283
|
@enum.unique
|
|
284
|
-
class
|
|
284
|
+
class SSZConstant(float, enum.ReprEnum):
|
|
285
285
|
"""
|
|
286
286
|
Scale factors to offset sample size reduction.
|
|
287
287
|
|
|
@@ -13,18 +13,18 @@ from attrs import Attribute, define, field, validators
|
|
|
13
13
|
from joblib import Parallel, cpu_count, delayed # type: ignore
|
|
14
14
|
from numpy.random import SeedSequence
|
|
15
15
|
|
|
16
|
-
from .. import VERSION,
|
|
16
|
+
from .. import VERSION, RECForm # noqa: TID252 # noqa
|
|
17
17
|
from ..core import guidelines_boundaries as gbl # noqa: TID252
|
|
18
18
|
from ..core.guidelines_boundaries import HMGThresholds # noqa: TID252
|
|
19
19
|
from . import (
|
|
20
|
-
|
|
20
|
+
FM2Constraint,
|
|
21
21
|
MarketDataSample,
|
|
22
|
-
|
|
22
|
+
PCMDistribution,
|
|
23
23
|
PCMSpec,
|
|
24
24
|
PriceSpec,
|
|
25
25
|
ShareSpec,
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
SHRDistribution,
|
|
27
|
+
SSZConstant,
|
|
28
28
|
UPPTestRegime,
|
|
29
29
|
UPPTestsCounts,
|
|
30
30
|
)
|
|
@@ -40,7 +40,7 @@ __version__ = VERSION
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
class SamplingFunctionKWArgs(TypedDict, total=False):
|
|
43
|
-
"Keyword arguments of
|
|
43
|
+
"Keyword arguments of sampling methods defined below"
|
|
44
44
|
|
|
45
45
|
sample_size: int
|
|
46
46
|
"""number of draws to generate"""
|
|
@@ -73,26 +73,26 @@ class MarketSample:
|
|
|
73
73
|
|
|
74
74
|
share_spec: ShareSpec = field(
|
|
75
75
|
kw_only=True,
|
|
76
|
-
default=ShareSpec(
|
|
76
|
+
default=ShareSpec(SHRDistribution.UNI, None, None, RECForm.INOUT, 0.8),
|
|
77
77
|
validator=validators.instance_of(ShareSpec),
|
|
78
78
|
)
|
|
79
79
|
"""Market-share specification, see :class:`ShareSpec`"""
|
|
80
80
|
|
|
81
81
|
pcm_spec: PCMSpec = field(
|
|
82
|
-
kw_only=True, default=PCMSpec(
|
|
82
|
+
kw_only=True, default=PCMSpec(PCMDistribution.UNI, None, FM2Constraint.IID)
|
|
83
83
|
)
|
|
84
84
|
"""Margin specification, see :class:`PCMSpec`"""
|
|
85
85
|
|
|
86
86
|
@pcm_spec.validator
|
|
87
87
|
def _check_pcm(self, _a: Attribute[PCMSpec], _v: PCMSpec, /) -> None:
|
|
88
88
|
if (
|
|
89
|
-
self.share_spec.recapture_form ==
|
|
90
|
-
and _v.firm2_pcm_constraint ==
|
|
89
|
+
self.share_spec.recapture_form == RECForm.FIXED
|
|
90
|
+
and _v.firm2_pcm_constraint == FM2Constraint.MNL
|
|
91
91
|
):
|
|
92
92
|
raise ValueError(
|
|
93
93
|
f'Specification of "recapture_form", "{self.share_spec.recapture_form}" '
|
|
94
94
|
"requires Firm 2 margin must have property, "
|
|
95
|
-
f'"{
|
|
95
|
+
f'"{FM2Constraint.IID}" or "{FM2Constraint.SYM}".'
|
|
96
96
|
)
|
|
97
97
|
|
|
98
98
|
price_spec: PriceSpec = field(
|
|
@@ -100,12 +100,12 @@ class MarketSample:
|
|
|
100
100
|
)
|
|
101
101
|
"""Price specification, see :class:`PriceSpec`"""
|
|
102
102
|
|
|
103
|
-
hsr_filing_test_type:
|
|
103
|
+
hsr_filing_test_type: SSZConstant = field(
|
|
104
104
|
kw_only=True,
|
|
105
|
-
default=
|
|
106
|
-
validator=validators.instance_of(
|
|
105
|
+
default=SSZConstant.ONE,
|
|
106
|
+
validator=validators.instance_of(SSZConstant),
|
|
107
107
|
)
|
|
108
|
-
"""Method for modeling HSR filing threholds, see :class:`
|
|
108
|
+
"""Method for modeling HSR filing threholds, see :class:`SSZConstant`"""
|
|
109
109
|
|
|
110
110
|
data: MarketDataSample = field(default=None)
|
|
111
111
|
|
|
@@ -124,7 +124,7 @@ class MarketSample:
|
|
|
124
124
|
"""
|
|
125
125
|
Generate share, diversion ratio, price, and margin data for MarketSpec.
|
|
126
126
|
|
|
127
|
-
see :attr:`SamplingFunctionKWArgs` for description of parameters
|
|
127
|
+
see :attr:`SamplingFunctionKWArgs` for description of keyord parameters
|
|
128
128
|
|
|
129
129
|
Returns
|
|
130
130
|
-------
|
|
@@ -149,8 +149,8 @@ class MarketSample:
|
|
|
149
149
|
_shr_sample_size = 1.0 * sample_size
|
|
150
150
|
# Scale up sample size to offset discards based on specified criteria
|
|
151
151
|
_shr_sample_size *= _hsr_filing_test_type
|
|
152
|
-
if _dist_firm2_pcm ==
|
|
153
|
-
_shr_sample_size *=
|
|
152
|
+
if _dist_firm2_pcm == FM2Constraint.MNL:
|
|
153
|
+
_shr_sample_size *= SSZConstant.MNL_DEP
|
|
154
154
|
_shr_sample_size = int(_shr_sample_size)
|
|
155
155
|
|
|
156
156
|
# Generate share data
|
|
@@ -195,7 +195,7 @@ class MarketSample:
|
|
|
195
195
|
|
|
196
196
|
_mnl_test_rows = _mnl_test_rows * _hsr_filing_test
|
|
197
197
|
_s_size = sample_size # originally-specified sample size
|
|
198
|
-
if _dist_firm2_pcm ==
|
|
198
|
+
if _dist_firm2_pcm == FM2Constraint.MNL:
|
|
199
199
|
_mktshr_array = _mktshr_array[_mnl_test_rows][:_s_size]
|
|
200
200
|
_pcm_array = _pcm_array[_mnl_test_rows][:_s_size]
|
|
201
201
|
_price_array = _price_array[_mnl_test_rows][:_s_size]
|
|
@@ -240,13 +240,21 @@ class MarketSample:
|
|
|
240
240
|
self,
|
|
241
241
|
/,
|
|
242
242
|
*,
|
|
243
|
-
sample_size: int
|
|
244
|
-
seed_seq_list:
|
|
243
|
+
sample_size: int,
|
|
244
|
+
seed_seq_list: Sequence[SeedSequence],
|
|
245
245
|
nthreads: int,
|
|
246
|
-
save_data_to_file: SaveData
|
|
247
|
-
saved_array_name_suffix: str
|
|
246
|
+
save_data_to_file: SaveData,
|
|
247
|
+
saved_array_name_suffix: str,
|
|
248
248
|
) -> None:
|
|
249
|
-
"""
|
|
249
|
+
"""Populate :attr:`data` with generated data
|
|
250
|
+
|
|
251
|
+
see :attr:`SamplingFunctionKWArgs` for description of keyord parameters
|
|
252
|
+
|
|
253
|
+
Returns
|
|
254
|
+
-------
|
|
255
|
+
None
|
|
256
|
+
|
|
257
|
+
"""
|
|
250
258
|
|
|
251
259
|
self.data = self.gen_market_sample(
|
|
252
260
|
sample_size=sample_size, seed_seq_list=seed_seq_list, nthreads=nthreads
|
|
@@ -389,7 +397,8 @@ class MarketSample:
|
|
|
389
397
|
|
|
390
398
|
Returns
|
|
391
399
|
-------
|
|
392
|
-
Arrays of
|
|
400
|
+
Arrays of enforcement counts or clearance counts by firm count,
|
|
401
|
+
ΔHHI and concentration zone
|
|
393
402
|
|
|
394
403
|
"""
|
|
395
404
|
_sample_sz = sample_size
|
|
@@ -400,7 +409,7 @@ class MarketSample:
|
|
|
400
409
|
_thread_count = cpu_count()
|
|
401
410
|
|
|
402
411
|
if (
|
|
403
|
-
self.share_spec.recapture_form !=
|
|
412
|
+
self.share_spec.recapture_form != RECForm.OUTIN
|
|
404
413
|
and self.share_spec.recapture_rate != _enf_parm_vec.rec
|
|
405
414
|
):
|
|
406
415
|
raise ValueError(
|
|
@@ -458,12 +467,12 @@ class MarketSample:
|
|
|
458
467
|
/,
|
|
459
468
|
*,
|
|
460
469
|
sample_size: int = 10**6,
|
|
461
|
-
seed_seq_list:
|
|
462
|
-
nthreads: int,
|
|
470
|
+
seed_seq_list: Sequence[SeedSequence] | None = None,
|
|
471
|
+
nthreads: int = 16,
|
|
463
472
|
save_data_to_file: SaveData = False,
|
|
464
473
|
saved_array_name_suffix: str = "",
|
|
465
474
|
) -> None:
|
|
466
|
-
"""
|
|
475
|
+
"""Populate :attr:`enf_counts` etimated test counts.
|
|
467
476
|
|
|
468
477
|
Parameters
|
|
469
478
|
----------
|
|
@@ -478,16 +487,16 @@ class MarketSample:
|
|
|
478
487
|
merging firms
|
|
479
488
|
|
|
480
489
|
sample_size
|
|
481
|
-
|
|
490
|
+
Number of draws to simulate
|
|
482
491
|
|
|
483
492
|
seed_seq_list
|
|
484
|
-
List of
|
|
493
|
+
List of seed sequences, to assure independent samples in each thread
|
|
485
494
|
|
|
486
495
|
nthreads
|
|
487
|
-
Number of
|
|
496
|
+
Number of parallel processes to use
|
|
488
497
|
|
|
489
498
|
save_data_to_file
|
|
490
|
-
|
|
499
|
+
Whether to save data to an HDF5 file, and where to save it
|
|
491
500
|
|
|
492
501
|
saved_array_name_suffix
|
|
493
502
|
Suffix to add to the array names in the HDF5 file
|