mergeron 2024.738949.1__py3-none-any.whl → 2024.738949.6__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 +29 -0
- mergeron/core/__init__.py +65 -1
- mergeron/core/excel_helper.py +5 -12
- mergeron/core/guidelines_boundaries.py +194 -400
- mergeron/core/guidelines_boundaries_specialized_functions.py +341 -0
- mergeron/core/pseudorandom_numbers.py +1 -1
- mergeron/examples/concentration_as_diversion.py +97 -83
- mergeron/examples/enforcement_boundaries_for_mergers_with_asymmetric_shares.py +13 -7
- mergeron/examples/investigations_stats_obs_tables.py +13 -11
- mergeron/examples/investigations_stats_sim_tables.py +11 -12
- mergeron/examples/plotSafeHarbs_symbolically.py +7 -5
- mergeron/examples/sound_guppi_safeharbor.py +6 -7
- mergeron/examples/visualize_guidelines_tests.py +3 -5
- mergeron/gen/__init__.py +9 -33
- mergeron/gen/_data_generation_functions_nonpublic.py +5 -6
- mergeron/gen/data_generation.py +1 -2
- mergeron/gen/upp_tests.py +7 -7
- {mergeron-2024.738949.1.dist-info → mergeron-2024.738949.6.dist-info}/METADATA +1 -1
- {mergeron-2024.738949.1.dist-info → mergeron-2024.738949.6.dist-info}/RECORD +20 -19
- {mergeron-2024.738949.1.dist-info → mergeron-2024.738949.6.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Specialized routines for defining and analyzing boundaries for Guidelines standards.
|
|
3
|
+
|
|
4
|
+
These routines provide improved precision or demonstrate additional methods, but tend
|
|
5
|
+
to have poor performance
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from importlib.metadata import version
|
|
10
|
+
from typing import Literal
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
from mpmath import mp, mpf # type: ignore
|
|
14
|
+
from scipy.spatial.distance import minkowski as distance_function # type: ignore
|
|
15
|
+
from sympy import lambdify, simplify, solve, symbols
|
|
16
|
+
|
|
17
|
+
from .. import _PKG_NAME # noqa: TID252
|
|
18
|
+
from .guidelines_boundaries import (
|
|
19
|
+
GuidelinesBoundary,
|
|
20
|
+
GuidelinesBoundaryCallable,
|
|
21
|
+
_shrratio_boundary_intcpt,
|
|
22
|
+
lerp,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__version__ = version(_PKG_NAME)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
mp.prec = 80
|
|
29
|
+
mp.trap_complex = True
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def delta_hhi_boundary_qdtr(_dh_val: float = 0.01) -> GuidelinesBoundaryCallable:
|
|
33
|
+
"""
|
|
34
|
+
Generate the list of share combination on the ΔHHI boundary.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
_dh_val:
|
|
39
|
+
Merging-firms' ΔHHI bound.
|
|
40
|
+
prec
|
|
41
|
+
Number of decimal places for rounding reported shares.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
Callable to generate array of share-pairs, area under boundary.
|
|
46
|
+
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
_dh_val = mpf(f"{_dh_val}")
|
|
50
|
+
|
|
51
|
+
_s_1, _s_2 = symbols("s_1, s_2", positive=True)
|
|
52
|
+
|
|
53
|
+
_hhi_eqn = _s_2 - 0.01 / (2 * _s_1)
|
|
54
|
+
|
|
55
|
+
_hhi_bdry = solve(_hhi_eqn, _s_2)[0] # type: ignore
|
|
56
|
+
_s_nought = float(solve(_hhi_eqn.subs({_s_2: 1 - _s_1}), _s_1)[0]) # type: ignore
|
|
57
|
+
|
|
58
|
+
_hhi_bdry_area = 2 * (
|
|
59
|
+
_s_nought
|
|
60
|
+
+ mp.quad(lambdify(_s_1, _hhi_bdry, "mpmath"), (_s_nought, 1 - _s_nought))
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return GuidelinesBoundaryCallable(
|
|
64
|
+
lambdify(_s_1, _hhi_bdry, "numpy"), _hhi_bdry_area, _s_nought
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def shrratio_boundary_qdtr_wtd_avg(
|
|
69
|
+
_delta_star: float = 0.075,
|
|
70
|
+
_r_val: float = 0.80,
|
|
71
|
+
/,
|
|
72
|
+
*,
|
|
73
|
+
weighting: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
74
|
+
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
75
|
+
) -> GuidelinesBoundaryCallable:
|
|
76
|
+
"""
|
|
77
|
+
Share combinations for the share-weighted average GUPPI boundary with symmetric
|
|
78
|
+
merging-firm margins.
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
_delta_star
|
|
83
|
+
corollary to GUPPI bound (:math:`\\overline{g} / (m^* \\cdot \\overline{r})`)
|
|
84
|
+
_r_val
|
|
85
|
+
recapture ratio
|
|
86
|
+
weighting
|
|
87
|
+
Whether "own-share" or "cross-product-share" (or None for simple, unweighted average)
|
|
88
|
+
recapture_spec
|
|
89
|
+
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
90
|
+
value for both merging firms ("proportional").
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
Array of share-pairs, area under boundary.
|
|
95
|
+
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
_delta_star = mpf(f"{_delta_star}")
|
|
99
|
+
_s_mid = _delta_star / (1 + _delta_star)
|
|
100
|
+
_s_naught = 0
|
|
101
|
+
|
|
102
|
+
_s_1, _s_2 = symbols("s_1:3", positive=True)
|
|
103
|
+
|
|
104
|
+
match weighting:
|
|
105
|
+
case "own-share":
|
|
106
|
+
_bdry_eqn = (
|
|
107
|
+
_s_1 * _s_2 / (1 - _s_1)
|
|
108
|
+
+ _s_2
|
|
109
|
+
* _s_1
|
|
110
|
+
/ (
|
|
111
|
+
(1 - (_r_val * _s_2 + (1 - _r_val) * _s_1))
|
|
112
|
+
if recapture_spec == "inside-out"
|
|
113
|
+
else (1 - _s_2)
|
|
114
|
+
)
|
|
115
|
+
- (_s_1 + _s_2) * _delta_star
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
_bdry_func = solve(_bdry_eqn, _s_2)[0] # type: ignore
|
|
119
|
+
_s_naught = (
|
|
120
|
+
float(solve(simplify(_bdry_eqn.subs({_s_2: 1 - _s_1})), _s_1)[0]) # type: ignore
|
|
121
|
+
if recapture_spec == "inside-out"
|
|
122
|
+
else 0
|
|
123
|
+
)
|
|
124
|
+
_bdry_area = float(
|
|
125
|
+
2
|
|
126
|
+
* (
|
|
127
|
+
_s_naught
|
|
128
|
+
+ mp.quad(lambdify(_s_1, _bdry_func, "mpmath"), (_s_naught, _s_mid))
|
|
129
|
+
)
|
|
130
|
+
- (_s_mid**2 + _s_naught**2)
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
case "cross-product-share":
|
|
134
|
+
mp.trap_complex = False
|
|
135
|
+
_d_star = symbols("d", positive=True)
|
|
136
|
+
_bdry_eqn = (
|
|
137
|
+
_s_2 * _s_2 / (1 - _s_1)
|
|
138
|
+
+ _s_1
|
|
139
|
+
* _s_1
|
|
140
|
+
/ (
|
|
141
|
+
(1 - (_r_val * _s_2 + (1 - _r_val) * _s_1))
|
|
142
|
+
if recapture_spec == "inside-out"
|
|
143
|
+
else (1 - _s_2)
|
|
144
|
+
)
|
|
145
|
+
- (_s_1 + _s_2) * _d_star
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
_bdry_func = solve(_bdry_eqn, _s_2)[1] # type: ignore
|
|
149
|
+
_bdry_area = float(
|
|
150
|
+
2
|
|
151
|
+
* (
|
|
152
|
+
mp.quad(
|
|
153
|
+
lambdify(
|
|
154
|
+
_s_1, _bdry_func.subs({_d_star: _delta_star}), "mpmath"
|
|
155
|
+
),
|
|
156
|
+
(0, _s_mid),
|
|
157
|
+
)
|
|
158
|
+
).real
|
|
159
|
+
- _s_mid**2
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
case _:
|
|
163
|
+
_bdry_eqn = (
|
|
164
|
+
1 / 2 * _s_2 / (1 - _s_1)
|
|
165
|
+
+ 1
|
|
166
|
+
/ 2
|
|
167
|
+
* _s_1
|
|
168
|
+
/ (
|
|
169
|
+
(1 - (_r_val * _s_2 + (1 - _r_val) * _s_1))
|
|
170
|
+
if recapture_spec == "inside-out"
|
|
171
|
+
else (1 - _s_2)
|
|
172
|
+
)
|
|
173
|
+
- _delta_star
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
_bdry_func = solve(_bdry_eqn, _s_2)[0] # type: ignore
|
|
177
|
+
_bdry_area = float(
|
|
178
|
+
2 * (mp.quad(lambdify(_s_1, _bdry_func, "mpmath"), (0, _s_mid)))
|
|
179
|
+
- _s_mid**2
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return GuidelinesBoundaryCallable(
|
|
183
|
+
lambdify(_s_1, _bdry_func, "numpy"), _bdry_area, _s_naught
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def shrratio_boundary_distance(
|
|
188
|
+
_delta_star: float = 0.075,
|
|
189
|
+
_r_val: float = 0.80,
|
|
190
|
+
/,
|
|
191
|
+
*,
|
|
192
|
+
agg_method: Literal["arithmetic", "distance"] = "arithmetic",
|
|
193
|
+
weighting: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
194
|
+
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
195
|
+
prec: int = 5,
|
|
196
|
+
) -> GuidelinesBoundary:
|
|
197
|
+
"""
|
|
198
|
+
Share combinations for the GUPPI boundaries using various aggregators with
|
|
199
|
+
symmetric merging-firm margins.
|
|
200
|
+
|
|
201
|
+
Reimplements the arithmetic-averages and distance estimations from function,
|
|
202
|
+
`shrratio_boundary_wtd_avg`but uses the Minkowski-distance function,
|
|
203
|
+
`scipy.spatial.distance.minkowski` for all aggregators. This reimplementation
|
|
204
|
+
is useful for testing the output of `shrratio_boundary_wtd_avg`
|
|
205
|
+
but runs considerably slower.
|
|
206
|
+
|
|
207
|
+
Parameters
|
|
208
|
+
----------
|
|
209
|
+
_delta_star
|
|
210
|
+
corollary to GUPPI bound (:math:`\\overline{g} / (m^* \\cdot \\overline{r})`)
|
|
211
|
+
_r_val
|
|
212
|
+
recapture ratio
|
|
213
|
+
agg_method
|
|
214
|
+
Whether "arithmetic", "geometric", or "distance".
|
|
215
|
+
weighting
|
|
216
|
+
Whether "own-share" or "cross-product-share".
|
|
217
|
+
recapture_spec
|
|
218
|
+
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
219
|
+
value for both merging firms ("proportional").
|
|
220
|
+
prec
|
|
221
|
+
Number of decimal places for rounding returned shares and area.
|
|
222
|
+
|
|
223
|
+
Returns
|
|
224
|
+
-------
|
|
225
|
+
Array of share-pairs, area under boundary.
|
|
226
|
+
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
_delta_star = mpf(f"{_delta_star}")
|
|
230
|
+
_s_mid = _delta_star / (1 + _delta_star)
|
|
231
|
+
|
|
232
|
+
# initial conditions
|
|
233
|
+
_gbdry_points = [(_s_mid, _s_mid)]
|
|
234
|
+
_s_1_pre, _s_2_pre = _s_mid, _s_mid
|
|
235
|
+
_s_2_oddval, _s_2_oddsum, _s_2_evnsum = True, 0, 0
|
|
236
|
+
|
|
237
|
+
# parameters for iteration
|
|
238
|
+
_weights_base = (mpf("0.5"),) * 2
|
|
239
|
+
_gbd_step_sz = mp.power(10, -prec)
|
|
240
|
+
_theta = _gbd_step_sz * (10 if weighting == "cross-product-share" else 1)
|
|
241
|
+
for _s_1 in mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz):
|
|
242
|
+
# The wtd. avg. GUPPI is not always convex to the origin, so we
|
|
243
|
+
# increment _s_2 after each iteration in which our algorithm
|
|
244
|
+
# finds (s1, s2) on the boundary
|
|
245
|
+
_s_2 = _s_2_pre * (1 + _theta)
|
|
246
|
+
|
|
247
|
+
if (_s_1 + _s_2) > mpf("0.99875"):
|
|
248
|
+
# 1: # We lose accuracy at 3-9s and up
|
|
249
|
+
break
|
|
250
|
+
|
|
251
|
+
while True:
|
|
252
|
+
_de_1 = _s_2 / (1 - _s_1)
|
|
253
|
+
_de_2 = (
|
|
254
|
+
_s_1 / (1 - lerp(_s_1, _s_2, _r_val))
|
|
255
|
+
if recapture_spec == "inside-out"
|
|
256
|
+
else _s_1 / (1 - _s_2)
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
_weights_i = (
|
|
260
|
+
(
|
|
261
|
+
_w1 := mp.fdiv(
|
|
262
|
+
_s_2 if weighting == "cross-product-share" else _s_1,
|
|
263
|
+
_s_1 + _s_2,
|
|
264
|
+
),
|
|
265
|
+
1 - _w1,
|
|
266
|
+
)
|
|
267
|
+
if weighting
|
|
268
|
+
else _weights_base
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
match agg_method:
|
|
272
|
+
case "arithmetic":
|
|
273
|
+
_delta_test = distance_function(
|
|
274
|
+
(_de_1, _de_2), (0.0, 0.0), p=1, w=_weights_i
|
|
275
|
+
)
|
|
276
|
+
case "distance":
|
|
277
|
+
_delta_test = distance_function(
|
|
278
|
+
(_de_1, _de_2), (0.0, 0.0), p=2, w=_weights_i
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
_test_flag, _incr_decr = (
|
|
282
|
+
(_delta_test > _delta_star, -1)
|
|
283
|
+
if weighting == "cross-product-share"
|
|
284
|
+
else (_delta_test < _delta_star, 1)
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
if _test_flag:
|
|
288
|
+
_s_2 += _incr_decr * _gbd_step_sz
|
|
289
|
+
else:
|
|
290
|
+
break
|
|
291
|
+
|
|
292
|
+
# Build-up boundary points
|
|
293
|
+
_gbdry_points.append((_s_1, _s_2))
|
|
294
|
+
|
|
295
|
+
# Build up area terms
|
|
296
|
+
_s_2_oddsum += _s_2 if _s_2_oddval else 0
|
|
297
|
+
_s_2_evnsum += _s_2 if not _s_2_oddval else 0
|
|
298
|
+
_s_2_oddval = not _s_2_oddval
|
|
299
|
+
|
|
300
|
+
# Hold share points
|
|
301
|
+
_s_2_pre = _s_2
|
|
302
|
+
_s_1_pre = _s_1
|
|
303
|
+
|
|
304
|
+
if _s_2_oddval:
|
|
305
|
+
_s_2_evnsum -= _s_2_pre
|
|
306
|
+
else:
|
|
307
|
+
_s_2_oddsum -= _s_1_pre
|
|
308
|
+
|
|
309
|
+
_s_intcpt = _shrratio_boundary_intcpt(
|
|
310
|
+
_s_1_pre,
|
|
311
|
+
_delta_star,
|
|
312
|
+
_r_val,
|
|
313
|
+
recapture_spec=recapture_spec,
|
|
314
|
+
agg_method=agg_method,
|
|
315
|
+
weighting=weighting,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
if weighting == "own-share":
|
|
319
|
+
_gbd_prtlarea = (
|
|
320
|
+
_gbd_step_sz * (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_2_pre) / 3
|
|
321
|
+
)
|
|
322
|
+
# Area under boundary
|
|
323
|
+
_gbdry_area_total = 2 * (_s_1_pre + _gbd_prtlarea) - (
|
|
324
|
+
mp.power(_s_mid, "2") + mp.power(_s_1_pre, "2")
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
else:
|
|
328
|
+
_gbd_prtlarea = (
|
|
329
|
+
_gbd_step_sz * (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_intcpt) / 3
|
|
330
|
+
)
|
|
331
|
+
# Area under boundary
|
|
332
|
+
_gbdry_area_total = 2 * _gbd_prtlarea - mp.power(_s_mid, "2")
|
|
333
|
+
|
|
334
|
+
_gbdry_points = np.row_stack((_gbdry_points, (mpf("0.0"), _s_intcpt))).astype(
|
|
335
|
+
np.float64
|
|
336
|
+
)
|
|
337
|
+
# Points defining boundary to point-of-symmetry
|
|
338
|
+
return GuidelinesBoundary(
|
|
339
|
+
np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
|
|
340
|
+
round(float(_gbdry_area_total), prec),
|
|
341
|
+
)
|
|
@@ -145,7 +145,7 @@ class MultithreadedRNG:
|
|
|
145
145
|
dist_type: Literal[
|
|
146
146
|
"Beta", "Dirichlet", "Gaussian", "Normal", "Random", "Uniform"
|
|
147
147
|
] = "Uniform",
|
|
148
|
-
dist_parms: NDArray[np.floating[TF]] | None = DIST_PARMS_DEFAULT,
|
|
148
|
+
dist_parms: NDArray[np.floating[TF]] | None = DIST_PARMS_DEFAULT, # type: ignore
|
|
149
149
|
seed_sequence: SeedSequence | None = None,
|
|
150
150
|
nthreads: int = NTHREADS,
|
|
151
151
|
):
|
|
@@ -27,18 +27,21 @@ from pathlib import Path
|
|
|
27
27
|
from typing import Any, Literal
|
|
28
28
|
|
|
29
29
|
import matplotlib.axes as mpa
|
|
30
|
-
from
|
|
30
|
+
from jinja2 import FileSystemLoader
|
|
31
|
+
from joblib import Parallel, cpu_count, delayed # type: ignore
|
|
31
32
|
from numpy import pi
|
|
32
|
-
from xlsxwriter import Workbook
|
|
33
|
+
from xlsxwriter import Workbook # type: ignore
|
|
33
34
|
|
|
34
35
|
import mergeron.core.excel_helper as xlh
|
|
35
36
|
import mergeron.core.guidelines_boundaries as gbl
|
|
36
37
|
import mergeron.ext.tol_colors as ptcolor
|
|
37
|
-
|
|
38
|
+
import mergeron.gen.investigations_stats as isl
|
|
39
|
+
from mergeron import DATA_DIR, RECConstants, UPPAggrSelector
|
|
40
|
+
from mergeron.core import UPPBoundarySpec
|
|
38
41
|
|
|
39
42
|
PROG_PATH = Path(__file__)
|
|
40
43
|
|
|
41
|
-
RECAPTURE_SPEC =
|
|
44
|
+
RECAPTURE_SPEC = RECConstants.INOUT
|
|
42
45
|
# Map boundary forms to titles and generating-function names, with
|
|
43
46
|
# additional parameters as relevant
|
|
44
47
|
BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
|
|
@@ -52,26 +55,22 @@ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
|
|
|
52
55
|
"title_str": "Aggregated-diversion-ratio boundary, own-share wtd. avg.",
|
|
53
56
|
"sheet_name": "OSWAG, wtd avg",
|
|
54
57
|
"func_str": R"(s_1 d_{12} + s_2 d_{21}) / s_M",
|
|
55
|
-
"
|
|
56
|
-
"
|
|
58
|
+
"agg_method": UPPAggrSelector.OSA,
|
|
59
|
+
"recapture_spec": RECAPTURE_SPEC,
|
|
57
60
|
},
|
|
58
61
|
"OSWAG Own-shr-wtd Div Ratio Distance": {
|
|
59
62
|
"title_str": "Aggregated-diversion-ratio boundary, own-shr. wtd. distance",
|
|
60
63
|
"sheet_name": "OSWAG, distance",
|
|
61
64
|
"func_str": R"\surd (s_1 d_{12}^2 / s_M + s_2 d_{21}^2 / s_M)",
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"wgtng_policy": "own-share",
|
|
65
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
66
|
-
"avg_method": "distance",
|
|
67
|
-
},
|
|
65
|
+
"agg_method": UPPAggrSelector.OSD,
|
|
66
|
+
"recapture_spec": RECAPTURE_SPEC,
|
|
68
67
|
},
|
|
69
68
|
"OSWAG Min Div Ratio": {
|
|
70
69
|
"title_str": "Aggregated-diversion-ratio boundary, minimum",
|
|
71
70
|
"sheet_name": "OSWAG, minimum",
|
|
72
71
|
"func_str": R"\min (d_{12}, d_{21})",
|
|
73
|
-
"
|
|
74
|
-
"
|
|
72
|
+
"agg_method": UPPAggrSelector.MIN,
|
|
73
|
+
"recapture_spec": RECAPTURE_SPEC,
|
|
75
74
|
},
|
|
76
75
|
"SAG Combined Share": {
|
|
77
76
|
"title_str": "Combined Share boundary",
|
|
@@ -79,23 +78,19 @@ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
|
|
|
79
78
|
"func_str": R"s_M",
|
|
80
79
|
"func": gbl.combined_share_boundary,
|
|
81
80
|
},
|
|
82
|
-
"SAG Div Ratio Distance": {
|
|
83
|
-
"title_str": "Aggregated-diversion-ratio boundary, distance",
|
|
84
|
-
"sheet_name": "SAG, distance",
|
|
85
|
-
"func_str": R"\surd (d_{12}^2 / 2 + d_{21}^2 / 2)",
|
|
86
|
-
"func": gbl.shrratio_boundary_wtd_avg,
|
|
87
|
-
"func_kwargs": {
|
|
88
|
-
"wgtng_policy": None,
|
|
89
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
90
|
-
"avg_method": "distance",
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
81
|
"SAG Average Div Ratio": {
|
|
94
82
|
"title_str": "Aggregated-diversion-ratio boundary, simple average",
|
|
95
83
|
"sheet_name": "SAG, average",
|
|
96
84
|
"func_str": R"(d_{12} + d_{21}) / 2",
|
|
97
|
-
"
|
|
98
|
-
"
|
|
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,
|
|
99
94
|
},
|
|
100
95
|
"CPSWAG Premerger HHI-contribution": {
|
|
101
96
|
"title_str": "Premerger HHI-contribution boundary",
|
|
@@ -107,33 +102,27 @@ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
|
|
|
107
102
|
"title_str": "Aggregated-diversion-ratio boundary, cross-product-share wtd. avg.",
|
|
108
103
|
"sheet_name": "CPSWAG, wtd avg",
|
|
109
104
|
"func_str": R"(s_2 d_{12} / s_M + s_1 d_{21} / s_M)",
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"wgtng_policy": "cross-product-share",
|
|
113
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
114
|
-
},
|
|
105
|
+
"agg_method": UPPAggrSelector.CPA,
|
|
106
|
+
"recapture_spec": RECAPTURE_SPEC,
|
|
115
107
|
},
|
|
116
108
|
"CPSWAG Cross-product-shr-wtd Div Ratio Distance": {
|
|
117
109
|
"title_str": "Aggregated-diversion-ratio boundary, cross-prod-shr. wtd. distance",
|
|
118
110
|
"sheet_name": "CPSWAG, distance",
|
|
119
111
|
"func_str": R"\surd (s_2 d_{12}^2 / s_M + s_1 d_{21}^2 / s_M)",
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"wgtng_policy": "cross-product-share",
|
|
123
|
-
"recapture_spec": RECAPTURE_SPEC,
|
|
124
|
-
"avg_method": "distance",
|
|
125
|
-
},
|
|
112
|
+
"agg_method": UPPAggrSelector.CPD,
|
|
113
|
+
"recapture_spec": RECAPTURE_SPEC,
|
|
126
114
|
},
|
|
127
115
|
"CPSWAG Max Div Ratio": {
|
|
128
116
|
"title_str": "Aggregated-diversion-ratio boundary, maximum",
|
|
129
117
|
"sheet_name": "CPSWAG, maximum",
|
|
130
118
|
"func_str": R"\max (d_{12}, d_{21})",
|
|
131
|
-
"
|
|
119
|
+
"agg_method": UPPAggrSelector.MAX,
|
|
120
|
+
"recapture_spec": RECAPTURE_SPEC,
|
|
132
121
|
},
|
|
133
122
|
}
|
|
134
123
|
|
|
135
124
|
|
|
136
|
-
def tabulate_boundary_stats(_gpubyr:
|
|
125
|
+
def tabulate_boundary_stats(_gpubyr: gbl.HMGPubYear, /) -> None:
|
|
137
126
|
"""
|
|
138
127
|
Parameters
|
|
139
128
|
----------
|
|
@@ -142,15 +131,17 @@ def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
|
|
|
142
131
|
are drawn
|
|
143
132
|
|
|
144
133
|
"""
|
|
134
|
+
_invres_rate_table_content = isl.StatsContainer()
|
|
135
|
+
|
|
145
136
|
gso = gbl.GuidelinesThresholds(_gpubyr)
|
|
146
137
|
_dhhi_val, _r_val, _g_val = (
|
|
147
138
|
getattr(gso.presumption, _f) for _f in ("delta", "rec", "guppi")
|
|
148
139
|
)
|
|
149
140
|
|
|
150
141
|
_dhhi_seq = (
|
|
151
|
-
(0.01, 0.02,
|
|
142
|
+
(0.005, 0.01, 0.02, gso.imputed_presumption.delta, 0.08)
|
|
152
143
|
if _gpubyr == 2010
|
|
153
|
-
else (0.005, 0.01, 0.02,
|
|
144
|
+
else (0.005, 0.01, 0.02, gso.imputed_presumption.delta, 0.08)
|
|
154
145
|
)
|
|
155
146
|
|
|
156
147
|
_bdry_approx_data_dict = {
|
|
@@ -166,7 +157,7 @@ def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
|
|
|
166
157
|
),
|
|
167
158
|
)
|
|
168
159
|
for _k in BDRY_SPECS_DICT
|
|
169
|
-
if not _k.endswith("Distance")
|
|
160
|
+
# if not _k.endswith("Distance")
|
|
170
161
|
}
|
|
171
162
|
}
|
|
172
163
|
_bdry_approx_data_dict |= {
|
|
@@ -176,32 +167,46 @@ def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
|
|
|
176
167
|
}
|
|
177
168
|
|
|
178
169
|
_bdry_data = Parallel(n_jobs=-1)(
|
|
179
|
-
delayed(_dhhi_stats)(_dhhi_val, _r_val
|
|
170
|
+
delayed(_dhhi_stats)(_dhhi_val, _r_val) for _dhhi_val in _dhhi_seq
|
|
180
171
|
)
|
|
181
172
|
_bdry_approx_data_dict |= dict(_bdry_data)
|
|
182
173
|
|
|
183
|
-
|
|
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
|
+
)
|
|
184
181
|
for _sk in _bdry_approx_data_dict["Criterion"]:
|
|
185
|
-
|
|
186
|
-
" & ".join(
|
|
187
|
-
_bdry_approx_data_dict[_k][_sk] for _k in _bdry_approx_data_dict
|
|
188
|
-
),
|
|
189
|
-
R"\\",
|
|
182
|
+
_data_str += "{} \\\\ \n".format(
|
|
183
|
+
" & ".join(_bdry_approx_data_dict[_k][_sk] for _k in _bdry_approx_data_dict)
|
|
190
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))
|
|
191
197
|
|
|
192
198
|
|
|
193
|
-
def _dhhi_stats(
|
|
194
|
-
_dhhi_val: float, _r_val: float, _g_val: float
|
|
195
|
-
) -> tuple[str, dict[str, str]]:
|
|
199
|
+
def _dhhi_stats(_dhhi_val: float, _r_val: float) -> tuple[str, dict[str, str]]:
|
|
196
200
|
_dhhi_val = round(_dhhi_val, 5)
|
|
197
201
|
|
|
198
|
-
|
|
199
|
-
|
|
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)
|
|
200
205
|
|
|
201
|
-
_delta_val = _s_mid / (1 - _s_mid)
|
|
202
|
-
if _dhhi_val * 1e4 in (50, 100, 200):
|
|
203
|
-
|
|
204
|
-
_divr_val = _r_val * _delta_val
|
|
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
|
|
205
210
|
|
|
206
211
|
print(
|
|
207
212
|
"Processing data for ΔHHI = {0:.{1}f} points;".format(
|
|
@@ -237,18 +242,23 @@ def _bdry_stats_col(
|
|
|
237
242
|
case "CPSWAG Premerger HHI-contribution":
|
|
238
243
|
return _bdry_spec, f"{_hhi_m_pre_prob:6.5f}"
|
|
239
244
|
case _ if "Div Ratio" in _bdry_spec:
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
|
244
253
|
_within_bdry_prob = 2 * _within_bdry_area
|
|
245
|
-
|
|
246
|
-
_hhi_m_pre_prob
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
|
252
262
|
_within_bdry_prob,
|
|
253
263
|
100 * (1 - (_within_conc_bdry_prob / _within_bdry_prob)),
|
|
254
264
|
)
|
|
@@ -257,7 +267,7 @@ def _bdry_stats_col(
|
|
|
257
267
|
|
|
258
268
|
|
|
259
269
|
def plot_and_save_boundary_coords(
|
|
260
|
-
_gpubyr:
|
|
270
|
+
_gpubyr: gbl.HMGPubYear,
|
|
261
271
|
_xl_book: Workbook,
|
|
262
272
|
/,
|
|
263
273
|
layout: Literal["collected", "distributed"] = "collected",
|
|
@@ -390,10 +400,11 @@ def gen_plot_boundary(
|
|
|
390
400
|
print(_bdry_spec_dict["title_str"])
|
|
391
401
|
|
|
392
402
|
_pt_mdco: ptcolor.Mcset = ptcolor.tol_cset("medium-contrast") # type: ignore
|
|
403
|
+
_pt_vbco: ptcolor.Vcset = ptcolor.tol_cset("vibrant") # type: ignore
|
|
393
404
|
|
|
394
405
|
_plot_line_width = 1.0
|
|
395
406
|
_plot_line_alpha = 0.8
|
|
396
|
-
_plot_line_color =
|
|
407
|
+
_plot_line_color = _pt_vbco.black
|
|
397
408
|
_plot_line_style = {"OSWAG": "-", "SAG": "-.", "CPSWAG": "--"}.get(
|
|
398
409
|
_bdry_spec_str.split(" ")[0], "-"
|
|
399
410
|
)
|
|
@@ -407,15 +418,14 @@ def gen_plot_boundary(
|
|
|
407
418
|
case _ if _bdry_spec_str.startswith(("SAG Combined", "CPSWAG Premerger")):
|
|
408
419
|
_zrdr = 2
|
|
409
420
|
case _ if "Distance" in _bdry_spec_str:
|
|
410
|
-
_plot_line_color =
|
|
421
|
+
_plot_line_color = _pt_vbco.blue
|
|
411
422
|
_zrdr = 3
|
|
412
423
|
case _ if "shr-wtd" in _bdry_spec_str or "Mean" in _bdry_spec_str:
|
|
413
|
-
_plot_line_color =
|
|
424
|
+
_plot_line_color = _pt_vbco.teal
|
|
414
425
|
_zrdr = 3
|
|
415
426
|
case _:
|
|
416
|
-
_plot_line_color =
|
|
427
|
+
_plot_line_color = _pt_vbco.red
|
|
417
428
|
|
|
418
|
-
_dh_bar = _gso.safeharbor.divr
|
|
419
429
|
_g_val = _gso.safeharbor.guppi
|
|
420
430
|
|
|
421
431
|
_r_bar = _gso.presumption.rec
|
|
@@ -424,12 +434,15 @@ def gen_plot_boundary(
|
|
|
424
434
|
_s_mid = sqrt(_dhhi_val / 2)
|
|
425
435
|
_delta_val = _g_val / _r_bar if _gs_str == "safeharbor" else _s_mid / (1 - _s_mid)
|
|
426
436
|
|
|
427
|
-
_bdry_func = _bdry_spec_dict
|
|
437
|
+
_bdry_func = _bdry_spec_dict.get("func", gbl.shrratio_boundary)
|
|
428
438
|
if "Div Ratio" in _bdry_spec_str:
|
|
429
|
-
_bdry_boundary =
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
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
|
+
)
|
|
433
446
|
)
|
|
434
447
|
_plot_label_mag, _plot_label_uom = _r_bar * _delta_val * 1e2, "%"
|
|
435
448
|
elif _bdry_spec_str.endswith("Combined Share"):
|
|
@@ -599,8 +612,9 @@ def boundary_data_to_worksheet(
|
|
|
599
612
|
|
|
600
613
|
|
|
601
614
|
if __name__ == "__main__":
|
|
602
|
-
|
|
603
|
-
|
|
615
|
+
gpubyrs: list[gbl.HMGPubYear] = [1992, 2010, 2023]
|
|
616
|
+
for gpubyr in gpubyrs[2:][:1]:
|
|
617
|
+
tabulate_boundary_stats(gpubyr)
|
|
604
618
|
|
|
605
619
|
# Initiliaze workbook for saving boundary coordinates
|
|
606
620
|
with Workbook(
|