mergeron 2024.738936.2__tar.gz → 2024.738940.0__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.738936.2 → mergeron-2024.738940.0}/PKG-INFO +1 -1
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/pyproject.toml +1 -1
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/core/excel_helper.py +4 -2
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/core/guidelines_standards.py +137 -83
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/concentration_as_diversion.py +30 -30
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/investigations_stats_sim_tables.py +22 -29
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/safeharbor_boundaries_for_mergers_with_asymmetric_shares.py +13 -13
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/safeharbor_boundaries_for_symmetric_firm_mergers.py +3 -3
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/sound_guppi_safeharbor.py +31 -28
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/testIntrinsicClearanceRates.py +12 -12
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/visualize_guidelines_tests.py +34 -29
- mergeron-2024.738940.0/src/mergeron/gen/__init__.py +468 -0
- mergeron-2024.738940.0/src/mergeron/gen/_data_generation_functions_nonpublic.py +626 -0
- mergeron-2024.738940.0/src/mergeron/gen/data_generation.py +285 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/gen/guidelines_tests.py +122 -99
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/gen/investigations_stats.py +10 -12
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/jinja_LaTex_templates/clrrate_cis_summary_table_template.tex.jinja2 +1 -1
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/jinja_LaTex_templates/ftcinvdata_summarypaired_table_template.tex.jinja2 +1 -1
- mergeron-2024.738936.2/src/mergeron/gen/__init__.py +0 -5
- mergeron-2024.738936.2/src/mergeron/gen/data_generation.py +0 -1229
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/README.rst +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/License.txt +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/__init__.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/core/InCommon RSA Server CA cert chain.pem +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/core/__init__.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/core/damodaran_margin_data.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/core/ftc_merger_investigations_data.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/core/proportions_tests.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/core/pseudorandom_numbers.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/__init__.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/example_parameterizations.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/guidelines_enforcement_patterns.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/investigations_stats_obs_tables.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/plotSafeHarbs_symbolically.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/summarize_ftc_investigations_data.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/examples/visualize_empirical_margin_distribution.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/ext/__init__.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/ext/tol_colors.py +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/jinja_LaTex_templates/ftcinvdata_byhhianddelta_table_template.tex.jinja2 +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/jinja_LaTex_templates/ftcinvdata_summary_table_template.tex.jinja2 +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/jinja_LaTex_templates/mergeron.cls +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/jinja_LaTex_templates/mergeron_table_collection_template.tex.jinja2 +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/jinja_LaTex_templates/setup_tikz_tables.tex.jinja2 +0 -0
- {mergeron-2024.738936.2 → mergeron-2024.738940.0}/src/mergeron/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mergeron
|
|
3
|
-
Version: 2024.
|
|
3
|
+
Version: 2024.738940.0
|
|
4
4
|
Summary: Analysis of standards defined in Horizontal Merger Guidelines
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: merger policy analysis,merger guidelines,merger screening,policy presumptions,concentration standards,upward pricing pressure,GUPPI
|
|
@@ -6,6 +6,8 @@ Includes a flexible system of defining cell formats.
|
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
9
11
|
from importlib.metadata import version
|
|
10
12
|
|
|
11
13
|
from .. import _PKG_NAME # noqa: TID252
|
|
@@ -126,7 +128,7 @@ def matrix_to_sheet(
|
|
|
126
128
|
elif isinstance(cell_format, CFmt):
|
|
127
129
|
_cell_format = (cell_format,) * len(_data_array[0])
|
|
128
130
|
else:
|
|
129
|
-
_cell_format = (CFmt.XL_DEFAULT,) * len(_data_array[0])
|
|
131
|
+
_cell_format = (CFmt.XL_DEFAULT,) * len(_data_array[0]) # type: ignore
|
|
130
132
|
|
|
131
133
|
for _cell_row in range(_row_id, _bottom_row_id):
|
|
132
134
|
for _cell_col in range(_col_id, _right_column_id):
|
|
@@ -222,7 +224,7 @@ def xl_fmt(
|
|
|
222
224
|
elif isinstance(_cell_fmt, CFmt):
|
|
223
225
|
_cell_fmt_dict = _cell_fmt.value
|
|
224
226
|
else:
|
|
225
|
-
_cell_fmt_dict = CFmt.XL_DEFAULT.value
|
|
227
|
+
_cell_fmt_dict = CFmt.XL_DEFAULT.value # type: ignore
|
|
226
228
|
|
|
227
229
|
return _xl_book.add_format(_cell_fmt_dict)
|
|
228
230
|
|
|
@@ -4,7 +4,6 @@ with a canvas on which to draw boundaries for Guidelines standards.
|
|
|
4
4
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from collections import namedtuple
|
|
8
7
|
from importlib.metadata import version
|
|
9
8
|
|
|
10
9
|
from .. import _PKG_NAME # noqa: TID252
|
|
@@ -12,9 +11,11 @@ from .. import _PKG_NAME # noqa: TID252
|
|
|
12
11
|
__version__ = version(_PKG_NAME)
|
|
13
12
|
|
|
14
13
|
import decimal
|
|
14
|
+
from dataclasses import dataclass
|
|
15
15
|
from typing import Any, Literal, TypeAlias
|
|
16
16
|
|
|
17
17
|
import numpy as np
|
|
18
|
+
from attr import define, field
|
|
18
19
|
from mpmath import mp, mpf # type: ignore
|
|
19
20
|
from numpy.typing import NDArray
|
|
20
21
|
from scipy.spatial.distance import minkowski as distance_function
|
|
@@ -23,9 +24,25 @@ mp.prec = 80
|
|
|
23
24
|
mp.trap_complex = True
|
|
24
25
|
|
|
25
26
|
HMGPubYear: TypeAlias = Literal[1992, 2010, 2023]
|
|
26
|
-
GuidelinesSTD = namedtuple("GuidelinesSTD", "delta rec guppi divr cmcr ipr")
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
@dataclass(slots=True, frozen=True)
|
|
30
|
+
class GuidelinesBoundary:
|
|
31
|
+
coordinates: NDArray[np.float64]
|
|
32
|
+
area: float
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@define(slots=True, frozen=True)
|
|
36
|
+
class GuidelinesSTD:
|
|
37
|
+
delta: float
|
|
38
|
+
rec: float
|
|
39
|
+
guppi: float
|
|
40
|
+
divr: float
|
|
41
|
+
cmcr: float
|
|
42
|
+
ipr: float
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@define(slots=True, frozen=True)
|
|
29
46
|
class GuidelinesStandards:
|
|
30
47
|
"""
|
|
31
48
|
Guidelines standards by Guidelines publication year
|
|
@@ -33,76 +50,100 @@ class GuidelinesStandards:
|
|
|
33
50
|
Diversion ratio, GUPPI, CMCR, and IPR standards are constructed from
|
|
34
51
|
concentration standards.
|
|
35
52
|
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
"""
|
|
54
|
+
|
|
38
55
|
pub_year: HMGPubYear
|
|
39
|
-
Year of publication of the U.S. Horizontal Merger Guidelines (HMG);
|
|
40
|
-
1992, 2010, or 2023
|
|
41
|
-
safeharbor: GuidelinesSTD
|
|
42
|
-
ΔHHI safeharbor bound, default recapture rate, GUPPI bound and
|
|
43
|
-
diversion ratio limit at ΔHHI safeharbor
|
|
44
|
-
inferred_presumption: GuidelinesSTD
|
|
45
|
-
ΔHHI safeharbor bound, default recapture rate, GUPPI bound and
|
|
46
|
-
diversion ratio limit at enforcement margin for Guidelines
|
|
47
|
-
presumption of harm, interpreted strictly
|
|
48
|
-
presumption: GuidelinesSTD
|
|
49
|
-
ΔHHI safeharbor bound, default recapture rate, GUPPI bound and
|
|
50
|
-
diversion ratio limit at enforcement margin for Guidelines
|
|
51
|
-
presumption of harm, as typically interpreted in the literature
|
|
52
|
-
on merger enforcement
|
|
53
56
|
"""
|
|
57
|
+
Year of publication of the U.S. Horizontal Merger Guidelines (HMG)
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
safeharbor: GuidelinesSTD = field(kw_only=True, default=None)
|
|
61
|
+
"""
|
|
62
|
+
Negative presumption defined on various measures
|
|
54
63
|
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
ΔHHI safeharbor bound, default recapture rate, GUPPI bound,
|
|
65
|
+
diversion ratio limit, CMCR, and IPR
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
inferred_presumption: GuidelinesSTD = field(kw_only=True, default=None)
|
|
69
|
+
"""
|
|
70
|
+
Inferred ΔHHI safeharbor presumption and related measures
|
|
71
|
+
|
|
72
|
+
ΔHHI bound inferred from strict numbers-equivalent
|
|
73
|
+
of (post-merger) HHI presumption, and corresponding default recapture rate,
|
|
74
|
+
GUPPI bound, diversion ratio limit, CMCR, and IPR
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
presumption: GuidelinesSTD = field(kw_only=True, default=None)
|
|
78
|
+
"""
|
|
79
|
+
Guidelines ΔHHI safeharbor presumption and related measures
|
|
80
|
+
|
|
81
|
+
ΔHHI bound and corresponding default recapture rate, GUPPI bound,
|
|
82
|
+
diversion ratio limit, CMCR, and IPR
|
|
83
|
+
"""
|
|
57
84
|
|
|
58
|
-
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
# the
|
|
85
|
+
def __attrs_post_init__(self, /):
|
|
86
|
+
# In the 2023 Guidlines, the agencies do not define a
|
|
87
|
+
# negative presumption, or safeharbor. Practically speaking,
|
|
88
|
+
# given resource constraints and loss aversion, it is likely
|
|
89
|
+
# that staff only investigates mergers that meet the presumption;
|
|
90
|
+
# thus, here, the tentative delta safeharbor under
|
|
91
|
+
# the 2023 Guidelines is 100 points
|
|
63
92
|
_hhi_p, _dh_s, _dh_p = {
|
|
64
93
|
1992: (0.18, 0.005, 0.01),
|
|
65
94
|
2010: (0.25, 0.01, 0.02),
|
|
66
95
|
2023: (0.18, 0.01, 0.01),
|
|
67
|
-
}[
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
96
|
+
}[self.pub_year]
|
|
97
|
+
|
|
98
|
+
object.__setattr__(
|
|
99
|
+
self,
|
|
100
|
+
"safeharbor",
|
|
101
|
+
GuidelinesSTD(
|
|
102
|
+
_dh_s,
|
|
103
|
+
_r := round_cust((_fc := int(np.ceil(1 / _hhi_p))) / (_fc + 1)),
|
|
104
|
+
_g_s := gbd_from_dsf(_dh_s, m_star=1.0, r_bar=_r),
|
|
105
|
+
_dr := round_cust(1 / (_fc + 1)),
|
|
106
|
+
_cmcr := 0.03, # Not strictly a Guidelines standard
|
|
107
|
+
_ipr := _g_s, # Not strictly a Guidelines standard
|
|
108
|
+
),
|
|
76
109
|
)
|
|
77
110
|
|
|
78
111
|
# inferred_presumption is relevant for 2010 Guidelines
|
|
79
|
-
|
|
112
|
+
object.__setattr__(
|
|
113
|
+
self,
|
|
114
|
+
"inferred_presumption",
|
|
115
|
+
(
|
|
116
|
+
GuidelinesSTD(
|
|
117
|
+
_dh_i := 2 * (0.5 / _fc) ** 2,
|
|
118
|
+
_r_i := round_cust((_fc - 1 / 2) / (_fc + 1 / 2)),
|
|
119
|
+
_g_i := gbd_from_dsf(_dh_i, m_star=1.0, r_bar=_r_i),
|
|
120
|
+
round_cust((1 / 2) / (_fc - 1 / 2)),
|
|
121
|
+
_cmcr,
|
|
122
|
+
_g_i,
|
|
123
|
+
)
|
|
124
|
+
if self.pub_year == 2010
|
|
125
|
+
else GuidelinesSTD(
|
|
126
|
+
_dh_i := 2 * (1 / (_fc + 1)) ** 2,
|
|
127
|
+
_r,
|
|
128
|
+
_g_i := gbd_from_dsf(_dh_i, m_star=1.0, r_bar=_r),
|
|
129
|
+
_dr,
|
|
130
|
+
_cmcr,
|
|
131
|
+
_g_i,
|
|
132
|
+
)
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
object.__setattr__(
|
|
137
|
+
self,
|
|
138
|
+
"presumption",
|
|
80
139
|
GuidelinesSTD(
|
|
81
|
-
|
|
140
|
+
_dh_p,
|
|
82
141
|
_r,
|
|
83
|
-
|
|
142
|
+
_g_p := gbd_from_dsf(_dh_p, m_star=1.0, r_bar=_r),
|
|
84
143
|
_dr,
|
|
85
144
|
_cmcr,
|
|
86
|
-
|
|
87
|
-
)
|
|
88
|
-
if _pub_year in (1992, 2023)
|
|
89
|
-
else GuidelinesSTD(
|
|
90
|
-
_dh_i := 2 * (_s := 0.5 / _fc) * _s,
|
|
91
|
-
_r_i := round_cust((_fc - 1 / 2) / (_fc + 1 / 2)),
|
|
92
|
-
_g_i := gbd_from_dsf(_dh_i, m_star=1.0, r_bar=_r_i),
|
|
93
|
-
round_cust((1 / 2) / (_fc - 1 / 2)),
|
|
94
|
-
_cmcr,
|
|
95
|
-
_g_i,
|
|
96
|
-
)
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
self.presumption = GuidelinesSTD(
|
|
100
|
-
_dh_p,
|
|
101
|
-
_r,
|
|
102
|
-
_g_p := gbd_from_dsf(_dh_p, m_star=1.0, r_bar=_r),
|
|
103
|
-
_dr,
|
|
104
|
-
_cmcr,
|
|
105
|
-
_ipr := _g_p,
|
|
145
|
+
_ipr := _g_p,
|
|
146
|
+
),
|
|
106
147
|
)
|
|
107
148
|
|
|
108
149
|
|
|
@@ -521,7 +562,7 @@ def dh_area_quad(_dh_val: float = 0.01, /, *, dh_dps: int = 9) -> float:
|
|
|
521
562
|
|
|
522
563
|
def delta_hhi_boundary(
|
|
523
564
|
_dh_val: float = 0.01, /, *, dh_dps: int = 5
|
|
524
|
-
) ->
|
|
565
|
+
) -> GuidelinesBoundary:
|
|
525
566
|
"""
|
|
526
567
|
Generate the list of share combination on the ΔHHI boundary.
|
|
527
568
|
|
|
@@ -557,7 +598,7 @@ def delta_hhi_boundary(
|
|
|
557
598
|
_dh_bdry_pts = np.row_stack((np.flip(_dh_half, 0), np.flip(_dh_half[1:], 1)))
|
|
558
599
|
|
|
559
600
|
_s_1_pts, _s_2_pts = np.split(_dh_bdry_pts, 2, axis=1)
|
|
560
|
-
return (
|
|
601
|
+
return GuidelinesBoundary(
|
|
561
602
|
np.column_stack((
|
|
562
603
|
np.array(_s_1_pts, np.float64),
|
|
563
604
|
np.array(_s_2_pts, np.float64),
|
|
@@ -568,7 +609,7 @@ def delta_hhi_boundary(
|
|
|
568
609
|
|
|
569
610
|
def combined_share_boundary(
|
|
570
611
|
_s_intcpt: float = 0.0625, /, *, bdry_dps: int = 10
|
|
571
|
-
) ->
|
|
612
|
+
) -> GuidelinesBoundary:
|
|
572
613
|
"""
|
|
573
614
|
Share combinations on the merging-firms' combined share boundary.
|
|
574
615
|
|
|
@@ -592,7 +633,7 @@ def combined_share_boundary(
|
|
|
592
633
|
_s_mid = _s_intcpt / 2
|
|
593
634
|
|
|
594
635
|
_s1_pts = (0, _s_mid, _s_intcpt)
|
|
595
|
-
return (
|
|
636
|
+
return GuidelinesBoundary(
|
|
596
637
|
np.column_stack((
|
|
597
638
|
np.array(_s1_pts, np.float64),
|
|
598
639
|
np.array(_s1_pts[::-1], np.float64),
|
|
@@ -603,7 +644,7 @@ def combined_share_boundary(
|
|
|
603
644
|
|
|
604
645
|
def hhi_pre_contrib_boundary(
|
|
605
646
|
_hhi_contrib: float = 0.03125, /, *, bdry_dps: int = 5
|
|
606
|
-
) ->
|
|
647
|
+
) -> GuidelinesBoundary:
|
|
607
648
|
"""
|
|
608
649
|
Share combinations on the premerger HHI contribution boundary.
|
|
609
650
|
|
|
@@ -627,15 +668,15 @@ def hhi_pre_contrib_boundary(
|
|
|
627
668
|
_s_1 = np.array(mp.arange(_s_mid, -_bdry_step_sz, -_bdry_step_sz), np.float64)
|
|
628
669
|
_s_2 = np.sqrt(_hhi_contrib - _s_1**2).astype(np.float64)
|
|
629
670
|
_bdry_pts_mid = np.column_stack((_s_1, _s_2))
|
|
630
|
-
return (
|
|
671
|
+
return GuidelinesBoundary(
|
|
631
672
|
np.row_stack((np.flip(_bdry_pts_mid, 0), np.flip(_bdry_pts_mid[1:], 1))),
|
|
632
673
|
round(float(mp.pi * _hhi_contrib / 4), bdry_dps),
|
|
633
674
|
)
|
|
634
675
|
|
|
635
676
|
|
|
636
|
-
def
|
|
677
|
+
def shrratio_boundary_max(
|
|
637
678
|
_delta_star: float = 0.075, _r_val: float = 0.80, /, *, gbd_dps: int = 10
|
|
638
|
-
) ->
|
|
679
|
+
) -> GuidelinesBoundary:
|
|
639
680
|
"""
|
|
640
681
|
Share combinations on the minimum GUPPI boundary with symmetric
|
|
641
682
|
merging-firm margins.
|
|
@@ -670,7 +711,7 @@ def shrratio_mgnsym_boundary_max(
|
|
|
670
711
|
|
|
671
712
|
_s1_pts = (0, _s_mid, _s_intcpt)
|
|
672
713
|
|
|
673
|
-
return (
|
|
714
|
+
return GuidelinesBoundary(
|
|
674
715
|
np.column_stack((
|
|
675
716
|
np.array(_s1_pts, np.float64),
|
|
676
717
|
np.array(_s1_pts[::-1], np.float64),
|
|
@@ -679,14 +720,14 @@ def shrratio_mgnsym_boundary_max(
|
|
|
679
720
|
)
|
|
680
721
|
|
|
681
722
|
|
|
682
|
-
def
|
|
723
|
+
def shrratio_boundary_min(
|
|
683
724
|
_delta_star: float = 0.075,
|
|
684
725
|
_r_val: float = 0.80,
|
|
685
726
|
/,
|
|
686
727
|
*,
|
|
687
728
|
recapture_spec: str = "inside-out",
|
|
688
729
|
gbd_dps: int = 10,
|
|
689
|
-
) ->
|
|
730
|
+
) -> GuidelinesBoundary:
|
|
690
731
|
"""
|
|
691
732
|
Share combinations on the minimum GUPPI boundary, with symmetric
|
|
692
733
|
merging-firm margins.
|
|
@@ -749,10 +790,12 @@ def shrratio_mgnsym_boundary_min(
|
|
|
749
790
|
else:
|
|
750
791
|
_s1_pts, _gbd_area = np.array((0, _s_mid, _s_intcpt), np.float64), _s_mid
|
|
751
792
|
|
|
752
|
-
return
|
|
793
|
+
return GuidelinesBoundary(
|
|
794
|
+
np.column_stack((_s1_pts, _s1_pts[::-1])), round(float(_gbd_area), gbd_dps)
|
|
795
|
+
)
|
|
753
796
|
|
|
754
797
|
|
|
755
|
-
def
|
|
798
|
+
def shrratio_boundary_wtd_avg(
|
|
756
799
|
_delta_star: float = 0.075,
|
|
757
800
|
_r_val: float = 0.80,
|
|
758
801
|
/,
|
|
@@ -761,7 +804,7 @@ def shrratio_mgnsym_boundary_wtd_avg(
|
|
|
761
804
|
wgtng_policy: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
762
805
|
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
763
806
|
gbd_dps: int = 5,
|
|
764
|
-
) ->
|
|
807
|
+
) -> GuidelinesBoundary:
|
|
765
808
|
"""
|
|
766
809
|
Share combinations for the share-weighted average GUPPI boundary with symmetric
|
|
767
810
|
merging-firm margins.
|
|
@@ -947,20 +990,20 @@ def shrratio_mgnsym_boundary_wtd_avg(
|
|
|
947
990
|
np.float64
|
|
948
991
|
)
|
|
949
992
|
# Points defining boundary to point-of-symmetry
|
|
950
|
-
return (
|
|
993
|
+
return GuidelinesBoundary(
|
|
951
994
|
np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
|
|
952
995
|
round(float(_gbdry_area_total), gbd_dps),
|
|
953
996
|
)
|
|
954
997
|
|
|
955
998
|
|
|
956
|
-
def
|
|
999
|
+
def shrratio_boundary_xact_avg(
|
|
957
1000
|
_delta_star: float = 0.075,
|
|
958
1001
|
_r_val: float = 0.80,
|
|
959
1002
|
/,
|
|
960
1003
|
*,
|
|
961
1004
|
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
962
1005
|
gbd_dps: int = 5,
|
|
963
|
-
) ->
|
|
1006
|
+
) -> GuidelinesBoundary:
|
|
964
1007
|
"""
|
|
965
1008
|
Share combinations for the simple average GUPPI boundary with symmetric
|
|
966
1009
|
merging-firm margins.
|
|
@@ -1115,13 +1158,13 @@ def shrratio_mgnsym_boundary_xact_avg(
|
|
|
1115
1158
|
) - np.power(_s_mid, 2)
|
|
1116
1159
|
|
|
1117
1160
|
_s_1_pts, _s_2_pts = np.split(_gbdry_points, 2, axis=1)
|
|
1118
|
-
return (
|
|
1161
|
+
return GuidelinesBoundary(
|
|
1119
1162
|
np.column_stack((np.array(_s_1_pts), np.array(_s_2_pts))),
|
|
1120
1163
|
round(float(_gbdry_area_simpson), gbd_dps),
|
|
1121
1164
|
)
|
|
1122
1165
|
|
|
1123
1166
|
|
|
1124
|
-
def
|
|
1167
|
+
def shrratio_boundary_avg(
|
|
1125
1168
|
_delta_star: float = 0.075,
|
|
1126
1169
|
_r_val: float = 0.80,
|
|
1127
1170
|
/,
|
|
@@ -1129,12 +1172,16 @@ def shrratio_mgnsym_boundary_avg(
|
|
|
1129
1172
|
avg_method: Literal["arithmetic", "geometric", "distance"] = "arithmetic",
|
|
1130
1173
|
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
1131
1174
|
gbd_dps: int = 5,
|
|
1132
|
-
) ->
|
|
1175
|
+
) -> GuidelinesBoundary:
|
|
1133
1176
|
"""
|
|
1134
1177
|
Share combinations along the average GUPPI boundary, with
|
|
1135
1178
|
symmetric merging-firm margins.
|
|
1136
1179
|
|
|
1137
|
-
|
|
1180
|
+
Reimplements the unweighted average and distance estimations from function,
|
|
1181
|
+
`shrratio_boundary_wtd_avg`. This reimplementation
|
|
1182
|
+
is primarifly useful for testing the output of `shrratio_boundary_wtd_avg`
|
|
1183
|
+
as it tests considerably slower.
|
|
1184
|
+
|
|
1138
1185
|
|
|
1139
1186
|
Parameters
|
|
1140
1187
|
----------
|
|
@@ -1234,13 +1281,13 @@ def shrratio_mgnsym_boundary_avg(
|
|
|
1234
1281
|
) - mp.power(_s_mid, 2)
|
|
1235
1282
|
|
|
1236
1283
|
_gbdry_points = np.array(_gbdry_points, np.float64)
|
|
1237
|
-
return (
|
|
1284
|
+
return GuidelinesBoundary(
|
|
1238
1285
|
np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
|
|
1239
1286
|
round(float(_gbd_prtlarea), gbd_dps),
|
|
1240
1287
|
)
|
|
1241
1288
|
|
|
1242
1289
|
|
|
1243
|
-
def
|
|
1290
|
+
def shrratio_boundary_distance(
|
|
1244
1291
|
_delta_star: float = 0.075,
|
|
1245
1292
|
_r_val: float = 0.80,
|
|
1246
1293
|
/,
|
|
@@ -1249,9 +1296,16 @@ def shrratio_mgnsym_boundary_distance(
|
|
|
1249
1296
|
wgtng_policy: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
1250
1297
|
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
1251
1298
|
gbd_dps: int = 5,
|
|
1252
|
-
) ->
|
|
1299
|
+
) -> GuidelinesBoundary:
|
|
1253
1300
|
"""
|
|
1254
|
-
Share combinations for the GUPPI boundaries using various aggregators with
|
|
1301
|
+
Share combinations for the GUPPI boundaries using various aggregators with
|
|
1302
|
+
symmetric merging-firm margins.
|
|
1303
|
+
|
|
1304
|
+
Reimplements the arithmetic-averages and distance estimations from function,
|
|
1305
|
+
`shrratio_boundary_wtd_avg`but uses the Minkowski-distance function,
|
|
1306
|
+
`scipy.spatial.distance.minkowski` for all aggregators. This reimplementation
|
|
1307
|
+
is primarifly useful for testing the output of `shrratio_boundary_wtd_avg`
|
|
1308
|
+
as it tests considerably slower.
|
|
1255
1309
|
|
|
1256
1310
|
Parameters
|
|
1257
1311
|
----------
|
|
@@ -1389,7 +1443,7 @@ def shrratio_mgnsym_boundary_distance(
|
|
|
1389
1443
|
np.float64
|
|
1390
1444
|
)
|
|
1391
1445
|
# Points defining boundary to point-of-symmetry
|
|
1392
|
-
return (
|
|
1446
|
+
return GuidelinesBoundary(
|
|
1393
1447
|
np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
|
|
1394
1448
|
round(float(_gbdry_area_total), gbd_dps),
|
|
1395
1449
|
)
|
|
@@ -26,13 +26,13 @@ from math import sqrt
|
|
|
26
26
|
from pathlib import Path
|
|
27
27
|
from typing import Any, Literal
|
|
28
28
|
|
|
29
|
-
import matplotlib.
|
|
29
|
+
import matplotlib.axes as mpa
|
|
30
30
|
from joblib import Parallel, cpu_count, delayed
|
|
31
31
|
from numpy import pi
|
|
32
32
|
from xlsxwriter import Workbook
|
|
33
33
|
|
|
34
34
|
import mergeron.core.excel_helper as xlh
|
|
35
|
-
import mergeron.core.guidelines_standards as
|
|
35
|
+
import mergeron.core.guidelines_standards as gsl
|
|
36
36
|
import mergeron.ext.tol_colors as ptcolor
|
|
37
37
|
from mergeron import DATA_DIR
|
|
38
38
|
|
|
@@ -46,20 +46,20 @@ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
|
|
|
46
46
|
"title_str": "ΔHHI boundary",
|
|
47
47
|
"sheet_name": "ΔHHI",
|
|
48
48
|
"func_str": R"\Delta HHI",
|
|
49
|
-
"func":
|
|
49
|
+
"func": gsl.delta_hhi_boundary,
|
|
50
50
|
},
|
|
51
51
|
"OSWAG Own-shr-wtd Div Ratio Index": {
|
|
52
52
|
"title_str": "Aggregated-diversion-ratio boundary, own-share wtd. avg.",
|
|
53
53
|
"sheet_name": "OSWAG, wtd avg",
|
|
54
54
|
"func_str": R"(s_1 d_{12} + s_2 d_{21}) / s_M",
|
|
55
|
-
"func":
|
|
55
|
+
"func": gsl.shrratio_boundary_wtd_avg,
|
|
56
56
|
"func_kwargs": {"wgtng_policy": "own-share", "recapture_spec": RECAPTURE_SPEC},
|
|
57
57
|
},
|
|
58
58
|
"OSWAG Own-shr-wtd Div Ratio Distance": {
|
|
59
59
|
"title_str": "Aggregated-diversion-ratio boundary, own-shr. wtd. distance",
|
|
60
60
|
"sheet_name": "OSWAG, distance",
|
|
61
61
|
"func_str": R"\surd (s_1 d_{12}^2 / s_M + s_2 d_{21}^2 / s_M)",
|
|
62
|
-
"func":
|
|
62
|
+
"func": gsl.shrratio_boundary_wtd_avg,
|
|
63
63
|
"func_kwargs": {
|
|
64
64
|
"wgtng_policy": "own-share",
|
|
65
65
|
"recapture_spec": RECAPTURE_SPEC,
|
|
@@ -70,40 +70,44 @@ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
|
|
|
70
70
|
"title_str": "Aggregated-diversion-ratio boundary, minimum",
|
|
71
71
|
"sheet_name": "OSWAG, minimum",
|
|
72
72
|
"func_str": R"\min (d_{12}, d_{21})",
|
|
73
|
-
"func":
|
|
73
|
+
"func": gsl.shrratio_boundary_min,
|
|
74
74
|
"func_kwargs": {"recapture_spec": RECAPTURE_SPEC},
|
|
75
75
|
},
|
|
76
76
|
"SAG Combined Share": {
|
|
77
77
|
"title_str": "Combined Share boundary",
|
|
78
78
|
"sheet_name": "SAG, combined-share",
|
|
79
79
|
"func_str": R"s_M",
|
|
80
|
-
"func":
|
|
80
|
+
"func": gsl.combined_share_boundary,
|
|
81
81
|
},
|
|
82
82
|
"SAG Div Ratio Distance": {
|
|
83
83
|
"title_str": "Aggregated-diversion-ratio boundary, distance",
|
|
84
84
|
"sheet_name": "SAG, distance",
|
|
85
85
|
"func_str": R"\surd (d_{12}^2 / 2 + d_{21}^2 / 2)",
|
|
86
|
-
"func":
|
|
87
|
-
"func_kwargs": {
|
|
86
|
+
"func": gsl.shrratio_boundary_wtd_avg,
|
|
87
|
+
"func_kwargs": {
|
|
88
|
+
"wgtng_policy": None,
|
|
89
|
+
"recapture_spec": RECAPTURE_SPEC,
|
|
90
|
+
"avg_method": "distance",
|
|
91
|
+
},
|
|
88
92
|
},
|
|
89
93
|
"SAG Average Div Ratio": {
|
|
90
94
|
"title_str": "Aggregated-diversion-ratio boundary, simple average",
|
|
91
95
|
"sheet_name": "SAG, average",
|
|
92
96
|
"func_str": R"(d_{12} + d_{21}) / 2",
|
|
93
|
-
"func":
|
|
97
|
+
"func": gsl.shrratio_boundary_xact_avg,
|
|
94
98
|
"func_kwargs": {"recapture_spec": RECAPTURE_SPEC},
|
|
95
99
|
},
|
|
96
100
|
"CPSWAG Premerger HHI-contribution": {
|
|
97
101
|
"title_str": "Premerger HHI-contribution boundary",
|
|
98
102
|
"sheet_name": "CPSWAG, HHI-contrib-pre",
|
|
99
103
|
"func_str": R"HHI_M^{pre}",
|
|
100
|
-
"func":
|
|
104
|
+
"func": gsl.hhi_pre_contrib_boundary,
|
|
101
105
|
},
|
|
102
106
|
"CPSWAG Cross-product-shr-wtd Div Ratio Index": {
|
|
103
107
|
"title_str": "Aggregated-diversion-ratio boundary, cross-product-share wtd. avg.",
|
|
104
108
|
"sheet_name": "CPSWAG, wtd avg",
|
|
105
109
|
"func_str": R"(s_2 d_{12} / s_M + s_1 d_{21} / s_M)",
|
|
106
|
-
"func":
|
|
110
|
+
"func": gsl.shrratio_boundary_wtd_avg,
|
|
107
111
|
"func_kwargs": {
|
|
108
112
|
"wgtng_policy": "cross-product-share",
|
|
109
113
|
"recapture_spec": RECAPTURE_SPEC,
|
|
@@ -113,7 +117,7 @@ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
|
|
|
113
117
|
"title_str": "Aggregated-diversion-ratio boundary, cross-prod-shr. wtd. distance",
|
|
114
118
|
"sheet_name": "CPSWAG, distance",
|
|
115
119
|
"func_str": R"\surd (s_2 d_{12}^2 / s_M + s_1 d_{21}^2 / s_M)",
|
|
116
|
-
"func":
|
|
120
|
+
"func": gsl.shrratio_boundary_wtd_avg,
|
|
117
121
|
"func_kwargs": {
|
|
118
122
|
"wgtng_policy": "cross-product-share",
|
|
119
123
|
"recapture_spec": RECAPTURE_SPEC,
|
|
@@ -124,7 +128,7 @@ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
|
|
|
124
128
|
"title_str": "Aggregated-diversion-ratio boundary, maximum",
|
|
125
129
|
"sheet_name": "CPSWAG, maximum",
|
|
126
130
|
"func_str": R"\max (d_{12}, d_{21})",
|
|
127
|
-
"func":
|
|
131
|
+
"func": gsl.shrratio_boundary_max,
|
|
128
132
|
},
|
|
129
133
|
}
|
|
130
134
|
|
|
@@ -138,7 +142,7 @@ def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
|
|
|
138
142
|
are drawn
|
|
139
143
|
|
|
140
144
|
"""
|
|
141
|
-
gso =
|
|
145
|
+
gso = gsl.GuidelinesStandards(_gpubyr)
|
|
142
146
|
_dhhi_val, _r_val, _g_val = (
|
|
143
147
|
getattr(gso.presumption, _f) for _f in ("delta", "rec", "guppi")
|
|
144
148
|
)
|
|
@@ -196,7 +200,7 @@ def _dhhi_stats(
|
|
|
196
200
|
|
|
197
201
|
_delta_val = _s_mid / (1 - _s_mid)
|
|
198
202
|
if _dhhi_val * 1e4 in (50, 100, 200):
|
|
199
|
-
_delta_val =
|
|
203
|
+
_delta_val = gsl.round_cust(_r_val * _delta_val) / _r_val
|
|
200
204
|
_divr_val = _r_val * _delta_val
|
|
201
205
|
|
|
202
206
|
print(
|
|
@@ -221,7 +225,7 @@ def _dhhi_stats(
|
|
|
221
225
|
def _bdry_stats_col(
|
|
222
226
|
_bdry_spec: str, _dhhi_val: float, _delta_val: float, _r_val: float, /
|
|
223
227
|
) -> tuple[str, str]:
|
|
224
|
-
_dhhi_prob = 2 *
|
|
228
|
+
_dhhi_prob = 2 * gsl.dh_area(_dhhi_val)
|
|
225
229
|
_cs_prob = 2 * _dhhi_val
|
|
226
230
|
_hhi_m_pre_prob = pi * _dhhi_val / 2
|
|
227
231
|
|
|
@@ -258,7 +262,7 @@ def plot_and_save_boundary_coords(
|
|
|
258
262
|
/,
|
|
259
263
|
layout: Literal["collected", "distributed"] = "collected",
|
|
260
264
|
) -> None:
|
|
261
|
-
gso =
|
|
265
|
+
gso = gsl.GuidelinesStandards(_gpubyr)
|
|
262
266
|
|
|
263
267
|
_hmg_standards_strings_dict = {
|
|
264
268
|
"distributed": ("presumption", "inferred presumption", "safeharbor"),
|
|
@@ -272,7 +276,7 @@ def plot_and_save_boundary_coords(
|
|
|
272
276
|
)
|
|
273
277
|
|
|
274
278
|
# Initialize plot area
|
|
275
|
-
_plt, _my_fig1, _ax1, _set_axis_def =
|
|
279
|
+
_plt, _my_fig1, _ax1, _set_axis_def = gsl.boundary_plot()
|
|
276
280
|
|
|
277
281
|
_divr_agg_methods = ("OSWAG", "SAG", "CPSWAG")
|
|
278
282
|
|
|
@@ -323,7 +327,7 @@ def plot_and_save_boundary_coords(
|
|
|
323
327
|
|
|
324
328
|
_fig_leg = _ax1.legend(
|
|
325
329
|
loc="upper right",
|
|
326
|
-
bbox_to_anchor=(0.995, 0.
|
|
330
|
+
bbox_to_anchor=(0.995, 0.999),
|
|
327
331
|
shadow=True,
|
|
328
332
|
fancybox=False,
|
|
329
333
|
frameon=False,
|
|
@@ -332,9 +336,6 @@ def plot_and_save_boundary_coords(
|
|
|
332
336
|
_fig_leg.set_in_layout(False)
|
|
333
337
|
|
|
334
338
|
for _bndry_name in _bndry_data_dict:
|
|
335
|
-
# if _bndry_name == "ΔHHI": # and _divr_agg_method != "OSWAG" and
|
|
336
|
-
# continue
|
|
337
|
-
|
|
338
339
|
boundary_data_to_worksheet(
|
|
339
340
|
_bndry_name,
|
|
340
341
|
_dhhi_val_str,
|
|
@@ -347,15 +348,14 @@ def plot_and_save_boundary_coords(
|
|
|
347
348
|
_fig_savepath = DATA_DIR / rf"{PROG_PATH.stem}_{_gpubyr}.pdf"
|
|
348
349
|
_my_fig1.savefig(_fig_savepath)
|
|
349
350
|
print()
|
|
350
|
-
del _divr_agg_method
|
|
351
351
|
|
|
352
352
|
|
|
353
353
|
def gen_plot_boundary(
|
|
354
354
|
_bndry_data_dict: Mapping[str, Sequence[tuple[float]]],
|
|
355
|
-
_gso:
|
|
355
|
+
_gso: gsl.GuidelinesStandards,
|
|
356
356
|
_gs_str: str,
|
|
357
357
|
_bdry_spec: tuple[str, Mapping[str, Any]],
|
|
358
|
-
_ax1:
|
|
358
|
+
_ax1: mpa.Axes,
|
|
359
359
|
/,
|
|
360
360
|
) -> tuple[tuple[float], tuple[float]]:
|
|
361
361
|
"""
|
|
@@ -366,7 +366,7 @@ def gen_plot_boundary(
|
|
|
366
366
|
_bndry_data_dict
|
|
367
367
|
mapping for storing boundary coordinates for each plotted boundary
|
|
368
368
|
_gso
|
|
369
|
-
|
|
369
|
+
gsl.GuidelinesStandards instance of tuples listing
|
|
370
370
|
concentration standard, default recapture-rate, GUPPI bound,
|
|
371
371
|
and diversion ratio bound for "safeharbor", "weak presumption",
|
|
372
372
|
and "presumption", where "weak presumption" represents an alternative
|
|
@@ -378,7 +378,7 @@ def gen_plot_boundary(
|
|
|
378
378
|
a mapping detailing the boundary function specification including
|
|
379
379
|
boundary function name and keyword parameters
|
|
380
380
|
_ax1
|
|
381
|
-
matplotlib
|
|
381
|
+
matplotlib Axes object for plots
|
|
382
382
|
|
|
383
383
|
Returns
|
|
384
384
|
-------
|
|
@@ -483,7 +483,7 @@ def gen_plot_boundary(
|
|
|
483
483
|
|
|
484
484
|
|
|
485
485
|
def _plot_annotator(
|
|
486
|
-
_ax:
|
|
486
|
+
_ax: mpa.Axes,
|
|
487
487
|
_a_str: str,
|
|
488
488
|
_data_pt: tuple[float, float],
|
|
489
489
|
_note_offset: tuple[float, float],
|
|
@@ -583,7 +583,7 @@ def boundary_data_to_worksheet(
|
|
|
583
583
|
_xl_sheet,
|
|
584
584
|
_bndry_points,
|
|
585
585
|
_results_top_row,
|
|
586
|
-
cell_format=xlh.CFmt.PCT_NUM,
|
|
586
|
+
cell_format=xlh.CFmt.PCT_NUM, # type: ignore
|
|
587
587
|
)
|
|
588
588
|
|
|
589
589
|
# Draw a bottom border
|