mergeron 2024.738949.6__py3-none-any.whl → 2024.738953.1__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 +1 -1
- mergeron/core/__init__.py +0 -1
- mergeron/core/ftc_invdata.msgpack +0 -0
- mergeron/core/ftc_merger_investigations_data.py +6 -0
- mergeron/core/guidelines_boundaries.py +1 -1
- mergeron/gen/investigations_stats.py +5 -6
- {mergeron-2024.738949.6.dist-info → mergeron-2024.738953.1.dist-info}/METADATA +1 -2
- {mergeron-2024.738949.6.dist-info → mergeron-2024.738953.1.dist-info}/RECORD +9 -22
- mergeron/examples/__init__.py +0 -5
- mergeron/examples/concentration_as_diversion.py +0 -625
- mergeron/examples/enforcement_boundaries_for_mergers_with_asymmetric_shares.py +0 -493
- mergeron/examples/enforcement_boundaries_for_symmetric_firm_mergers.py +0 -206
- mergeron/examples/example_parameterizations.py +0 -143
- mergeron/examples/guidelines_enforcement_patterns.py +0 -74
- mergeron/examples/investigations_stats_obs_tables.py +0 -481
- mergeron/examples/investigations_stats_sim_tables.py +0 -425
- mergeron/examples/plotSafeHarbs_symbolically.py +0 -53
- mergeron/examples/sound_guppi_safeharbor.py +0 -181
- mergeron/examples/summarize_ftc_investigations_data.py +0 -44
- mergeron/examples/testIntrinsicClearanceRates.py +0 -135
- mergeron/examples/visualize_empirical_margin_distribution.py +0 -100
- mergeron/examples/visualize_guidelines_tests.py +0 -298
- {mergeron-2024.738949.6.dist-info → mergeron-2024.738953.1.dist-info}/WHEEL +0 -0
|
@@ -1,625 +0,0 @@
|
|
|
1
|
-
R"""
|
|
2
|
-
|
|
3
|
-
Demonstrates the correspondence between concentration standards and
|
|
4
|
-
diversion ratio standards, graphically
|
|
5
|
-
|
|
6
|
-
Here, *correspondence* is defined as the close approximation of
|
|
7
|
-
boundaries for sets of mergers meeting a guidelines concentration
|
|
8
|
-
standard to boundaries for sets of mergers meeting a
|
|
9
|
-
matching diversion ratio. Separate demonstrations based on
|
|
10
|
-
1992 Guidelines concentration standards and 2010 Guidelines concentration
|
|
11
|
-
standards are generated as,
|
|
12
|
-
1.) Plots of the boundaries write to separate PDF files
|
|
13
|
-
2.) Tables of boundary coordinates written to separate Excel files
|
|
14
|
-
|
|
15
|
-
Output is written in the `mergeron` sub-folder within a user's home directory,
|
|
16
|
-
i.e., `%USERPROFILE%\mergeron` on Windows, or `~/mergeron/` on Unix-like
|
|
17
|
-
systems.
|
|
18
|
-
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
from __future__ import annotations
|
|
22
|
-
|
|
23
|
-
from collections.abc import Mapping, Sequence
|
|
24
|
-
from datetime import datetime
|
|
25
|
-
from math import sqrt
|
|
26
|
-
from pathlib import Path
|
|
27
|
-
from typing import Any, Literal
|
|
28
|
-
|
|
29
|
-
import matplotlib.axes as mpa
|
|
30
|
-
from jinja2 import FileSystemLoader
|
|
31
|
-
from joblib import Parallel, cpu_count, delayed # type: ignore
|
|
32
|
-
from numpy import pi
|
|
33
|
-
from xlsxwriter import Workbook # type: ignore
|
|
34
|
-
|
|
35
|
-
import mergeron.core.excel_helper as xlh
|
|
36
|
-
import mergeron.core.guidelines_boundaries as gbl
|
|
37
|
-
import mergeron.ext.tol_colors as ptcolor
|
|
38
|
-
import mergeron.gen.investigations_stats as isl
|
|
39
|
-
from mergeron import DATA_DIR, RECConstants, UPPAggrSelector
|
|
40
|
-
from mergeron.core import UPPBoundarySpec
|
|
41
|
-
|
|
42
|
-
PROG_PATH = Path(__file__)
|
|
43
|
-
|
|
44
|
-
RECAPTURE_SPEC = RECConstants.INOUT
|
|
45
|
-
# Map boundary forms to titles and generating-function names, with
|
|
46
|
-
# additional parameters as relevant
|
|
47
|
-
BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
|
|
48
|
-
"ΔHHI": {
|
|
49
|
-
"title_str": "ΔHHI boundary",
|
|
50
|
-
"sheet_name": "ΔHHI",
|
|
51
|
-
"func_str": R"\Delta HHI",
|
|
52
|
-
"func": gbl.delta_hhi_boundary,
|
|
53
|
-
},
|
|
54
|
-
"OSWAG Own-shr-wtd Div Ratio Index": {
|
|
55
|
-
"title_str": "Aggregated-diversion-ratio boundary, own-share wtd. avg.",
|
|
56
|
-
"sheet_name": "OSWAG, wtd avg",
|
|
57
|
-
"func_str": R"(s_1 d_{12} + s_2 d_{21}) / s_M",
|
|
58
|
-
"agg_method": UPPAggrSelector.OSA,
|
|
59
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
60
|
-
},
|
|
61
|
-
"OSWAG Own-shr-wtd Div Ratio Distance": {
|
|
62
|
-
"title_str": "Aggregated-diversion-ratio boundary, own-shr. wtd. distance",
|
|
63
|
-
"sheet_name": "OSWAG, distance",
|
|
64
|
-
"func_str": R"\surd (s_1 d_{12}^2 / s_M + s_2 d_{21}^2 / s_M)",
|
|
65
|
-
"agg_method": UPPAggrSelector.OSD,
|
|
66
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
67
|
-
},
|
|
68
|
-
"OSWAG Min Div Ratio": {
|
|
69
|
-
"title_str": "Aggregated-diversion-ratio boundary, minimum",
|
|
70
|
-
"sheet_name": "OSWAG, minimum",
|
|
71
|
-
"func_str": R"\min (d_{12}, d_{21})",
|
|
72
|
-
"agg_method": UPPAggrSelector.MIN,
|
|
73
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
74
|
-
},
|
|
75
|
-
"SAG Combined Share": {
|
|
76
|
-
"title_str": "Combined Share boundary",
|
|
77
|
-
"sheet_name": "SAG, combined-share",
|
|
78
|
-
"func_str": R"s_M",
|
|
79
|
-
"func": gbl.combined_share_boundary,
|
|
80
|
-
},
|
|
81
|
-
"SAG Average Div Ratio": {
|
|
82
|
-
"title_str": "Aggregated-diversion-ratio boundary, simple average",
|
|
83
|
-
"sheet_name": "SAG, average",
|
|
84
|
-
"func_str": R"(d_{12} + d_{21}) / 2",
|
|
85
|
-
"agg_method": UPPAggrSelector.AVG,
|
|
86
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
87
|
-
},
|
|
88
|
-
"SAG Div Ratio Distance": {
|
|
89
|
-
"title_str": "Aggregated-diversion-ratio boundary, distance",
|
|
90
|
-
"sheet_name": "SAG, distance",
|
|
91
|
-
"func_str": R"\surd (d_{12}^2 / 2 + d_{21}^2 / 2)",
|
|
92
|
-
"agg_method": UPPAggrSelector.DIS,
|
|
93
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
94
|
-
},
|
|
95
|
-
"CPSWAG Premerger HHI-contribution": {
|
|
96
|
-
"title_str": "Premerger HHI-contribution boundary",
|
|
97
|
-
"sheet_name": "CPSWAG, HHI-contrib-pre",
|
|
98
|
-
"func_str": R"HHI_M^{pre}",
|
|
99
|
-
"func": gbl.hhi_pre_contrib_boundary,
|
|
100
|
-
},
|
|
101
|
-
"CPSWAG Cross-product-shr-wtd Div Ratio Index": {
|
|
102
|
-
"title_str": "Aggregated-diversion-ratio boundary, cross-product-share wtd. avg.",
|
|
103
|
-
"sheet_name": "CPSWAG, wtd avg",
|
|
104
|
-
"func_str": R"(s_2 d_{12} / s_M + s_1 d_{21} / s_M)",
|
|
105
|
-
"agg_method": UPPAggrSelector.CPA,
|
|
106
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
107
|
-
},
|
|
108
|
-
"CPSWAG Cross-product-shr-wtd Div Ratio Distance": {
|
|
109
|
-
"title_str": "Aggregated-diversion-ratio boundary, cross-prod-shr. wtd. distance",
|
|
110
|
-
"sheet_name": "CPSWAG, distance",
|
|
111
|
-
"func_str": R"\surd (s_2 d_{12}^2 / s_M + s_1 d_{21}^2 / s_M)",
|
|
112
|
-
"agg_method": UPPAggrSelector.CPD,
|
|
113
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
114
|
-
},
|
|
115
|
-
"CPSWAG Max Div Ratio": {
|
|
116
|
-
"title_str": "Aggregated-diversion-ratio boundary, maximum",
|
|
117
|
-
"sheet_name": "CPSWAG, maximum",
|
|
118
|
-
"func_str": R"\max (d_{12}, d_{21})",
|
|
119
|
-
"agg_method": UPPAggrSelector.MAX,
|
|
120
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
121
|
-
},
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def tabulate_boundary_stats(_gpubyr: gbl.HMGPubYear, /) -> None:
|
|
126
|
-
"""
|
|
127
|
-
Parameters
|
|
128
|
-
----------
|
|
129
|
-
_gpubyr
|
|
130
|
-
Guidelines version (year of publication) from which concentration standards
|
|
131
|
-
are drawn
|
|
132
|
-
|
|
133
|
-
"""
|
|
134
|
-
_invres_rate_table_content = isl.StatsContainer()
|
|
135
|
-
|
|
136
|
-
gso = gbl.GuidelinesThresholds(_gpubyr)
|
|
137
|
-
_dhhi_val, _r_val, _g_val = (
|
|
138
|
-
getattr(gso.presumption, _f) for _f in ("delta", "rec", "guppi")
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
_dhhi_seq = (
|
|
142
|
-
(0.005, 0.01, 0.02, gso.imputed_presumption.delta, 0.08)
|
|
143
|
-
if _gpubyr == 2010
|
|
144
|
-
else (0.005, 0.01, 0.02, gso.imputed_presumption.delta, 0.08)
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
_bdry_approx_data_dict = {
|
|
148
|
-
"Criterion": {
|
|
149
|
-
_k: R"\({} < {}\)".format(
|
|
150
|
-
BDRY_SPECS_DICT[_k]["func_str"],
|
|
151
|
-
R"\safeharb{d}"
|
|
152
|
-
if "Div Ratio" in _k
|
|
153
|
-
else (
|
|
154
|
-
R"\surd (2 \safeharb{H})"
|
|
155
|
-
if _k.endswith("Combined Share")
|
|
156
|
-
else R"\safeharb{H}"
|
|
157
|
-
),
|
|
158
|
-
)
|
|
159
|
-
for _k in BDRY_SPECS_DICT
|
|
160
|
-
# if not _k.endswith("Distance")
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
_bdry_approx_data_dict |= {
|
|
164
|
-
R"{ \safeharb{H} \\ \safeharb{d} }": {
|
|
165
|
-
_k: R"{}" for _k in _bdry_approx_data_dict["Criterion"]
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
_bdry_data = Parallel(n_jobs=-1)(
|
|
170
|
-
delayed(_dhhi_stats)(_dhhi_val, _r_val) for _dhhi_val in _dhhi_seq
|
|
171
|
-
)
|
|
172
|
-
_bdry_approx_data_dict |= dict(_bdry_data)
|
|
173
|
-
|
|
174
|
-
_data_str = ""
|
|
175
|
-
_data_str = "{} \\\\ \n".format(
|
|
176
|
-
" & ".join(
|
|
177
|
-
_k.replace("Criterion", R"{\text{} \\ Criterion}") # \phantom{Criterion}
|
|
178
|
-
for _k in _bdry_approx_data_dict
|
|
179
|
-
)
|
|
180
|
-
)
|
|
181
|
-
for _sk in _bdry_approx_data_dict["Criterion"]:
|
|
182
|
-
_data_str += "{} \\\\ \n".format(
|
|
183
|
-
" & ".join(_bdry_approx_data_dict[_k][_sk] for _k in _bdry_approx_data_dict)
|
|
184
|
-
)
|
|
185
|
-
print(_data_str)
|
|
186
|
-
|
|
187
|
-
_invres_rate_table_content.data_str = _data_str
|
|
188
|
-
|
|
189
|
-
_j2_env = isl.latex_jinja_env
|
|
190
|
-
_j2_env.loader = FileSystemLoader(str(PROG_PATH.parent / "templates"))
|
|
191
|
-
_j2_templ = _j2_env.get_template(
|
|
192
|
-
"concentration_as_diversion_intrinsic_enforcement_rates.tex.jinja2"
|
|
193
|
-
)
|
|
194
|
-
PROG_PATH.parents[1].joinpath(
|
|
195
|
-
f"{PROG_PATH.stem}_intrinsic_enforcement_rates_{_gpubyr}.tex"
|
|
196
|
-
).write_text(_j2_templ.render(tmpl_data=_invres_rate_table_content))
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def _dhhi_stats(_dhhi_val: float, _r_val: float) -> tuple[str, dict[str, str]]:
|
|
200
|
-
_dhhi_val = round(_dhhi_val, 5)
|
|
201
|
-
|
|
202
|
-
_divr_val = gbl.gbd_from_dsf(_dhhi_val, r_bar=_r_val)
|
|
203
|
-
_delta_val = gbl.critical_shrratio(_divr_val, r_bar=_r_val)
|
|
204
|
-
# _s_mid = sqrt(_dhhi_val / 2)
|
|
205
|
-
|
|
206
|
-
# _delta_val = _s_mid / (1 - _s_mid)
|
|
207
|
-
# if _dhhi_val * 1e4 in (50, 100, 200):
|
|
208
|
-
# _delta_val = gbl.critical_shrratio()(_r_val * _delta_val) / _r_val
|
|
209
|
-
# _divr_val = _r_val * _delta_val
|
|
210
|
-
|
|
211
|
-
print(
|
|
212
|
-
"Processing data for ΔHHI = {0:.{1}f} points;".format(
|
|
213
|
-
_dhhi_val * 1e4, 1 * (_dhhi_val * 1e4 % 1 > 1e-8)
|
|
214
|
-
),
|
|
215
|
-
f"diversion ratio = {_divr_val:.{1 * (_divr_val * 1e2 % 1 > 1e-8)}%};",
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
_bdry_stats = Parallel(n_jobs=cpu_count() // 2)(
|
|
219
|
-
delayed(_bdry_stats_col)(_bdry_spec, _dhhi_val, _delta_val, _r_val)
|
|
220
|
-
for _bdry_spec in BDRY_SPECS_DICT
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
_bounds_string = R"{{ {} \\ {} }}".format(
|
|
224
|
-
Rf"{_dhhi_val * 1e4:.{1 * (_dhhi_val * 1e4 % 1 > 1e-8)}f} points",
|
|
225
|
-
Rf"{_divr_val * 1e2:.{2 * (_divr_val * 1e2 % 1 > 1e-8)}f}\%",
|
|
226
|
-
)
|
|
227
|
-
return _bounds_string, dict(_bdry_stats)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
def _bdry_stats_col(
|
|
231
|
-
_bdry_spec: str, _dhhi_val: float, _delta_val: float, _r_val: float, /
|
|
232
|
-
) -> tuple[str, str]:
|
|
233
|
-
_dhhi_prob = 2 * gbl.dh_area(_dhhi_val)
|
|
234
|
-
_cs_prob = 2 * _dhhi_val
|
|
235
|
-
_hhi_m_pre_prob = pi * _dhhi_val / 2
|
|
236
|
-
|
|
237
|
-
match _bdry_spec:
|
|
238
|
-
case "ΔHHI":
|
|
239
|
-
return _bdry_spec, f"{_dhhi_prob:6.5f}"
|
|
240
|
-
case "SAG Combined Share":
|
|
241
|
-
return _bdry_spec, f"{_cs_prob:6.5f}"
|
|
242
|
-
case "CPSWAG Premerger HHI-contribution":
|
|
243
|
-
return _bdry_spec, f"{_hhi_m_pre_prob:6.5f}"
|
|
244
|
-
case _ if "Div Ratio" in _bdry_spec:
|
|
245
|
-
_within_bdry_area = gbl.shrratio_boundary(
|
|
246
|
-
UPPBoundarySpec(
|
|
247
|
-
_delta_val,
|
|
248
|
-
_r_val,
|
|
249
|
-
agg_method=BDRY_SPECS_DICT[_bdry_spec]["agg_method"],
|
|
250
|
-
recapture_spec=BDRY_SPECS_DICT[_bdry_spec]["recapture_spec"],
|
|
251
|
-
)
|
|
252
|
-
).area
|
|
253
|
-
_within_bdry_prob = 2 * _within_bdry_area
|
|
254
|
-
if _bdry_spec.startswith("CPSWAG"):
|
|
255
|
-
_within_conc_bdry_prob = _hhi_m_pre_prob
|
|
256
|
-
elif _bdry_spec.startswith("SAG"):
|
|
257
|
-
_within_conc_bdry_prob = _cs_prob
|
|
258
|
-
else:
|
|
259
|
-
_within_conc_bdry_prob = _dhhi_prob
|
|
260
|
-
|
|
261
|
-
return _bdry_spec, R"{{ {:6.5f} \\ {:.2f}\% }}".format( # noqa: UP032
|
|
262
|
-
_within_bdry_prob,
|
|
263
|
-
100 * (1 - (_within_conc_bdry_prob / _within_bdry_prob)),
|
|
264
|
-
)
|
|
265
|
-
case _:
|
|
266
|
-
raise ValueError(f'Unexpected specification, "{_bdry_spec}"?')
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
def plot_and_save_boundary_coords(
|
|
270
|
-
_gpubyr: gbl.HMGPubYear,
|
|
271
|
-
_xl_book: Workbook,
|
|
272
|
-
/,
|
|
273
|
-
layout: Literal["collected", "distributed"] = "collected",
|
|
274
|
-
) -> None:
|
|
275
|
-
gso = gbl.GuidelinesThresholds(_gpubyr)
|
|
276
|
-
|
|
277
|
-
_hmg_standards_strings_dict = {
|
|
278
|
-
"distributed": ("presumption", "inferred presumption", "safeharbor"),
|
|
279
|
-
"collected": ("safeharbor", "imputed_presumption", "presumption"),
|
|
280
|
-
}
|
|
281
|
-
_hmg_standards_strings = _hmg_standards_strings_dict.get(layout, ())
|
|
282
|
-
if not _hmg_standards_strings:
|
|
283
|
-
raise ValueError(
|
|
284
|
-
f"Layout parameter value, {layout!r} is invalid. "
|
|
285
|
-
f'Must be one of, ("collected", "distributed"). '
|
|
286
|
-
)
|
|
287
|
-
|
|
288
|
-
# Initialize plot area
|
|
289
|
-
_plt, _my_fig1, _ax1, _set_axis_def = gbl.boundary_plot()
|
|
290
|
-
|
|
291
|
-
_divr_agg_methods = ("OSWAG", "SAG", "CPSWAG")
|
|
292
|
-
|
|
293
|
-
for _divr_agg_method, _hmg_standards_str in zip(
|
|
294
|
-
_divr_agg_methods, _hmg_standards_strings, strict=True
|
|
295
|
-
):
|
|
296
|
-
_r_bar, _g_bar = (getattr(gso.presumption, _f) for _f in ("rec", "guppi"))
|
|
297
|
-
_dhhi_val = getattr(gso, _hmg_standards_str).delta
|
|
298
|
-
_divr_val = (
|
|
299
|
-
_g_bar
|
|
300
|
-
if _hmg_standards_str == "safeharbor"
|
|
301
|
-
else _r_bar * sqrt(_dhhi_val / 2) / (1 - sqrt(_dhhi_val / 2))
|
|
302
|
-
)
|
|
303
|
-
|
|
304
|
-
_dhhi_val_str = "{0:.{1}f} points".format(
|
|
305
|
-
_dhhi_val * 1e4, 1 * (_dhhi_val * 1e4 % 1 > 1e-8)
|
|
306
|
-
)
|
|
307
|
-
_divr_val_str = f"{_divr_val:.{1 * (_divr_val * 1e2 % 1 > 1e-8)}%}"
|
|
308
|
-
|
|
309
|
-
print(
|
|
310
|
-
f"Processing data for ΔHHI = {_dhhi_val_str},",
|
|
311
|
-
f"diversion ratio = {_divr_val_str}:",
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
_bndry_data_dict: dict[
|
|
315
|
-
str, Sequence[tuple[float]]
|
|
316
|
-
] = {} #: Container for boundary coordinates data, by boundary
|
|
317
|
-
|
|
318
|
-
for _bdry_spec_key in BDRY_SPECS_DICT:
|
|
319
|
-
_bdry_spec = (_bdry_spec_key, BDRY_SPECS_DICT[_bdry_spec_key])
|
|
320
|
-
|
|
321
|
-
if _bdry_spec_key == "ΔHHI":
|
|
322
|
-
if _hmg_standards_str != _hmg_standards_strings_dict[layout][0]:
|
|
323
|
-
continue
|
|
324
|
-
|
|
325
|
-
_dh_s1, _dh_s2 = gen_plot_boundary(
|
|
326
|
-
_bndry_data_dict, gso, _hmg_standards_str, _bdry_spec, _ax1
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
del _dh_s1, _dh_s2
|
|
330
|
-
|
|
331
|
-
elif _bdry_spec_key.startswith(
|
|
332
|
-
_divr_agg_method
|
|
333
|
-
): # and not _bdry_spec_key.endswith("Distance"):
|
|
334
|
-
gen_plot_boundary(
|
|
335
|
-
_bndry_data_dict, gso, _hmg_standards_str, _bdry_spec, _ax1
|
|
336
|
-
)
|
|
337
|
-
|
|
338
|
-
_fig_leg = _ax1.legend(
|
|
339
|
-
loc="upper right",
|
|
340
|
-
bbox_to_anchor=(0.995, 0.999),
|
|
341
|
-
shadow=True,
|
|
342
|
-
fancybox=False,
|
|
343
|
-
frameon=False,
|
|
344
|
-
fontsize=8,
|
|
345
|
-
)
|
|
346
|
-
_fig_leg.set_in_layout(False)
|
|
347
|
-
|
|
348
|
-
for _bndry_name in _bndry_data_dict:
|
|
349
|
-
boundary_data_to_worksheet(
|
|
350
|
-
_bndry_name,
|
|
351
|
-
_dhhi_val_str,
|
|
352
|
-
_divr_val_str,
|
|
353
|
-
_r_bar,
|
|
354
|
-
_bndry_data_dict,
|
|
355
|
-
_xl_book,
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
_fig_savepath = DATA_DIR / rf"{PROG_PATH.stem}_{_gpubyr}.pdf"
|
|
359
|
-
_my_fig1.savefig(_fig_savepath)
|
|
360
|
-
print()
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
def gen_plot_boundary(
|
|
364
|
-
_bndry_data_dict: Mapping[str, Sequence[tuple[float]]],
|
|
365
|
-
_gso: gbl.GuidelinesThresholds,
|
|
366
|
-
_gs_str: str,
|
|
367
|
-
_bdry_spec: tuple[str, Mapping[str, Any]],
|
|
368
|
-
_ax1: mpa.Axes,
|
|
369
|
-
/,
|
|
370
|
-
) -> tuple[tuple[float], tuple[float]]:
|
|
371
|
-
"""
|
|
372
|
-
Utility function to plot boundaries given a dict of relevant parms.
|
|
373
|
-
|
|
374
|
-
Parameters
|
|
375
|
-
----------
|
|
376
|
-
_bndry_data_dict
|
|
377
|
-
mapping for storing boundary coordinates for each plotted boundary
|
|
378
|
-
_gso
|
|
379
|
-
gbl.GuidelinesStandards instance of tuples listing
|
|
380
|
-
concentration standard, default recapture-rate, GUPPI bound,
|
|
381
|
-
and diversion ratio bound for "safeharbor", "weak presumption",
|
|
382
|
-
and "presumption", where "weak presumption" represents an alternative
|
|
383
|
-
interpretation of the enforcement margin for the Guidelines presumption
|
|
384
|
-
_gs_str
|
|
385
|
-
safeharbor, presumption, or overt_presumption
|
|
386
|
-
_bdry_spec
|
|
387
|
-
tuple of a string specifying boundary function to plot and
|
|
388
|
-
a mapping detailing the boundary function specification including
|
|
389
|
-
boundary function name and keyword parameters
|
|
390
|
-
_ax1
|
|
391
|
-
matplotlib Axes object for plots
|
|
392
|
-
|
|
393
|
-
Returns
|
|
394
|
-
-------
|
|
395
|
-
tuples of boundary coordinates - Firm 1 shares and Firm 2 shares along
|
|
396
|
-
boundary for Guidelines standard
|
|
397
|
-
"""
|
|
398
|
-
|
|
399
|
-
_bdry_spec_str, _bdry_spec_dict = _bdry_spec
|
|
400
|
-
print(_bdry_spec_dict["title_str"])
|
|
401
|
-
|
|
402
|
-
_pt_mdco: ptcolor.Mcset = ptcolor.tol_cset("medium-contrast") # type: ignore
|
|
403
|
-
_pt_vbco: ptcolor.Vcset = ptcolor.tol_cset("vibrant") # type: ignore
|
|
404
|
-
|
|
405
|
-
_plot_line_width = 1.0
|
|
406
|
-
_plot_line_alpha = 0.8
|
|
407
|
-
_plot_line_color = _pt_vbco.black
|
|
408
|
-
_plot_line_style = {"OSWAG": "-", "SAG": "-.", "CPSWAG": "--"}.get(
|
|
409
|
-
_bdry_spec_str.split(" ")[0], "-"
|
|
410
|
-
)
|
|
411
|
-
if _bdry_spec_str.startswith("ΔHHI"):
|
|
412
|
-
_plot_line_width = 0.5
|
|
413
|
-
_plot_line_alpha = 1.0
|
|
414
|
-
_zrdr = 5
|
|
415
|
-
|
|
416
|
-
if not _bdry_spec_str.startswith("ΔHHI"):
|
|
417
|
-
match _bdry_spec_str:
|
|
418
|
-
case _ if _bdry_spec_str.startswith(("SAG Combined", "CPSWAG Premerger")):
|
|
419
|
-
_zrdr = 2
|
|
420
|
-
case _ if "Distance" in _bdry_spec_str:
|
|
421
|
-
_plot_line_color = _pt_vbco.blue
|
|
422
|
-
_zrdr = 3
|
|
423
|
-
case _ if "shr-wtd" in _bdry_spec_str or "Mean" in _bdry_spec_str:
|
|
424
|
-
_plot_line_color = _pt_vbco.teal
|
|
425
|
-
_zrdr = 3
|
|
426
|
-
case _:
|
|
427
|
-
_plot_line_color = _pt_vbco.red
|
|
428
|
-
|
|
429
|
-
_g_val = _gso.safeharbor.guppi
|
|
430
|
-
|
|
431
|
-
_r_bar = _gso.presumption.rec
|
|
432
|
-
|
|
433
|
-
_dhhi_val = getattr(_gso, _gs_str).delta
|
|
434
|
-
_s_mid = sqrt(_dhhi_val / 2)
|
|
435
|
-
_delta_val = _g_val / _r_bar if _gs_str == "safeharbor" else _s_mid / (1 - _s_mid)
|
|
436
|
-
|
|
437
|
-
_bdry_func = _bdry_spec_dict.get("func", gbl.shrratio_boundary)
|
|
438
|
-
if "Div Ratio" in _bdry_spec_str:
|
|
439
|
-
_bdry_boundary = gbl.shrratio_boundary(
|
|
440
|
-
UPPBoundarySpec(
|
|
441
|
-
_delta_val,
|
|
442
|
-
_r_bar,
|
|
443
|
-
agg_method=_bdry_spec_dict["agg_method"],
|
|
444
|
-
recapture_spec=_bdry_spec_dict["recapture_spec"],
|
|
445
|
-
)
|
|
446
|
-
)
|
|
447
|
-
_plot_label_mag, _plot_label_uom = _r_bar * _delta_val * 1e2, "%"
|
|
448
|
-
elif _bdry_spec_str.endswith("Combined Share"):
|
|
449
|
-
_bdry_boundary = _bdry_func(2 * _s_mid)
|
|
450
|
-
_plot_label_mag, _plot_label_uom = 2 * _s_mid * 1e2, "%"
|
|
451
|
-
else:
|
|
452
|
-
_bdry_boundary = _bdry_func(_dhhi_val)
|
|
453
|
-
_plot_label_mag, _plot_label_uom = _dhhi_val * 1e4, " points"
|
|
454
|
-
|
|
455
|
-
_plot_label = R"${0}$ = {1:.{2}f}{3}".format(
|
|
456
|
-
_bdry_spec_dict["func_str"],
|
|
457
|
-
_plot_label_mag,
|
|
458
|
-
1 * (_plot_label_mag % 1 > 1e-8),
|
|
459
|
-
_plot_label_uom,
|
|
460
|
-
)
|
|
461
|
-
|
|
462
|
-
_bndry_data_dict |= {
|
|
463
|
-
_bdry_spec_str: (
|
|
464
|
-
_bdry_spec_dict["sheet_name"],
|
|
465
|
-
_bdry_boundary.coordinates,
|
|
466
|
-
_bdry_boundary.area,
|
|
467
|
-
)
|
|
468
|
-
} # type: ignore
|
|
469
|
-
_bdry_s1, _bdry_s2 = zip(*_bdry_boundary.coordinates, strict=True)
|
|
470
|
-
|
|
471
|
-
_ax1.plot(
|
|
472
|
-
_bdry_s1,
|
|
473
|
-
_bdry_s2,
|
|
474
|
-
label=_plot_label,
|
|
475
|
-
color=_plot_line_color,
|
|
476
|
-
linestyle=_plot_line_style,
|
|
477
|
-
linewidth=_plot_line_width,
|
|
478
|
-
alpha=_plot_line_alpha,
|
|
479
|
-
zorder=_zrdr,
|
|
480
|
-
)
|
|
481
|
-
|
|
482
|
-
print("\t", _bdry_spec_str, f"{_bdry_s2[0]:.1%}")
|
|
483
|
-
if _bdry_spec_str.startswith(("ΔHHI", "OSWAG Min")):
|
|
484
|
-
_plot_annotator(
|
|
485
|
-
_ax1,
|
|
486
|
-
f"({_bdry_s1[1]:.1%}, {_bdry_s2[1]:.1%})",
|
|
487
|
-
(_bdry_s1[1], _bdry_s2[1]),
|
|
488
|
-
(0.005, 0),
|
|
489
|
-
"left",
|
|
490
|
-
)
|
|
491
|
-
elif _bdry_spec_str.startswith("SAG") or _bdry_spec_str in (
|
|
492
|
-
"CPSWAG Premerger HHI-contribution",
|
|
493
|
-
"CPSWAG Max Div Ratio",
|
|
494
|
-
):
|
|
495
|
-
_plot_annotator(
|
|
496
|
-
_ax1, f"{_bdry_s2[0]:.1%}", (_bdry_s1[0], _bdry_s2[0]), (-0.005, 0), "right"
|
|
497
|
-
)
|
|
498
|
-
|
|
499
|
-
return _bdry_s1, _bdry_s2
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
def _plot_annotator(
|
|
503
|
-
_ax: mpa.Axes,
|
|
504
|
-
_a_str: str,
|
|
505
|
-
_data_pt: tuple[float, float],
|
|
506
|
-
_note_offset: tuple[float, float],
|
|
507
|
-
_h_align: str,
|
|
508
|
-
_v_align: str = "bottom",
|
|
509
|
-
_font_sz: int = 3,
|
|
510
|
-
_z_order: float = 5.0,
|
|
511
|
-
/,
|
|
512
|
-
) -> None:
|
|
513
|
-
_ax.annotate(
|
|
514
|
-
"" if _data_pt[1] * 10 % 1 < 1e-8 else _a_str,
|
|
515
|
-
xy=_data_pt,
|
|
516
|
-
xytext=(_data_pt[0] + _note_offset[0], _data_pt[1] + _note_offset[1]),
|
|
517
|
-
textcoords="data",
|
|
518
|
-
ha=_h_align,
|
|
519
|
-
va=_v_align,
|
|
520
|
-
fontsize=_font_sz,
|
|
521
|
-
zorder=_z_order,
|
|
522
|
-
)
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
def boundary_data_to_worksheet(
|
|
526
|
-
_bndry_name: str,
|
|
527
|
-
_dhhi_val_str: str,
|
|
528
|
-
_divr_val_str: str,
|
|
529
|
-
_r_bar: float,
|
|
530
|
-
_bndry_data_dict: Mapping[str, Sequence[tuple[Any]]],
|
|
531
|
-
_xl_book: Workbook,
|
|
532
|
-
/,
|
|
533
|
-
) -> None:
|
|
534
|
-
"""
|
|
535
|
-
Write boundary data to worksheet in specified Excel workbook
|
|
536
|
-
|
|
537
|
-
Parameters
|
|
538
|
-
----------
|
|
539
|
-
_bndry_name
|
|
540
|
-
Name of concentration or diversion boundary
|
|
541
|
-
_dhhi_val_str
|
|
542
|
-
∆HHI value as a formatted string
|
|
543
|
-
_divr_val_str
|
|
544
|
-
Diversion ratio value as a formatted string
|
|
545
|
-
_r_bar
|
|
546
|
-
Specified recapture rate
|
|
547
|
-
_bndry_data_dict
|
|
548
|
-
Container with boundary coordinates data for various concentration and
|
|
549
|
-
diversion boundaries
|
|
550
|
-
_xl_book
|
|
551
|
-
Specified Excel Workbook
|
|
552
|
-
|
|
553
|
-
"""
|
|
554
|
-
_sheet_name, _bndry_points, _bndry_area = _bndry_data_dict[_bndry_name]
|
|
555
|
-
|
|
556
|
-
_xl_sheet = _xl_book.add_worksheet(_sheet_name)
|
|
557
|
-
|
|
558
|
-
_xl_sheet.write("A1", "Sound GUPPI Safeharbor")
|
|
559
|
-
_xl_sheet.write("A2", "Merger Screens for Unilateral Effects")
|
|
560
|
-
_xl_sheet.write("A3", f"Share Coordinates Defining {_bndry_name}")
|
|
561
|
-
if "Div Ratio" in _bndry_name:
|
|
562
|
-
_xl_sheet.write(
|
|
563
|
-
"A4",
|
|
564
|
-
"Boundary parameters: {}; {}".format(
|
|
565
|
-
f"diversion ratio = {_divr_val_str}", f"recapture rate = {_r_bar:3.0%}"
|
|
566
|
-
),
|
|
567
|
-
)
|
|
568
|
-
_xl_sheet.write("A6", "Area Under Boundary (Simpson's Rule)")
|
|
569
|
-
else:
|
|
570
|
-
_xl_sheet.write("A4", f"Boundary parameters: ΔHHI = {_dhhi_val_str}")
|
|
571
|
-
_xl_sheet.write("A6", "Area Under Boundary (Closed Form)")
|
|
572
|
-
|
|
573
|
-
# Write and format the data
|
|
574
|
-
_left_footer = "{}, {} on {}.\n{}".format(
|
|
575
|
-
"Generated by Python module",
|
|
576
|
-
".".join(Path(__file__).parts[-3:]).rstrip(".py"),
|
|
577
|
-
datetime.now().strftime("%A, %d %B %Y"),
|
|
578
|
-
"© S. Murthy Kambhampaty, 2017-2023. License: CC-BY-NC-SA-4.0.",
|
|
579
|
-
)
|
|
580
|
-
_xl_sheet.set_footer(f"&L{_left_footer}")
|
|
581
|
-
|
|
582
|
-
xlh.scalar_to_sheet(_xl_book, _xl_sheet, "B7", _bndry_area, xlh.CFmt.AREA_NUM)
|
|
583
|
-
|
|
584
|
-
_results_header_row = 9
|
|
585
|
-
for _cell_addr_col in range(2):
|
|
586
|
-
xlh.scalar_to_sheet(
|
|
587
|
-
_xl_book,
|
|
588
|
-
_xl_sheet,
|
|
589
|
-
_results_header_row,
|
|
590
|
-
_cell_addr_col,
|
|
591
|
-
f"Firm {_cell_addr_col + 1}",
|
|
592
|
-
(xlh.CFmt.HDR_BORDER, xlh.CFmt.A_RIGHT),
|
|
593
|
-
)
|
|
594
|
-
# set column widths
|
|
595
|
-
_xl_sheet.set_column(0, 1, 15)
|
|
596
|
-
|
|
597
|
-
_results_top_row = 11
|
|
598
|
-
_last_written_row, _last_written_col = xlh.matrix_to_sheet(
|
|
599
|
-
_xl_book,
|
|
600
|
-
_xl_sheet,
|
|
601
|
-
_bndry_points,
|
|
602
|
-
_results_top_row,
|
|
603
|
-
cell_format=xlh.CFmt.PCT_NUM, # type: ignore
|
|
604
|
-
)
|
|
605
|
-
|
|
606
|
-
# Draw a bottom border
|
|
607
|
-
_cell_row = _last_written_row
|
|
608
|
-
for _cell_col in range(_last_written_col):
|
|
609
|
-
xlh.scalar_to_sheet(
|
|
610
|
-
_xl_book, _xl_sheet, _cell_row, _cell_col, "", xlh.CFmt.BOT_BORDER
|
|
611
|
-
)
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
if __name__ == "__main__":
|
|
615
|
-
gpubyrs: list[gbl.HMGPubYear] = [1992, 2010, 2023]
|
|
616
|
-
for gpubyr in gpubyrs[2:][:1]:
|
|
617
|
-
tabulate_boundary_stats(gpubyr)
|
|
618
|
-
|
|
619
|
-
# Initiliaze workbook for saving boundary coordinates
|
|
620
|
-
with Workbook(
|
|
621
|
-
DATA_DIR / rf"{PROG_PATH.stem}_{gpubyr}_BoundaryCoordinates.xlsx"
|
|
622
|
-
) as xl_book:
|
|
623
|
-
# tabulate_boundary_stats(gpubyr)
|
|
624
|
-
plot_and_save_boundary_coords(gpubyr, xl_book, layout="collected") # type: ignore
|
|
625
|
-
xl_book.worksheets()[0].activate()
|