mergeron 2024.739145.3__tar.gz → 2024.739145.5__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.739145.3 → mergeron-2024.739145.5}/PKG-INFO +2 -1
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/pyproject.toml +6 -6
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/__init__.py +2 -2
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/core/guidelines_boundaries.py +44 -58
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/core/guidelines_boundary_functions.py +61 -56
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/core/guidelines_boundary_functions_extra.py +3 -3
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/gen/__init__.py +3 -4
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/gen/data_generation.py +2 -2
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/gen/data_generation_functions.py +4 -5
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/gen/upp_tests.py +1 -1
- mergeron-2024.739145.3/src/mergeron/License.txt +0 -16
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/README.rst +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/core/__init__.py +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/core/empirical_margin_distribution.py +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/core/ftc_merger_investigations_data.py +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/core/pseudorandom_numbers.py +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/data/__init__.py +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/data/damodaran_margin_data.xls +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/data/damodaran_margin_data_dict.msgpack +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/data/ftc_invdata.msgpack +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/demo/__init__.py +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/demo/visualize_empirical_margin_distribution.py +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/gen/enforcement_stats.py +0 -0
- {mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mergeron
|
|
3
|
-
Version: 2024.739145.
|
|
3
|
+
Version: 2024.739145.5
|
|
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
|
|
@@ -16,6 +16,7 @@ Classifier: Operating System :: OS Independent
|
|
|
16
16
|
Classifier: Programming Language :: Python
|
|
17
17
|
Classifier: Programming Language :: Python :: 3
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
20
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
21
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
21
22
|
Requires-Dist: aenum (>=3.1.15,<4.0.0)
|
|
@@ -13,7 +13,7 @@ keywords = [
|
|
|
13
13
|
"upward pricing pressure",
|
|
14
14
|
"GUPPI",
|
|
15
15
|
]
|
|
16
|
-
version = "2024.739145.
|
|
16
|
+
version = "2024.739145.5"
|
|
17
17
|
|
|
18
18
|
# Classifiers list: https://pypi.org/classifiers/
|
|
19
19
|
classifiers = [
|
|
@@ -130,7 +130,7 @@ select = [
|
|
|
130
130
|
"S", # flake8-bandit
|
|
131
131
|
"SIM", # flake8-simplify
|
|
132
132
|
"TID", # flake8-tidy-imports
|
|
133
|
-
"
|
|
133
|
+
"TC", # flake8-type-checking
|
|
134
134
|
"UP", # pyupgrade
|
|
135
135
|
"RUF", # ruff-specific
|
|
136
136
|
]
|
|
@@ -148,9 +148,9 @@ ignore = [
|
|
|
148
148
|
'B905',
|
|
149
149
|
"PLR2004", # avoid magic values
|
|
150
150
|
# flake8-type-checking
|
|
151
|
-
"
|
|
152
|
-
"
|
|
153
|
-
"
|
|
151
|
+
"TC001", # move application import into a type-checking block
|
|
152
|
+
"TC002", # move third-party import into a type-checking block
|
|
153
|
+
"TC003", # move third-party import into a type-checking block
|
|
154
154
|
# Use typing.TypeAlias for now:
|
|
155
155
|
# mypy yet to implements PEP 695 type aliases;
|
|
156
156
|
# sphinx (as setup here) gives different results with TypeAlias and typing statement
|
|
@@ -169,7 +169,7 @@ preview = true
|
|
|
169
169
|
python_version = "3.12"
|
|
170
170
|
ignore_missing_imports = false
|
|
171
171
|
strict = true
|
|
172
|
-
enable_incomplete_feature = ["
|
|
172
|
+
enable_incomplete_feature = ["PreciseTupleTypes"]
|
|
173
173
|
|
|
174
174
|
show_column_numbers = true
|
|
175
175
|
show_error_codes = true
|
|
@@ -8,7 +8,7 @@ from numpy.typing import NDArray
|
|
|
8
8
|
|
|
9
9
|
_PKG_NAME: str = Path(__file__).parent.stem
|
|
10
10
|
|
|
11
|
-
VERSION = "2024.739145.
|
|
11
|
+
VERSION = "2024.739145.5"
|
|
12
12
|
|
|
13
13
|
__version__ = VERSION
|
|
14
14
|
|
|
@@ -30,7 +30,7 @@ type ArrayINT = NDArray[np.intp]
|
|
|
30
30
|
type ArrayDouble = NDArray[np.double]
|
|
31
31
|
type ArrayBIGINT = NDArray[np.int64]
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
DEFAULT_REC_RATIO = 0.85
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
@enum.unique
|
{mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/core/guidelines_boundaries.py
RENAMED
|
@@ -6,6 +6,7 @@ with a canvas on which to draw boundaries for Guidelines standards.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
import decimal
|
|
9
10
|
from dataclasses import dataclass
|
|
10
11
|
from typing import Literal
|
|
11
12
|
|
|
@@ -14,13 +15,12 @@ from attrs import Attribute, field, frozen, validators
|
|
|
14
15
|
from mpmath import mp, mpf # type: ignore
|
|
15
16
|
|
|
16
17
|
from .. import ( # noqa: TID252
|
|
17
|
-
|
|
18
|
+
DEFAULT_REC_RATIO,
|
|
18
19
|
VERSION,
|
|
19
20
|
ArrayDouble,
|
|
20
21
|
RECForm,
|
|
21
22
|
UPPAggrSelector,
|
|
22
23
|
)
|
|
23
|
-
from . import MPFloat
|
|
24
24
|
from . import guidelines_boundary_functions as gbfn
|
|
25
25
|
|
|
26
26
|
__version__ = VERSION
|
|
@@ -29,7 +29,7 @@ __version__ = VERSION
|
|
|
29
29
|
mp.dps = 32
|
|
30
30
|
mp.trap_complex = True
|
|
31
31
|
|
|
32
|
-
type HMGPubYear = Literal[
|
|
32
|
+
type HMGPubYear = Literal[1982, 1984, 1992, 2010, 2023]
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
@dataclass(frozen=True)
|
|
@@ -50,19 +50,15 @@ class GuidelinesThresholds:
|
|
|
50
50
|
|
|
51
51
|
ΔHHI, Recapture Ratio, GUPPI, Diversion ratio, CMCR, and IPR thresholds
|
|
52
52
|
constructed from concentration standards in Guidelines published in
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
The 2004 Guidelines refernced here are the EU Commission
|
|
56
|
-
guidelines on assessment of horizontal mergers. These
|
|
57
|
-
guidelines also define a presumption for mergers with
|
|
58
|
-
post-merger HHI in [1000, 2000) and ΔHHI >= 250 points,
|
|
59
|
-
whi is not modeled here.
|
|
60
|
-
|
|
61
|
-
All other Guidelines modeled here are U.S. merger guidelines.
|
|
53
|
+
1982, 1984, 1992, 2010, and 2023.
|
|
62
54
|
|
|
63
55
|
"""
|
|
64
56
|
|
|
65
|
-
pub_year: HMGPubYear
|
|
57
|
+
pub_year: HMGPubYear = field(
|
|
58
|
+
kw_only=True,
|
|
59
|
+
default=2023,
|
|
60
|
+
validator=validators.in_([1982, 1984, 1992, 2010, 2023]),
|
|
61
|
+
)
|
|
66
62
|
"""
|
|
67
63
|
Year of publication of the Guidelines
|
|
68
64
|
"""
|
|
@@ -100,9 +96,10 @@ class GuidelinesThresholds:
|
|
|
100
96
|
# thus, here, the tentative delta safeharbor under
|
|
101
97
|
# the 2023 Guidelines is 100 points
|
|
102
98
|
_hhi_p, _dh_s, _dh_p = {
|
|
103
|
-
|
|
99
|
+
1982: (_s1982 := (0.18, 0.005, 0.01)),
|
|
100
|
+
1984: _s1982,
|
|
101
|
+
1992: _s1982,
|
|
104
102
|
2010: (0.25, 0.01, 0.02),
|
|
105
|
-
2004: (0.20, 0.015, 0.025),
|
|
106
103
|
2023: (0.18, 0.01, 0.01),
|
|
107
104
|
}[self.pub_year]
|
|
108
105
|
|
|
@@ -112,52 +109,41 @@ class GuidelinesThresholds:
|
|
|
112
109
|
HMGThresholds(
|
|
113
110
|
_dh_s,
|
|
114
111
|
_fc := int(np.ceil(1 / _hhi_p)),
|
|
115
|
-
_r := gbfn.round_cust(_fc / (_fc + 1), frac=0.05),
|
|
116
|
-
|
|
117
|
-
_dr := (1 -
|
|
112
|
+
_r := float(_r_s := gbfn.round_cust(_fc / (_fc + 1), frac=0.05)),
|
|
113
|
+
_g := float(guppi_from_delta(_dh_s, m_star=1.0, r_bar=_r)),
|
|
114
|
+
_dr := float(1 - _r_s),
|
|
118
115
|
_cmcr := 0.03, # Not strictly a Guidelines standard
|
|
119
|
-
_ipr :=
|
|
116
|
+
_ipr := _g, # Not strictly a Guidelines standard
|
|
120
117
|
),
|
|
121
118
|
)
|
|
122
119
|
|
|
123
120
|
object.__setattr__(
|
|
124
|
-
self,
|
|
125
|
-
"presumption",
|
|
126
|
-
HMGThresholds(
|
|
127
|
-
_dh_p,
|
|
128
|
-
_fc,
|
|
129
|
-
_r,
|
|
130
|
-
_g_p := guppi_from_delta(_dh_p, m_star=1.0, r_bar=_r),
|
|
131
|
-
_dr,
|
|
132
|
-
_cmcr,
|
|
133
|
-
_ipr := _g_p,
|
|
134
|
-
),
|
|
121
|
+
self, "presumption", HMGThresholds(_dh_p, _fc, _r, _g, _dr, _cmcr, _ipr)
|
|
135
122
|
)
|
|
136
123
|
|
|
137
|
-
# imputed_presumption is relevant for
|
|
138
|
-
#
|
|
124
|
+
# imputed_presumption is relevant for presumptions implicating
|
|
125
|
+
# mergers *to* symmetry in numbers-equivalent of post-merger HHI
|
|
126
|
+
# as in 2010 U.S.Guidelines
|
|
139
127
|
object.__setattr__(
|
|
140
128
|
self,
|
|
141
129
|
"imputed_presumption",
|
|
142
130
|
(
|
|
143
131
|
HMGThresholds(
|
|
144
|
-
|
|
132
|
+
2 * (0.5 / _fc) ** 2,
|
|
145
133
|
_fc,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
134
|
+
float(
|
|
135
|
+
_r_i := gbfn.round_cust(
|
|
136
|
+
(_fc - 1 / 2) / (_fc + 1 / 2), frac=0.05
|
|
137
|
+
)
|
|
138
|
+
),
|
|
139
|
+
_g,
|
|
140
|
+
float((1 - _r_i) / 2),
|
|
149
141
|
_cmcr,
|
|
150
|
-
|
|
142
|
+
_ipr := _g,
|
|
151
143
|
)
|
|
152
|
-
if self.pub_year
|
|
144
|
+
if self.pub_year == 2010
|
|
153
145
|
else HMGThresholds(
|
|
154
|
-
|
|
155
|
-
_fc,
|
|
156
|
-
_r,
|
|
157
|
-
_g_i := guppi_from_delta(_dh_p, m_star=1.0, r_bar=_r),
|
|
158
|
-
_dr,
|
|
159
|
-
_cmcr,
|
|
160
|
-
_g_i,
|
|
146
|
+
2 * (1 / (_fc + 1)) ** 2, _fc, _r, _g, _dr, _cmcr, _ipr
|
|
161
147
|
)
|
|
162
148
|
),
|
|
163
149
|
)
|
|
@@ -169,10 +155,7 @@ class ConcentrationBoundary:
|
|
|
169
155
|
|
|
170
156
|
measure_name: Literal[
|
|
171
157
|
"ΔHHI", "Combined share", "Pre-merger HHI", "Post-merger HHI"
|
|
172
|
-
] = field(
|
|
173
|
-
kw_only=False,
|
|
174
|
-
default="ΔHHI", # pyright: ignore
|
|
175
|
-
)
|
|
158
|
+
] = field(kw_only=False, default="ΔHHI")
|
|
176
159
|
|
|
177
160
|
@measure_name.validator # pyright: ignore
|
|
178
161
|
def __mnv(
|
|
@@ -193,7 +176,7 @@ class ConcentrationBoundary:
|
|
|
193
176
|
_instance: ConcentrationBoundary, _attribute: Attribute[float], _value: float, /
|
|
194
177
|
) -> None:
|
|
195
178
|
if not 0 <= _value <= 1:
|
|
196
|
-
raise ValueError("Concentration threshold must lie between 0 and 1.")
|
|
179
|
+
raise ValueError("Concentration threshold must lie between 0 and 1.")
|
|
197
180
|
|
|
198
181
|
precision: int = field(
|
|
199
182
|
kw_only=False, default=5, validator=validators.instance_of(int)
|
|
@@ -251,7 +234,9 @@ class DiversionRatioBoundary:
|
|
|
251
234
|
)
|
|
252
235
|
|
|
253
236
|
recapture_ratio: float = field(
|
|
254
|
-
kw_only=False,
|
|
237
|
+
kw_only=False,
|
|
238
|
+
default=DEFAULT_REC_RATIO,
|
|
239
|
+
validator=validators.instance_of(float),
|
|
255
240
|
)
|
|
256
241
|
|
|
257
242
|
recapture_form: RECForm | None = field(kw_only=True, default=RECForm.INOUT)
|
|
@@ -337,6 +322,7 @@ class DiversionRatioBoundary:
|
|
|
337
322
|
"recapture_form": getattr(self.recapture_form, "value", "inside-out"),
|
|
338
323
|
"dps": self.precision,
|
|
339
324
|
}
|
|
325
|
+
|
|
340
326
|
match self.agg_method:
|
|
341
327
|
case UPPAggrSelector.DIS:
|
|
342
328
|
_upp_agg_fn = gbfn.shrratio_boundary_wtd_avg
|
|
@@ -380,8 +366,8 @@ def guppi_from_delta(
|
|
|
380
366
|
/,
|
|
381
367
|
*,
|
|
382
368
|
m_star: float = 1.00,
|
|
383
|
-
r_bar: float =
|
|
384
|
-
) ->
|
|
369
|
+
r_bar: float = DEFAULT_REC_RATIO,
|
|
370
|
+
) -> decimal.Decimal:
|
|
385
371
|
"""
|
|
386
372
|
Translate ∆HHI bound to GUPPI bound.
|
|
387
373
|
|
|
@@ -407,13 +393,13 @@ def guppi_from_delta(
|
|
|
407
393
|
|
|
408
394
|
|
|
409
395
|
def critical_share_ratio(
|
|
410
|
-
_guppi_bound: float = 0.075,
|
|
396
|
+
_guppi_bound: float | decimal.Decimal = 0.075,
|
|
411
397
|
/,
|
|
412
398
|
*,
|
|
413
399
|
m_star: float = 1.00,
|
|
414
400
|
r_bar: float = 1.00,
|
|
415
401
|
frac: float = 1e-16,
|
|
416
|
-
) ->
|
|
402
|
+
) -> decimal.Decimal:
|
|
417
403
|
"""
|
|
418
404
|
Corollary to GUPPI bound.
|
|
419
405
|
|
|
@@ -438,12 +424,12 @@ def critical_share_ratio(
|
|
|
438
424
|
|
|
439
425
|
|
|
440
426
|
def share_from_guppi(
|
|
441
|
-
_guppi_bound: float = 0.065,
|
|
427
|
+
_guppi_bound: float | decimal.Decimal = 0.065,
|
|
442
428
|
/,
|
|
443
429
|
*,
|
|
444
430
|
m_star: float = 1.00,
|
|
445
|
-
r_bar: float =
|
|
446
|
-
) ->
|
|
431
|
+
r_bar: float = DEFAULT_REC_RATIO,
|
|
432
|
+
) -> decimal.Decimal:
|
|
447
433
|
"""
|
|
448
434
|
Symmetric-firm share for given GUPPI, margin, and recapture ratio.
|
|
449
435
|
|
{mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/core/guidelines_boundary_functions.py
RENAMED
|
@@ -5,7 +5,7 @@ from typing import Any, Literal, TypedDict
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
from mpmath import mp, mpf # type: ignore
|
|
7
7
|
|
|
8
|
-
from .. import
|
|
8
|
+
from .. import DEFAULT_REC_RATIO, VERSION, ArrayBIGINT, ArrayDouble # noqa: TID252
|
|
9
9
|
from . import MPFloat
|
|
10
10
|
|
|
11
11
|
__version__ = VERSION
|
|
@@ -34,7 +34,7 @@ class GuidelinesBoundary:
|
|
|
34
34
|
"""Area under the boundary."""
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def dh_area(
|
|
37
|
+
def dh_area(_delta_bound: float | MPFloat = 0.01, /, *, dps: int = 9) -> float:
|
|
38
38
|
R"""
|
|
39
39
|
Area under the ΔHHI boundary.
|
|
40
40
|
|
|
@@ -55,7 +55,7 @@ def dh_area(_dh_val: float | MPFloat = 0.01, /, *, dps: int = 9) -> float:
|
|
|
55
55
|
|
|
56
56
|
Parameters
|
|
57
57
|
----------
|
|
58
|
-
|
|
58
|
+
_delta_bound
|
|
59
59
|
Change in concentration.
|
|
60
60
|
dps
|
|
61
61
|
Specified precision in decimal places.
|
|
@@ -66,22 +66,26 @@ def dh_area(_dh_val: float | MPFloat = 0.01, /, *, dps: int = 9) -> float:
|
|
|
66
66
|
|
|
67
67
|
"""
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
_s_naught = (1 - mp.sqrt(1 - 2 *
|
|
69
|
+
_delta_bound = mpf(f"{_delta_bound}")
|
|
70
|
+
_s_naught = (1 - mp.sqrt(1 - 2 * _delta_bound)) / 2
|
|
71
71
|
|
|
72
72
|
return round(
|
|
73
|
-
float(
|
|
73
|
+
float(
|
|
74
|
+
_s_naught + (_delta_bound / 2) * (mp.ln(1 - _s_naught) - mp.ln(_s_naught))
|
|
75
|
+
),
|
|
74
76
|
dps,
|
|
75
77
|
)
|
|
76
78
|
|
|
77
79
|
|
|
78
|
-
def hhi_delta_boundary(
|
|
80
|
+
def hhi_delta_boundary(
|
|
81
|
+
_delta_bound: float | decimal.Decimal | MPFloat = 0.01, /, *, dps: int = 5
|
|
82
|
+
) -> GuidelinesBoundary:
|
|
79
83
|
"""
|
|
80
84
|
Generate the list of share combination on the ΔHHI boundary.
|
|
81
85
|
|
|
82
86
|
Parameters
|
|
83
87
|
----------
|
|
84
|
-
|
|
88
|
+
_delta_bound:
|
|
85
89
|
Merging-firms' ΔHHI bound.
|
|
86
90
|
dps
|
|
87
91
|
Number of decimal places for rounding reported shares.
|
|
@@ -92,33 +96,32 @@ def hhi_delta_boundary(_dh_val: float = 0.01, /, *, dps: int = 5) -> GuidelinesB
|
|
|
92
96
|
|
|
93
97
|
"""
|
|
94
98
|
|
|
95
|
-
|
|
96
|
-
_s_naught = 1 / 2 * (1 - mp.sqrt(1 - 2 *
|
|
97
|
-
_s_mid = mp.sqrt(
|
|
99
|
+
_delta_bound = mpf(f"{_delta_bound}")
|
|
100
|
+
_s_naught = 1 / 2 * (1 - mp.sqrt(1 - 2 * _delta_bound))
|
|
101
|
+
_s_mid = mp.sqrt(_delta_bound / 2)
|
|
98
102
|
|
|
99
103
|
_dh_step_sz = mp.power(10, -6)
|
|
100
104
|
_s_1 = np.array(mp.arange(_s_mid, _s_naught - mp.eps, -_dh_step_sz))
|
|
101
|
-
_s_2 = _dh_val / (2 * _s_1)
|
|
102
105
|
|
|
103
106
|
# Boundary points
|
|
104
107
|
_dh_half = np.vstack((
|
|
105
|
-
np.column_stack((_s_1,
|
|
108
|
+
np.column_stack((_s_1, _delta_bound / (2 * _s_1))).astype(np.float64),
|
|
106
109
|
np.array([(mpf("0.0"), mpf("1.0"))], np.float64),
|
|
107
110
|
))
|
|
108
111
|
_dh_bdry_pts = np.vstack((_dh_half[::-1], _dh_half[1:, ::-1]))
|
|
109
112
|
|
|
110
|
-
return GuidelinesBoundary(_dh_bdry_pts, dh_area(
|
|
113
|
+
return GuidelinesBoundary(_dh_bdry_pts, dh_area(_delta_bound, dps=dps))
|
|
111
114
|
|
|
112
115
|
|
|
113
116
|
def hhi_pre_contrib_boundary(
|
|
114
|
-
|
|
117
|
+
_hhi_bound: float | decimal.Decimal | MPFloat = 0.03125, /, *, dps: int = 5
|
|
115
118
|
) -> GuidelinesBoundary:
|
|
116
119
|
"""
|
|
117
120
|
Share combinations on the premerger HHI contribution boundary.
|
|
118
121
|
|
|
119
122
|
Parameters
|
|
120
123
|
----------
|
|
121
|
-
|
|
124
|
+
_hhi_bound:
|
|
122
125
|
Merging-firms' pre-merger HHI contribution bound.
|
|
123
126
|
dps
|
|
124
127
|
Number of decimal places for rounding reported shares.
|
|
@@ -128,23 +131,23 @@ def hhi_pre_contrib_boundary(
|
|
|
128
131
|
Array of share-pairs, area under boundary.
|
|
129
132
|
|
|
130
133
|
"""
|
|
131
|
-
|
|
132
|
-
_s_mid = mp.sqrt(
|
|
134
|
+
_hhi_bound = mpf(f"{_hhi_bound}")
|
|
135
|
+
_s_mid = mp.sqrt(_hhi_bound / 2)
|
|
133
136
|
|
|
134
137
|
_bdry_step_sz = mp.power(10, -dps)
|
|
135
138
|
# Range-limit is 0 less a step, which is -1 * step-size
|
|
136
139
|
_s_1 = np.array(mp.arange(_s_mid, -_bdry_step_sz, -_bdry_step_sz))
|
|
137
|
-
_s_2 = np.sqrt(
|
|
140
|
+
_s_2 = np.sqrt(_hhi_bound - _s_1**2)
|
|
138
141
|
_bdry_pts_mid = np.column_stack((_s_1, _s_2)).astype(np.float64)
|
|
139
142
|
|
|
140
143
|
return GuidelinesBoundary(
|
|
141
144
|
np.vstack((_bdry_pts_mid[::-1], _bdry_pts_mid[1:, ::-1])),
|
|
142
|
-
round(float(mp.pi *
|
|
145
|
+
round(float(mp.pi * _hhi_bound / 4), dps),
|
|
143
146
|
)
|
|
144
147
|
|
|
145
148
|
|
|
146
149
|
def combined_share_boundary(
|
|
147
|
-
_s_intcpt: float = 0.0625, /, *, dps: int = 10
|
|
150
|
+
_s_intcpt: float | decimal.Decimal | MPFloat = 0.0625, /, *, dps: int = 10
|
|
148
151
|
) -> GuidelinesBoundary:
|
|
149
152
|
"""
|
|
150
153
|
Share combinations on the merging-firms' combined share boundary.
|
|
@@ -168,18 +171,14 @@ def combined_share_boundary(
|
|
|
168
171
|
_s_intcpt = mpf(f"{_s_intcpt}")
|
|
169
172
|
_s_mid = _s_intcpt / 2
|
|
170
173
|
|
|
171
|
-
_s1_pts = (0, _s_mid, _s_intcpt)
|
|
174
|
+
_s1_pts = np.array([0, _s_mid, _s_intcpt], np.float64)
|
|
172
175
|
return GuidelinesBoundary(
|
|
173
|
-
np.column_stack((
|
|
174
|
-
np.array(_s1_pts, np.float64),
|
|
175
|
-
np.array(_s1_pts[::-1], np.float64),
|
|
176
|
-
)),
|
|
177
|
-
round(float(_s_intcpt * _s_mid), dps),
|
|
176
|
+
np.column_stack((_s1_pts, _s1_pts[::-1])), round(float(_s_intcpt * _s_mid), dps)
|
|
178
177
|
)
|
|
179
178
|
|
|
180
179
|
|
|
181
180
|
def hhi_post_contrib_boundary(
|
|
182
|
-
|
|
181
|
+
_hhi_bound: float | decimal.Decimal | MPFloat = 0.800, /, *, dps: int = 10
|
|
183
182
|
) -> GuidelinesBoundary:
|
|
184
183
|
"""
|
|
185
184
|
Share combinations on the postmerger HHI contribution boundary.
|
|
@@ -189,7 +188,7 @@ def hhi_post_contrib_boundary(
|
|
|
189
188
|
|
|
190
189
|
Parameters
|
|
191
190
|
----------
|
|
192
|
-
|
|
191
|
+
_hhi_bound:
|
|
193
192
|
Merging-firms' pre-merger HHI contribution bound.
|
|
194
193
|
dps
|
|
195
194
|
Number of decimal places for rounding reported shares.
|
|
@@ -199,12 +198,17 @@ def hhi_post_contrib_boundary(
|
|
|
199
198
|
Array of share-pairs, area under boundary.
|
|
200
199
|
|
|
201
200
|
"""
|
|
202
|
-
return combined_share_boundary(
|
|
201
|
+
return combined_share_boundary(
|
|
202
|
+
_hhi_bound.sqrt()
|
|
203
|
+
if isinstance(_hhi_bound, decimal.Decimal | mpf)
|
|
204
|
+
else np.sqrt(_hhi_bound),
|
|
205
|
+
dps=dps,
|
|
206
|
+
)
|
|
203
207
|
|
|
204
208
|
|
|
205
209
|
def shrratio_boundary_wtd_avg(
|
|
206
|
-
_delta_star: float = 0.075,
|
|
207
|
-
_r_val: float =
|
|
210
|
+
_delta_star: float | decimal.Decimal | MPFloat = 0.075,
|
|
211
|
+
_r_val: float = DEFAULT_REC_RATIO,
|
|
208
212
|
/,
|
|
209
213
|
*,
|
|
210
214
|
agg_method: Literal[
|
|
@@ -305,7 +309,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
305
309
|
_s_mid = mp.fdiv(_delta_star, 1 + _delta_star)
|
|
306
310
|
|
|
307
311
|
# initial conditions
|
|
308
|
-
_gbdry_points
|
|
312
|
+
_gbdry_points = [(_s_mid, _s_mid)]
|
|
309
313
|
_s_1_pre, _s_2_pre = _s_mid, _s_mid
|
|
310
314
|
_s_2_oddval, _s_2_oddsum, _s_2_evnsum = True, 0.0, 0.0
|
|
311
315
|
|
|
@@ -401,18 +405,18 @@ def shrratio_boundary_wtd_avg(
|
|
|
401
405
|
_gbdry_area_total = float(2 * _gbd_prtlarea - mp.power(_s_mid, "2"))
|
|
402
406
|
|
|
403
407
|
_gbdry_points.append((mpf("0.0"), _s_intcpt))
|
|
404
|
-
|
|
408
|
+
_gbdry_array = np.array(_gbdry_points).astype(np.float64)
|
|
405
409
|
|
|
406
410
|
# Points defining boundary to point-of-symmetry
|
|
407
411
|
return GuidelinesBoundary(
|
|
408
|
-
np.vstack((
|
|
412
|
+
np.vstack((_gbdry_array[::-1], _gbdry_array[1:, ::-1])),
|
|
409
413
|
round(float(_gbdry_area_total), dps),
|
|
410
414
|
)
|
|
411
415
|
|
|
412
416
|
|
|
413
417
|
def shrratio_boundary_xact_avg(
|
|
414
|
-
_delta_star: float = 0.075,
|
|
415
|
-
_r_val: float =
|
|
418
|
+
_delta_star: float | decimal.Decimal | MPFloat = 0.075,
|
|
419
|
+
_r_val: float = DEFAULT_REC_RATIO,
|
|
416
420
|
/,
|
|
417
421
|
*,
|
|
418
422
|
recapture_form: Literal["inside-out", "proportional"] = "inside-out",
|
|
@@ -566,8 +570,8 @@ def shrratio_boundary_xact_avg(
|
|
|
566
570
|
|
|
567
571
|
|
|
568
572
|
def shrratio_boundary_xact_avg_mp(
|
|
569
|
-
_delta_star: float = 0.075,
|
|
570
|
-
_r_val: float =
|
|
573
|
+
_delta_star: float | decimal.Decimal | MPFloat = 0.075,
|
|
574
|
+
_r_val: float = DEFAULT_REC_RATIO,
|
|
571
575
|
/,
|
|
572
576
|
*,
|
|
573
577
|
recapture_form: Literal["inside-out", "proportional"] = "inside-out",
|
|
@@ -721,8 +725,8 @@ def shrratio_boundary_xact_avg_mp(
|
|
|
721
725
|
|
|
722
726
|
|
|
723
727
|
def shrratio_boundary_min(
|
|
724
|
-
_delta_star: float = 0.075,
|
|
725
|
-
_r_val: float =
|
|
728
|
+
_delta_star: float | decimal.Decimal | MPFloat = 0.075,
|
|
729
|
+
_r_val: float = DEFAULT_REC_RATIO,
|
|
726
730
|
/,
|
|
727
731
|
*,
|
|
728
732
|
recapture_form: str = "inside-out",
|
|
@@ -788,7 +792,11 @@ def shrratio_boundary_min(
|
|
|
788
792
|
|
|
789
793
|
|
|
790
794
|
def shrratio_boundary_max(
|
|
791
|
-
_delta_star: float
|
|
795
|
+
_delta_star: float | decimal.Decimal | MPFloat = 0.075,
|
|
796
|
+
_r_val: float = DEFAULT_REC_RATIO,
|
|
797
|
+
/,
|
|
798
|
+
*,
|
|
799
|
+
dps: int = 10,
|
|
792
800
|
) -> GuidelinesBoundary:
|
|
793
801
|
"""
|
|
794
802
|
Share combinations on the minimum GUPPI boundary with symmetric
|
|
@@ -851,7 +859,9 @@ def _shrratio_boundary_intcpt(
|
|
|
851
859
|
),
|
|
852
860
|
2 * mpf(f"{_r_val}"),
|
|
853
861
|
)
|
|
854
|
-
case None if
|
|
862
|
+
case None if (
|
|
863
|
+
agg_method == "arithmetic mean" and recapture_form == "proportional"
|
|
864
|
+
):
|
|
855
865
|
_s_intcpt = mp.fsub(_delta_star + 1 / 2, mp.fabs(_delta_star - 1 / 2))
|
|
856
866
|
case _:
|
|
857
867
|
_s_intcpt = _s_2_pre
|
|
@@ -859,12 +869,9 @@ def _shrratio_boundary_intcpt(
|
|
|
859
869
|
return _s_intcpt
|
|
860
870
|
|
|
861
871
|
|
|
862
|
-
def lerp(
|
|
863
|
-
_x1:
|
|
864
|
-
|
|
865
|
-
_r: float | MPFloat = 0.25,
|
|
866
|
-
/,
|
|
867
|
-
) -> float | MPFloat | ArrayDouble:
|
|
872
|
+
def lerp[LerpT: (float, MPFloat, ArrayDouble, ArrayBIGINT)](
|
|
873
|
+
_x1: LerpT, _x2: LerpT, _r: float = 0.25, /
|
|
874
|
+
) -> LerpT:
|
|
868
875
|
"""
|
|
869
876
|
From the function of the same name in the C++ standard [2]_
|
|
870
877
|
|
|
@@ -901,19 +908,17 @@ def lerp(
|
|
|
901
908
|
return _x1
|
|
902
909
|
elif _r == 1:
|
|
903
910
|
return _x2
|
|
904
|
-
elif _r == 0.5:
|
|
905
|
-
return 1 / 2 * (_x1 + _x2)
|
|
906
911
|
else:
|
|
907
|
-
return _r * _x2 + (1 - _r) * _x1
|
|
912
|
+
return _r * _x2 + (1 - _r) * _x1 # pyright: ignore
|
|
908
913
|
|
|
909
914
|
|
|
910
915
|
def round_cust(
|
|
911
|
-
_num: float = 0.060215,
|
|
916
|
+
_num: float | decimal.Decimal | MPFloat = 0.060215,
|
|
912
917
|
/,
|
|
913
918
|
*,
|
|
914
919
|
frac: float = 0.005,
|
|
915
920
|
rounding_mode: str = "ROUND_HALF_UP",
|
|
916
|
-
) ->
|
|
921
|
+
) -> decimal.Decimal:
|
|
917
922
|
"""
|
|
918
923
|
Custom rounding, to the nearest 0.5% by default.
|
|
919
924
|
|
|
@@ -955,12 +960,12 @@ def round_cust(
|
|
|
955
960
|
):
|
|
956
961
|
raise ValueError(
|
|
957
962
|
f"Value, {f'"{rounding_mode}"'} is invalid for rounding_mode."
|
|
958
|
-
|
|
963
|
+
'Documentation for the, "decimal" built-in lists valid rounding modes.'
|
|
959
964
|
)
|
|
960
965
|
|
|
961
966
|
_n, _f, _e = (decimal.Decimal(f"{_g}") for _g in [_num, frac, 1])
|
|
962
967
|
|
|
963
|
-
return
|
|
968
|
+
return _f * (_n / _f).quantize(_e, rounding=rounding_mode)
|
|
964
969
|
|
|
965
970
|
|
|
966
971
|
def boundary_plot(*, mktshares_plot_flag: bool = True) -> tuple[Any, ...]:
|
|
@@ -16,7 +16,7 @@ from mpmath import mp, mpf # type: ignore
|
|
|
16
16
|
from scipy.spatial.distance import minkowski as distance_function # type: ignore
|
|
17
17
|
from sympy import lambdify, simplify, solve, symbols # type: ignore
|
|
18
18
|
|
|
19
|
-
from .. import
|
|
19
|
+
from .. import DEFAULT_REC_RATIO, VERSION, ArrayDouble # noqa: TID252
|
|
20
20
|
from . import guidelines_boundary_functions as gbfn
|
|
21
21
|
|
|
22
22
|
__version__ = VERSION
|
|
@@ -101,7 +101,7 @@ def hhi_delta_boundary_qdtr(_dh_val: float = 0.01, /) -> GuidelinesBoundaryCalla
|
|
|
101
101
|
|
|
102
102
|
def shrratio_boundary_qdtr_wtd_avg(
|
|
103
103
|
_delta_star: float = 0.075,
|
|
104
|
-
_r_val: float =
|
|
104
|
+
_r_val: float = DEFAULT_REC_RATIO,
|
|
105
105
|
/,
|
|
106
106
|
*,
|
|
107
107
|
weighting: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
@@ -220,7 +220,7 @@ def shrratio_boundary_qdtr_wtd_avg(
|
|
|
220
220
|
|
|
221
221
|
def shrratio_boundary_distance(
|
|
222
222
|
_delta_star: float = 0.075,
|
|
223
|
-
_r_val: float =
|
|
223
|
+
_r_val: float = DEFAULT_REC_RATIO,
|
|
224
224
|
/,
|
|
225
225
|
*,
|
|
226
226
|
agg_method: Literal["arithmetic mean", "distance"] = "arithmetic mean",
|
|
@@ -15,7 +15,7 @@ from attrs import Attribute, cmp_using, field, frozen, validators
|
|
|
15
15
|
from numpy.random import SeedSequence
|
|
16
16
|
|
|
17
17
|
from .. import ( # noqa: TID252
|
|
18
|
-
|
|
18
|
+
DEFAULT_REC_RATIO,
|
|
19
19
|
VERSION,
|
|
20
20
|
ArrayBIGINT,
|
|
21
21
|
ArrayBoolean,
|
|
@@ -183,7 +183,7 @@ class ShareSpec:
|
|
|
183
183
|
recapture_form: RECForm = field(default=RECForm.INOUT)
|
|
184
184
|
"""See :class:`mergeron.RECForm`"""
|
|
185
185
|
|
|
186
|
-
recapture_ratio: float | None = field(default=
|
|
186
|
+
recapture_ratio: float | None = field(default=DEFAULT_REC_RATIO)
|
|
187
187
|
"""A value between 0 and 1.
|
|
188
188
|
|
|
189
189
|
:code:`None` if market share specification requires direct generation of
|
|
@@ -194,8 +194,7 @@ class ShareSpec:
|
|
|
194
194
|
in published merger guidelines. Accordingly, the recapture ratio rounded to
|
|
195
195
|
the nearest 5% is:
|
|
196
196
|
|
|
197
|
-
* 0.85, **7-to-6 merger from symmetry**; US Guidelines, 1992, 2023
|
|
198
|
-
* 0.80, **6-to-5 merger to symmetry**; EU Guidelines for horizontal mergers, 2004
|
|
197
|
+
* 0.85, **7-to-6 merger from symmetry**; US Guidelines, 1982, 1984, 1992, 2023
|
|
199
198
|
* 0.80, 5-to-4 merger from symmetry
|
|
200
199
|
* 0.80, **5-to-4 merger to symmetry**; US Guidelines, 2010
|
|
201
200
|
|
|
@@ -13,7 +13,7 @@ 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
|
|
16
|
+
from .. import DEFAULT_REC_RATIO, 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 (
|
|
@@ -74,7 +74,7 @@ class MarketSample:
|
|
|
74
74
|
share_spec: ShareSpec = field(
|
|
75
75
|
kw_only=True,
|
|
76
76
|
default=ShareSpec(
|
|
77
|
-
SHRDistribution.UNI, None, None, RECForm.INOUT,
|
|
77
|
+
SHRDistribution.UNI, None, None, RECForm.INOUT, DEFAULT_REC_RATIO
|
|
78
78
|
),
|
|
79
79
|
validator=validators.instance_of(ShareSpec),
|
|
80
80
|
)
|
{mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/gen/data_generation_functions.py
RENAMED
|
@@ -11,7 +11,7 @@ import numpy as np
|
|
|
11
11
|
from attrs import evolve
|
|
12
12
|
from numpy.random import SeedSequence
|
|
13
13
|
|
|
14
|
-
from .. import
|
|
14
|
+
from .. import DEFAULT_REC_RATIO, VERSION, ArrayDouble, RECForm # noqa: TID252
|
|
15
15
|
from ..core.empirical_margin_distribution import mgn_data_resampler # noqa: TID252
|
|
16
16
|
from ..core.pseudorandom_numbers import ( # noqa: TID252
|
|
17
17
|
DEFAULT_DIST_PARMS,
|
|
@@ -100,7 +100,7 @@ def gen_share_data(
|
|
|
100
100
|
|
|
101
101
|
# If recapture_form == "inside-out", recalculate _aggregate_purchase_prob
|
|
102
102
|
_frmshr_array = _mkt_share_sample.mktshr_array[:, :2]
|
|
103
|
-
_r_bar = _share_spec.recapture_ratio or
|
|
103
|
+
_r_bar = _share_spec.recapture_ratio or DEFAULT_REC_RATIO
|
|
104
104
|
if _recapture_form == RECForm.INOUT:
|
|
105
105
|
_mkt_share_sample = ShareDataSample(
|
|
106
106
|
_mkt_share_sample.mktshr_array,
|
|
@@ -266,7 +266,7 @@ def gen_market_shares_dirichlet_multimarket(
|
|
|
266
266
|
else:
|
|
267
267
|
|
|
268
268
|
def _gen_dir_alphas(_fcv: int) -> ArrayDouble:
|
|
269
|
-
return np.array(_dir_alphas_full[:_fcv], dtype=np.float64)
|
|
269
|
+
return np.array(_dir_alphas_full[:_fcv], dtype=np.float64)
|
|
270
270
|
|
|
271
271
|
_fcounts = prng(_fcount_rng_seed_seq).choice(
|
|
272
272
|
_fcount_keys, size=(_s_size, 1), p=_choice_wts
|
|
@@ -604,8 +604,7 @@ def gen_margin_price_data(
|
|
|
604
604
|
del _price_array_here
|
|
605
605
|
case _:
|
|
606
606
|
raise ValueError(
|
|
607
|
-
f
|
|
608
|
-
f' "{_price_spec.value}" is invalid.'
|
|
607
|
+
f'Specification of price distribution, "{_price_spec.value}" is invalid.'
|
|
609
608
|
)
|
|
610
609
|
if _price_spec != PriceSpec.CSY:
|
|
611
610
|
_margin_data = _gen_margin_data(
|
|
@@ -373,7 +373,7 @@ def save_array_to_hdf5(
|
|
|
373
373
|
*,
|
|
374
374
|
saved_array_name_suffix: str | None = None,
|
|
375
375
|
) -> None:
|
|
376
|
-
_h5_array_name = f"{_array_name}_{saved_array_name_suffix or
|
|
376
|
+
_h5_array_name = f"{_array_name}_{saved_array_name_suffix or ''}".rstrip("_")
|
|
377
377
|
|
|
378
378
|
with suppress(ptb.NoSuchNodeError):
|
|
379
379
|
_h5_file.remove_node(_h5_group, name=_array_name)
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
mergeron
|
|
2
|
-
========
|
|
3
|
-
|
|
4
|
-
Copyright 2017-2024 S. Murthy Kambhampaty
|
|
5
|
-
|
|
6
|
-
MIT License
|
|
7
|
-
-----------
|
|
8
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
9
|
-
|
|
10
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
11
|
-
|
|
12
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
13
|
-
|
|
14
|
-
Exceptions
|
|
15
|
-
----------
|
|
16
|
-
Modules provided in the mergeron.ext subpackage are redistributed under the license published within each module.
|
|
File without changes
|
|
File without changes
|
{mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/core/empirical_margin_distribution.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mergeron-2024.739145.3 → mergeron-2024.739145.5}/src/mergeron/data/damodaran_margin_data.xls
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|