mergeron 2024.739127.0__py3-none-any.whl → 2024.739139.0__py3-none-any.whl

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/__init__.py CHANGED
@@ -2,14 +2,13 @@ from __future__ import annotations
2
2
 
3
3
  import enum
4
4
  from pathlib import Path
5
- from typing import TypeAlias
6
5
 
7
6
  import numpy as np
8
7
  from numpy.typing import NDArray
9
8
 
10
9
  _PKG_NAME: str = Path(__file__).parent.stem
11
10
 
12
- VERSION = "2024.739127.0"
11
+ VERSION = "2024.739139.0"
13
12
 
14
13
  __version__ = VERSION
15
14
 
@@ -25,21 +24,21 @@ if not DATA_DIR.is_dir():
25
24
  np.set_printoptions(precision=18)
26
25
 
27
26
 
28
- ArrayINT = NDArray[np.intp]
29
- ArrayFloat = NDArray[np.half | np.single | np.double]
27
+ type ArrayINT = NDArray[np.intp]
28
+ type ArrayFloat = NDArray[np.half | np.single | np.double]
30
29
 
31
30
 
32
- ArrayBoolean: TypeAlias = NDArray[np.bool_]
31
+ type ArrayBoolean = NDArray[np.bool_]
33
32
 
34
- ArrayDouble: TypeAlias = NDArray[np.double]
35
- ArrayBIGINT: TypeAlias = NDArray[np.int64]
33
+ type ArrayDouble = NDArray[np.double]
34
+ type ArrayBIGINT = NDArray[np.int64]
36
35
 
37
36
  DEFAULT_REC_RATE = 0.85
38
37
 
39
38
 
40
39
  @enum.unique
41
40
  class RECForm(enum.StrEnum):
42
- """Recapture rate - derivation methods."""
41
+ """For derivation of recapture ratio from market shares."""
43
42
 
44
43
  INOUT = "inside-out"
45
44
  OUTIN = "outside-in"
@@ -49,7 +48,7 @@ class RECForm(enum.StrEnum):
49
48
  @enum.unique
50
49
  class UPPAggrSelector(enum.StrEnum):
51
50
  """
52
- Aggregator selection for GUPPI and diversion ratio
51
+ Aggregator for GUPPI and diversion ratio estimates.
53
52
 
54
53
  """
55
54
 
@@ -14,7 +14,7 @@ from importlib import resources
14
14
  from operator import itemgetter
15
15
  from pathlib import Path
16
16
  from types import MappingProxyType
17
- from typing import Any, NamedTuple, TypeAlias
17
+ from typing import Any, NamedTuple
18
18
 
19
19
  import msgpack # type: ignore
20
20
  import msgpack_numpy as m # type: ignore
@@ -95,7 +95,7 @@ class INVTableData(NamedTuple):
95
95
  data_array: ArrayBIGINT
96
96
 
97
97
 
98
- INVData: TypeAlias = Mapping[str, Mapping[str, Mapping[str, INVTableData]]]
98
+ type INVData = Mapping[str, Mapping[str, Mapping[str, INVTableData]]]
99
99
 
100
100
 
101
101
  def construct_data(
@@ -7,7 +7,7 @@ with a canvas on which to draw boundaries for Guidelines standards.
7
7
  from __future__ import annotations
8
8
 
9
9
  from dataclasses import dataclass
10
- from typing import Literal, TypeAlias
10
+ from typing import Literal
11
11
 
12
12
  import numpy as np
13
13
  from attrs import Attribute, field, frozen, validators
@@ -28,7 +28,7 @@ __version__ = VERSION
28
28
  mp.prec = 80
29
29
  mp.trap_complex = True
30
30
 
31
- HMGPubYear: TypeAlias = Literal[1992, 2004, 2010, 2023]
31
+ type HMGPubYear = Literal[1992, 2004, 2010, 2023]
32
32
 
33
33
 
34
34
  @dataclass(frozen=True)
@@ -47,7 +47,7 @@ class GuidelinesThresholds:
47
47
  """
48
48
  Guidelines threholds by Guidelines publication year
49
49
 
50
- ΔHHI, Recapture Rate, GUPPI, Diversion ratio, CMCR, and IPR thresholds
50
+ ΔHHI, Recapture Ratio, GUPPI, Diversion ratio, CMCR, and IPR thresholds
51
51
  constructed from concentration standards in Guidelines published in
52
52
  1992, 2004, 2010, and 2023.
53
53
 
@@ -70,7 +70,7 @@ class GuidelinesThresholds:
70
70
  """
71
71
  Negative presumption quantified on various measures
72
72
 
73
- ΔHHI safeharbor bound, default recapture rate, GUPPI bound,
73
+ ΔHHI safeharbor bound, default recapture ratio, GUPPI bound,
74
74
  diversion ratio limit, CMCR, and IPR
75
75
  """
76
76
 
@@ -78,7 +78,7 @@ class GuidelinesThresholds:
78
78
  """
79
79
  Presumption of harm defined in HMG
80
80
 
81
- ΔHHI bound and corresponding default recapture rate, GUPPI bound,
81
+ ΔHHI bound and corresponding default recapture ratio, GUPPI bound,
82
82
  diversion ratio limit, CMCR, and IPR
83
83
  """
84
84
 
@@ -87,7 +87,7 @@ class GuidelinesThresholds:
87
87
  Presumption of harm imputed from guidelines
88
88
 
89
89
  ΔHHI bound inferred from strict numbers-equivalent
90
- of (post-merger) HHI presumption, and corresponding default recapture rate,
90
+ of (post-merger) HHI presumption, and corresponding default recapture ratio,
91
91
  GUPPI bound, diversion ratio limit, CMCR, and IPR
92
92
  """
93
93
 
@@ -233,11 +233,11 @@ def _rec_spec_validator(
233
233
  _value: RECForm,
234
234
  /,
235
235
  ) -> None:
236
- if _value == RECForm.OUTIN and _instance.recapture_rate:
236
+ if _value == RECForm.OUTIN and _instance.recapture_ratio:
237
237
  raise ValueError(
238
238
  f"Invalid recapture specification, {_value!r}. "
239
239
  "You may consider specifying `mergeron.RECForm.INOUT` here, and "
240
- 'assigning the default recapture rate as attribute, "recapture_rate" of '
240
+ 'assigning the default recapture ratio as attribute, "recapture_ratio" of '
241
241
  "this `DiversionRatioBoundarySpec` object."
242
242
  )
243
243
  if _value is None and _instance.agg_method != UPPAggrSelector.MAX:
@@ -251,7 +251,7 @@ class DiversionRatioBoundary:
251
251
  """
252
252
  Diversion ratio specification, boundary coordinates, and area under boundary.
253
253
 
254
- Along with the default diversion ratio and recapture rate,
254
+ Along with the default diversion ratio and recapture ratio,
255
255
  a diversion ratio boundary specification includes the recapture form --
256
256
  whether fixed for both merging firms' products ("proportional") or
257
257
  consistent with share-proportionality, i.e., "inside-out";
@@ -267,7 +267,7 @@ class DiversionRatioBoundary:
267
267
  validator=(validators.instance_of(float), _divr_value_validator),
268
268
  )
269
269
 
270
- recapture_rate: float = field(
270
+ recapture_ratio: float = field(
271
271
  kw_only=False, default=DEFAULT_REC_RATE, validator=validators.instance_of(float)
272
272
  )
273
273
 
@@ -277,13 +277,13 @@ class DiversionRatioBoundary:
277
277
  validator=(validators.instance_of((type(None), RECForm)), _rec_spec_validator),
278
278
  )
279
279
  """
280
- The form of the recapture rate.
280
+ The form of the recapture ratio.
281
281
 
282
- When :attr:`mergeron.RECForm.INOUT`, the recapture rate for
282
+ When :attr:`mergeron.RECForm.INOUT`, the recapture ratio for
283
283
  he product having the smaller market-share is assumed to equal the default,
284
- and the recapture rate for the product with the larger market-share is
285
- computed assuming MNL demand. Fixed recapture rates are specified as
286
- :attr:`mergeron.RECForm.FIXED`. (To specify that recapture rates be
284
+ and the recapture ratio for the product with the larger market-share is
285
+ computed assuming MNL demand. Fixed recapture ratios are specified as
286
+ :attr:`mergeron.RECForm.FIXED`. (To specify that recapture ratios be
287
287
  constructed from the generated purchase-probabilities for products in
288
288
  the market and for the outside good, specify :attr:`mergeron.RECForm.OUTIN`.)
289
289
 
@@ -331,7 +331,7 @@ class DiversionRatioBoundary:
331
331
 
332
332
  def __attrs_post_init__(self, /) -> None:
333
333
  _share_ratio = critical_share_ratio(
334
- self.diversion_ratio, r_bar=self.recapture_rate
334
+ self.diversion_ratio, r_bar=self.recapture_ratio
335
335
  )
336
336
  _upp_agg_kwargs: gbfn.ShareRatioBoundaryKeywords = {
337
337
  "recapture_form": getattr(self.recapture_form, "value", "inside-out"),
@@ -370,7 +370,7 @@ class DiversionRatioBoundary:
370
370
 
371
371
  _upp_agg_kwargs |= {"agg_method": _aggregator, "weighting": _wgt_type}
372
372
 
373
- _boundary = _upp_agg_fn(_share_ratio, self.recapture_rate, **_upp_agg_kwargs)
373
+ _boundary = _upp_agg_fn(_share_ratio, self.recapture_ratio, **_upp_agg_kwargs)
374
374
  object.__setattr__(self, "coordinates", _boundary.coordinates)
375
375
  object.__setattr__(self, "area", _boundary.area)
376
376
 
@@ -392,11 +392,11 @@ def guppi_from_delta(
392
392
  m_star
393
393
  Parametric price-cost margin.
394
394
  r_bar
395
- Default recapture rate.
395
+ Default recapture ratio.
396
396
 
397
397
  Returns
398
398
  -------
399
- GUPPI bound corresponding to ∆HHI bound, at given margin and recapture rate.
399
+ GUPPI bound corresponding to ∆HHI bound, at given margin and recapture ratio.
400
400
 
401
401
  """
402
402
  return gbfn.round_cust(
@@ -424,12 +424,12 @@ def critical_share_ratio(
424
424
  m_star
425
425
  Parametric price-cost margin.
426
426
  r_bar
427
- Default recapture rate.
427
+ Default recapture ratio.
428
428
 
429
429
  Returns
430
430
  -------
431
431
  Critical share ratio (share ratio bound) corresponding to the GUPPI bound
432
- for given margin and recapture rate.
432
+ for given margin and recapture ratio.
433
433
 
434
434
  """
435
435
  return gbfn.round_cust(
@@ -445,7 +445,7 @@ def share_from_guppi(
445
445
  r_bar: float = DEFAULT_REC_RATE,
446
446
  ) -> float:
447
447
  """
448
- Symmetric-firm share for given GUPPI, margin, and recapture rate.
448
+ Symmetric-firm share for given GUPPI, margin, and recapture ratio.
449
449
 
450
450
  Parameters
451
451
  ----------
@@ -454,13 +454,13 @@ def share_from_guppi(
454
454
  m_star
455
455
  Parametric price-cost margin.
456
456
  r_bar
457
- Default recapture rate.
457
+ Default recapture ratio.
458
458
 
459
459
  Returns
460
460
  -------
461
461
  float
462
462
  Symmetric firm market share on GUPPI boundary, for given margin and
463
- recapture rate.
463
+ recapture ratio.
464
464
 
465
465
  """
466
466
 
@@ -48,10 +48,9 @@ with warnings.catch_warnings():
48
48
  mgn_kde = stats.gaussian_kde(mgn_data_obs, weights=mgn_data_wts, bw_method="silverman")
49
49
  mgn_kde.set_bandwidth(bw_method=mgn_kde.factor / 3.0)
50
50
 
51
- mgn_xvec = np.linspace(0, BIN_COUNT, 10**5) / BIN_COUNT
52
51
  mgn_ax.plot(
53
- mgn_xvec,
54
- mgn_kde(mgn_xvec),
52
+ (_xv := np.linspace(0, BIN_COUNT, 10**5) / BIN_COUNT),
53
+ mgn_kde(_xv),
55
54
  color="#004488",
56
55
  rasterized=True,
57
56
  label="Estimated Density",
mergeron/gen/__init__.py CHANGED
@@ -105,15 +105,14 @@ class ShareSpec:
105
105
 
106
106
  Notes
107
107
  -----
108
- If :attr:`mergeron.gen.ShareSpec.dist_type`:code:` == `:attr:`mergeron.gen.SHRDistribution.UNI`,
108
+ If :attr:`mergeron.gen.ShareSpec.dist_type` == :attr:`mergeron.gen.SHRDistribution.UNI`,
109
109
  then it is infeasible that
110
- :attr:`mergeron.gen.ShareSpec.recapture_form`:code:` == `:attr:`mergeron.RECForm.OUTIN`.
111
- In other words, if firm-counts are unspecified, the recapture rate cannot be
112
- estimated using outside good choice probabilities.
110
+ :attr:`mergeron.gen.ShareSpec.recapture_form` == :attr:`mergeron.RECForm.OUTIN`.
111
+ In other words, if the distribution of markets over firm-counts is unspecified,
112
+ recapture ratios cannot be estimated using outside-good choice probabilities.
113
113
 
114
- For a sample with explicit firm counts, market shares must
115
- be specified as having a supported Dirichlet distribution
116
- (see :class:`mergeron.gen.SHRDistribution`).
114
+ For a sample with explicit firm counts, market shares must be specified as
115
+ having a supported Dirichlet distribution (see :class:`mergeron.gen.SHRDistribution`).
117
116
 
118
117
  """
119
118
 
@@ -161,19 +160,19 @@ class ShareSpec:
161
160
  def _check_rf(_i: ShareSpec, _a: Attribute[RECForm], _v: RECForm) -> None:
162
161
  if _v == RECForm.OUTIN and _i.dist_type == SHRDistribution.UNI:
163
162
  raise ValueError(
164
- "Market share specification requires estimation of recapture rate from "
165
- "generated data. Either delete recapture rate specification or set it to None."
163
+ "Market share specification requires estimation of recapture ratio from "
164
+ "generated data. Either delete recapture ratio specification or set it to None."
166
165
  )
167
166
 
168
- recapture_rate: float | None = field(default=DEFAULT_REC_RATE)
167
+ recapture_ratio: float | None = field(default=DEFAULT_REC_RATE)
169
168
  """A value between 0 and 1.
170
169
 
171
170
  :code:`None` if market share specification requires direct generation of
172
171
  outside good choice probabilities (:attr:`mergeron.RECForm.OUTIN`).
173
172
 
174
- The recapture rate is usually calibrated to the numbers-equivalent of the
173
+ The recapture ratio is usually calibrated to the numbers-equivalent of the
175
174
  HHI threshold for the presumtion of harm from unilateral competitive effects
176
- in published merger guidelines. Accordingly, the recapture rate rounded to
175
+ in published merger guidelines. Accordingly, the recapture ratio rounded to
177
176
  the nearest 5% is:
178
177
 
179
178
  * 0.85, **7-to-6 merger from symmetry**; US Guidelines, 1992, 2023
@@ -188,14 +187,14 @@ class ShareSpec:
188
187
 
189
188
  """
190
189
 
191
- @recapture_rate.validator
190
+ @recapture_ratio.validator
192
191
  def _check_rr(_i: ShareSpec, _a: Attribute[float], _v: float) -> None:
193
192
  if _v and not (0 < _v <= 1):
194
- raise ValueError("Recapture rate must lie in the interval, [0, 1).")
193
+ raise ValueError("Recapture ratio must lie in the interval, [0, 1).")
195
194
  elif _v is None and _i.recapture_form != RECForm.OUTIN:
196
195
  raise ValueError(
197
196
  f"Recapture specification, {_i.recapture_form!r} requires that "
198
- "the market sample specification inclues a recapture rate in the "
197
+ "the market sample specification inclues a recapture ratio in the "
199
198
  "interval [0, 1)."
200
199
  )
201
200
 
@@ -134,7 +134,7 @@ class MarketSample:
134
134
  """
135
135
 
136
136
  _recapture_form = self.share_spec.recapture_form
137
- _recapture_rate = self.share_spec.recapture_rate
137
+ _recapture_ratio = self.share_spec.recapture_ratio
138
138
  _dist_type_mktshr = self.share_spec.dist_type
139
139
  _dist_firm2_pcm = self.pcm_spec.firm2_pcm_constraint
140
140
  _hsr_filing_test_type = self.hsr_filing_test_type
@@ -208,7 +208,7 @@ class MarketSample:
208
208
  # Calculate diversion ratios
209
209
  _divr_array = gen_divr_array(
210
210
  _recapture_form,
211
- _recapture_rate,
211
+ _recapture_ratio,
212
212
  _mktshr_array[:, :2],
213
213
  _aggregate_purchase_prob,
214
214
  )
@@ -410,11 +410,11 @@ class MarketSample:
410
410
 
411
411
  if (
412
412
  self.share_spec.recapture_form != RECForm.OUTIN
413
- and self.share_spec.recapture_rate != _enf_parm_vec.rec
413
+ and self.share_spec.recapture_ratio != _enf_parm_vec.rec
414
414
  ):
415
415
  raise ValueError(
416
416
  "{} {} {}".format(
417
- f"Recapture rate from market sample spec, {self.share_spec.recapture_rate}",
417
+ f"Recapture ratio from market sample spec, {self.share_spec.recapture_ratio}",
418
418
  f"must match the value, {_enf_parm_vec.rec}",
419
419
  "the guidelines thresholds vector.",
420
420
  )
@@ -106,7 +106,7 @@ def gen_share_data(
106
106
 
107
107
  # If recapture_form == "inside-out", recalculate _aggregate_purchase_prob
108
108
  _frmshr_array = _mkt_share_sample.mktshr_array[:, :2]
109
- _r_bar = _share_spec.recapture_rate or DEFAULT_REC_RATE
109
+ _r_bar = _share_spec.recapture_ratio or DEFAULT_REC_RATE
110
110
  if _recapture_form == RECForm.INOUT:
111
111
  _mkt_share_sample = ShareDataSample(
112
112
  _mkt_share_sample.mktshr_array,
@@ -409,7 +409,7 @@ def gen_market_shares_dirichlet(
409
409
 
410
410
  def gen_divr_array(
411
411
  _recapture_form: RECForm,
412
- _recapture_rate: float | None,
412
+ _recapture_ratio: float | None,
413
413
  _frmshr_array: ArrayDouble,
414
414
  _aggregate_purchase_prob: ArrayDouble = EMPTY_ARRAY_DEFAULT,
415
415
  /,
@@ -425,8 +425,8 @@ def gen_divr_array(
425
425
  _recapture_form
426
426
  Enum specifying Fixed (proportional), Inside-out, or Outside-in
427
427
 
428
- _recapture_rate
429
- If recapture is proportional or inside-out, the recapture rate
428
+ _recapture_ratio
429
+ If recapture is proportional or inside-out, the recapture ratio
430
430
  for the firm with the smaller share.
431
431
 
432
432
  _frmshr_array
@@ -450,7 +450,7 @@ def gen_divr_array(
450
450
 
451
451
  _divr_array: ArrayDouble
452
452
  if _recapture_form == RECForm.FIXED:
453
- _divr_array = _recapture_rate * _frmshr_array[:, ::-1] / (1 - _frmshr_array) # type: ignore
453
+ _divr_array = _recapture_ratio * _frmshr_array[:, ::-1] / (1 - _frmshr_array) # type: ignore
454
454
 
455
455
  else:
456
456
  _purchprob_array = _aggregate_purchase_prob * _frmshr_array
mergeron/gen/upp_tests.py CHANGED
@@ -7,11 +7,12 @@ from generated market data.
7
7
  from collections.abc import Sequence
8
8
  from contextlib import suppress
9
9
  from pathlib import Path
10
- from typing import Literal, TypeAlias, TypedDict
10
+ from typing import Any, Literal, TypedDict
11
11
 
12
12
  import numpy as np
13
13
  import tables as ptb # type: ignore
14
14
  from numpy.random import SeedSequence
15
+ from numpy.typing import NDArray
15
16
 
16
17
  from .. import ( # noqa
17
18
  VERSION,
@@ -40,7 +41,7 @@ __version__ = VERSION
40
41
  ptb.parameters.MAX_NUMEXPR_THREADS = 8
41
42
  ptb.parameters.MAX_BLOSC_THREADS = 4
42
43
 
43
- SaveData: TypeAlias = Literal[False] | tuple[Literal[True], ptb.File, ptb.Group]
44
+ type SaveData = Literal[False] | tuple[Literal[True], ptb.File, ptb.Group]
44
45
 
45
46
 
46
47
  class INVRESCntsArgs(TypedDict, total=False):
@@ -213,7 +214,8 @@ def compute_upp_test_arrays(
213
214
 
214
215
  """
215
216
  _g_bar, _divr_bar, _cmcr_bar, _ipr_bar = (
216
- getattr(_upp_test_parms, _f) for _f in ("guppi", "divr", "cmcr", "ipr"))
217
+ getattr(_upp_test_parms, _f) for _f in ("guppi", "divr", "cmcr", "ipr")
218
+ )
217
219
 
218
220
  _guppi_array, _ipr_array, _cmcr_array = (
219
221
  np.empty_like(_market_data.price_array) for _ in range(3)
@@ -366,7 +368,7 @@ def save_data_to_hdf5(
366
368
 
367
369
 
368
370
  def save_array_to_hdf5(
369
- _array_obj: ArrayFloat | ArrayINT | ArrayDouble | ArrayBIGINT | ArrayBoolean,
371
+ _array_obj: NDArray[Any],
370
372
  _array_name: str,
371
373
  _h5_group: ptb.Group,
372
374
  _h5_file: ptb.File,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mergeron
3
- Version: 2024.739127.0
3
+ Version: 2024.739139.0
4
4
  Summary: Merger Policy Analysis using Python
5
5
  License: MIT
6
6
  Keywords: merger policy analysis,merger guidelines,merger screening,policy presumptions,concentration standards,upward pricing pressure,GUPPI
@@ -41,23 +41,23 @@ Description-Content-Type: text/x-rst
41
41
  mergeron: Merger Policy Analysis using Python
42
42
  =============================================
43
43
 
44
- 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.
44
+ Visualize the sets of mergers conforming to concentration and diversion-ratio standards. Estimate 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.
45
45
 
46
46
  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.
47
47
 
48
48
  Introduction
49
49
  ------------
50
50
 
51
- 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.
51
+ 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.
52
52
 
53
- 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`
53
+ 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) computing the intrinsic enforcement rate and intrinsic clearance rate for the generated sample, given a method (:code:`.UPPAggrSelector`) 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`
54
54
  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.share_spec.firm_count_weights`, with defaults as discussed below (also see, :code:`.gen.ShareSpec.firm_count_weights`.
55
55
 
56
56
  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 (see property `dist_type` of :code:`.gen.data_generation.MarketSample.share_spec`, of type, :code:`.gen.SHRDistribution`), with specified shape parameters (property `dist_parms` of :code:`.gen.data_generation.MarketSample.share_spec`. When drawing shares from the Dirichlet distribution, the user specifies the `firm_count_weights` property of :code:`.gen.data_generation.MarketSample.share_spec`, as 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 the property `firm_count_weights` is not explicitly assigned a value when defining :code:`.gen.data_generation.MarketSample.share_spec`, 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.
57
57
 
58
- Recapture rates can be specified as, "proportional", "inside-out", or "outside-in" (see :code:`.RECForm`). The "inside-out" specification (assigning :code:`.RECForm.INOUT` to the `recapture_form` property of :code:`.gen.data_generation.MarketSample.share_spec`) results in recapture ratios consistent with merging-firms' in-market shares and a default recapture rate. The "outside-in" specification (assigning :code:`.RECForm.INOUT` to the `recapture_form` property of :code:`.gen.data_generation.MarketSample.share_spec`) 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 the property `dist_type` of :code:`.gen.data_generation.MarketSample.share_spec` is assigned :code:`.gen.ShareDistributions.UNI`, raising a :code:`ValueError` exception. The "proportional" form (`recapture_form` = :code:`.RECForm.FIXED`) is often used in the literature, as an approximation to the "inside-out" calibration. See, for example, Coate (2011).
58
+ Recapture ratios can be specified as, "proportional", "inside-out", or "outside-in" (see :code:`.RECForm`). The "inside-out" specification (assigning :code:`.RECForm.INOUT` to the `recapture_form` property of :code:`.gen.data_generation.MarketSample.share_spec`) results in recapture ratios consistent with MNL demand, given merging-firms' in-market shares and a default recapture ratio. The "outside-in" specification (assigning :code:`.RECForm.INOUT` to the `recapture_form` property of :code:`.gen.data_generation.MarketSample.share_spec`) yields diversion ratios from purchase probabilities drawn at random for :math:`N+1` goods, with market shares and recapture ratios for the :math:`N` goods in the putative market (see, :code:`.gen.ShareSpec`) computed from the simulated choice probabilities. The "outside-in" specification requires specification of the distribution of markets over firm counts (the default being uniform distirbution over markets with 2 to 7 firms pre-merger), and Dirichlet-distributed shares, with optional parameters (the default being a "flat" Dirichlet distribution, i.e., one with all parameters being 1). The parameters of the Dirichlet distribution can, for example, be specified to increase (decrease) the probability of drawing mergers to monopoly relative to that probability associated with the Flat Dirichlet specification, by setting the first 2 specified parameters at higher (lower) values relative to the others. Lastly, the "proportional" form of recapture ratio (`recapture_form` = :code:`.RECForm.FIXED`) is often used in the literature, as an approximation to the "inside-out" calibration. See, for example, Coate (2011).
59
59
 
60
- 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 (per the property `firm2_pcm_constraint` of :code:`.gen.data_generation.MarketSample.pcm_spec`) 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`).
60
+ Price-cost-margins may be specified as having uniform distribution, Beta distribution (including a bounded Beta distribution with specified mean and variance), or a built-in empirical distribution (see, :code:`.gen.PCMSpec`). The in-built 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 (per the property `firm2_pcm_constraint` of :code:`.gen.data_generation.MarketSample.pcm_spec`) 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`).
61
61
 
62
62
  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 prices equal :math:`1 / (1 - \pmb{m})`, where :math:`\pmb{m}` represents the array of margins for firms in the sample.
63
63
 
@@ -65,11 +65,11 @@ The market sample may be restricted to mergers meeting the HSR filing requiremen
65
65
 
66
66
  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).
67
67
 
68
- 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`.
68
+ Enforcement statistics based on FTC investigations data and test data are tabulated using methods provided in :code:`.gen.enforcement_stats`.
69
69
 
70
70
  Programs demonstrating the use of this package are included in the sub-package, :code:`.demo`.
71
71
 
72
- This package includes a class, :code:`.core.pseudorandom_numbers.MultithreadedRNG` 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:
72
+ This package includes a class, :code:`.core.pseudorandom_numbers.MultithreadedRNG` for generating random numbers with selected continuous distribution over specified parameters, and with CPU multithreading on machines with multiple CPU cores, be they virtual, logical, or physical cores. This class is an adaptation from the documentation for the external :code:`numpy.random` subpackage, from the discussion on, "`Multithreaded 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:
73
73
 
74
74
  .. code-block:: python
75
75
 
@@ -1,9 +1,9 @@
1
1
  mergeron/License.txt,sha256=7iX-y0EyjkbVJKJLS4ZKzuuE1wd0lryfsD_IytLG8lQ,1246
2
- mergeron/__init__.py,sha256=bTcTGdrdd0aHh_uD3Pl84q1uw-13oAwbGOXHqpK6vI8,1479
2
+ mergeron/__init__.py,sha256=hiOhxFInENJRReecosK422vBUnZGrOEutNkWfEs7JOs,1460
3
3
  mergeron/core/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
4
4
  mergeron/core/damodaran_margin_data.py,sha256=rMrgN1Qtw572a0ftY97OOj4otq8ldlLrcOi-bcE-org,8554
5
- mergeron/core/ftc_merger_investigations_data.py,sha256=Q8d2N4brY2cwJClibwxOVfLE3WV0XZABssblGN6nOdA,28639
6
- mergeron/core/guidelines_boundaries.py,sha256=sEvIIaOvWl6tMDYeZCIr8EsBioXOn9RSXKyKlmxnH-k,15610
5
+ mergeron/core/ftc_merger_investigations_data.py,sha256=eldNU4hX9oKE4Rb08YE9_1LgolvNKZnhOXW6KyWSwnM,28622
6
+ mergeron/core/guidelines_boundaries.py,sha256=7C5hMa8vijDZbLdrSxO3XHpsXF5e7PZFpI-abDKqt90,15616
7
7
  mergeron/core/guidelines_boundary_functions.py,sha256=GGn5mwBWmxkqcat4Ya0D-J6-7ujosgCCK3eJ9RFWASI,29749
8
8
  mergeron/core/guidelines_boundary_functions_extra.py,sha256=HDwwKZDWlrj3Tw-I0gHm0TCSDcIyb9jDfwbuDvK55B8,11322
9
9
  mergeron/core/pseudorandom_numbers.py,sha256=cJEWDTfy9CUTzR_di6Fm1Vl1Le6xWoU8wFHbYVMEuLI,9225
@@ -12,13 +12,13 @@ mergeron/data/damodaran_margin_data.xls,sha256=Qggl1p5nkOMJI8YUXhkwXQRz-OhRSqBTz
12
12
  mergeron/data/damodaran_margin_data_dict.msgpack,sha256=sr6s4L69kposEpzGI7jpPb4ULz0UpY-bEYfeNi6UlRA,57621
13
13
  mergeron/data/ftc_invdata.msgpack,sha256=WBFHgi7Ld4R-h2zL2Zc3TOIlKqVrbVFMH1LoI4-T-M0,264664
14
14
  mergeron/demo/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
15
- mergeron/demo/visualize_empirical_margin_distribution.py,sha256=v1xFJumBX2Ooye82kSSgly-_GpFVkYSDqBwM__rcmZY,2363
16
- mergeron/gen/__init__.py,sha256=0rfcWpKDhYE_jNsw6xKTGFJqgNtfJ-5JFxHS89CIEuI,16575
17
- mergeron/gen/data_generation.py,sha256=jSpwB2BHBDPVTsT1-NZhTSCcUV6816qn5oZBe6S0Hio,16797
18
- mergeron/gen/data_generation_functions.py,sha256=bP3E0IPXINRc8s0dUxS_Wqo1byVzheZLX811A17WNbU,28571
15
+ mergeron/demo/visualize_empirical_margin_distribution.py,sha256=R-sGC87kVovWBqcM5U6GiNC9oLsbNaMTJgljv8ts8w0,2347
16
+ mergeron/gen/__init__.py,sha256=DU6uFbRwe6ng-2sKCmpymD90CDNmyelWvUnmtNu8iHM,16593
17
+ mergeron/gen/data_generation.py,sha256=czTZcVZnT5kWViSFdSdbo0kupq1tUKGrKH5RThXbDwk,16803
18
+ mergeron/gen/data_generation_functions.py,sha256=Ag6u1yZ93ikGuKhj7PWbJ2lCZHxNGTemDfhK8p5xFq0,28576
19
19
  mergeron/gen/enforcement_stats.py,sha256=ZjrV_VkFMF0D1myc-fj-W99M1EhJMA9-nCfyE5g9e54,10890
20
- mergeron/gen/upp_tests.py,sha256=PtPOcu1zPDoHJUi06ytDUPNk21rzMwnfeGqUhvYXZs0,12607
20
+ mergeron/gen/upp_tests.py,sha256=uRF4RrBo3amwQQSu661Xa50xKGMUxtnM3zRtYy3nyB0,12581
21
21
  mergeron/py.typed,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
22
- mergeron-2024.739127.0.dist-info/METADATA,sha256=rvQUQmlBT2ECLY4t9Dy4fnUN1-A_sn_5f09z_IYNPE4,13976
23
- mergeron-2024.739127.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
24
- mergeron-2024.739127.0.dist-info/RECORD,,
22
+ mergeron-2024.739139.0.dist-info/METADATA,sha256=NrSRBKtvNhW9KFKRB4gW_YK39BmhFKiA8DNtz-nZQ7g,14430
23
+ mergeron-2024.739139.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
24
+ mergeron-2024.739139.0.dist-info/RECORD,,