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.

@@ -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 joblib import Parallel, cpu_count, delayed
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
- from mergeron import DATA_DIR
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 = "inside-out"
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
- "func": gbl.shrratio_boundary_wtd_avg,
56
- "func_kwargs": {"wgtng_policy": "own-share", "recapture_spec": RECAPTURE_SPEC},
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
- "func": gbl.shrratio_boundary_wtd_avg,
63
- "func_kwargs": {
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
- "func": gbl.shrratio_boundary_min,
74
- "func_kwargs": {"recapture_spec": RECAPTURE_SPEC},
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
- "func": gbl.shrratio_boundary_xact_avg,
98
- "func_kwargs": {"recapture_spec": RECAPTURE_SPEC},
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
- "func": gbl.shrratio_boundary_wtd_avg,
111
- "func_kwargs": {
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
- "func": gbl.shrratio_boundary_wtd_avg,
121
- "func_kwargs": {
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
- "func": gbl.shrratio_boundary_max,
119
+ "agg_method": UPPAggrSelector.MAX,
120
+ "recapture_spec": RECAPTURE_SPEC,
132
121
  },
133
122
  }
134
123
 
135
124
 
136
- def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
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, 0.03125, 0.05, _dhhi_val)
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, 0.03125, _dhhi_val)
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, _g_val) for _dhhi_val in _dhhi_seq
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
- print(" & ".join(_k for _k in _bdry_approx_data_dict), R" \\")
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
- print(
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
- _r_val = round(_r_val, 4)
199
- _s_mid = sqrt(_dhhi_val / 2)
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
- _delta_val = gbl.round_cust(_r_val * _delta_val) / _r_val
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
- _gbd_func = BDRY_SPECS_DICT[_bdry_spec]["func"]
241
- _, _within_bdry_area = _gbd_func(
242
- _delta_val, _r_val, **BDRY_SPECS_DICT[_bdry_spec].get("func_kwargs", {})
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
- _within_conc_bdry_prob = (
246
- _hhi_m_pre_prob
247
- if _bdry_spec.startswith("CPSWAG")
248
- else (_cs_prob if _bdry_spec.startswith("SAG") else _dhhi_prob)
249
- )
250
-
251
- return _bdry_spec, R"{{ {:6.5f} \\ {:.2f}\% }}".format(
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: Literal[1992, 2010, 2023],
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 = _pt_mdco.black
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 = _pt_mdco.light_blue
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 = _pt_mdco.light_yellow
424
+ _plot_line_color = _pt_vbco.teal
414
425
  _zrdr = 3
415
426
  case _:
416
- _plot_line_color = _pt_mdco.dark_red
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["func"]
437
+ _bdry_func = _bdry_spec_dict.get("func", gbl.shrratio_boundary)
428
438
  if "Div Ratio" in _bdry_spec_str:
429
- _bdry_boundary = _bdry_func(
430
- _delta_val,
431
- _r_bar,
432
- **_bdry_spec_dict.get("func_kwargs", {}), # tupe: ignore
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
- for gpubyr in [1992, 2010, 2023][2:]:
603
- # tabulate_boundary_stats(gpubyr)
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(