mergeron 2024.739139.0__py3-none-any.whl → 2024.739145.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.

@@ -6,10 +6,11 @@ import numpy as np
6
6
  from mpmath import mp, mpf # type: ignore
7
7
 
8
8
  from .. import DEFAULT_REC_RATE, VERSION, ArrayBIGINT, ArrayDouble # noqa: TID252
9
+ from . import MPFloat
9
10
 
10
11
  __version__ = VERSION
11
12
 
12
- mp.prec = 80
13
+ mp.dps = 32
13
14
  mp.trap_complex = True
14
15
 
15
16
 
@@ -17,7 +18,7 @@ class ShareRatioBoundaryKeywords(TypedDict, total=False):
17
18
  """Keyword arguments for functions generating share ratio boundaries."""
18
19
 
19
20
  recapture_form: Literal["inside-out", "proportional"]
20
- prec: int
21
+ dps: int
21
22
  agg_method: Literal["arithmetic mean", "geometric mean", "distance"]
22
23
  weighting: Literal["own-share", "cross-product-share", None]
23
24
 
@@ -33,7 +34,7 @@ class GuidelinesBoundary:
33
34
  """Area under the boundary."""
34
35
 
35
36
 
36
- def dh_area(_dh_val: float = 0.01, /, *, prec: int = 9) -> float:
37
+ def dh_area(_dh_val: float | MPFloat = 0.01, /, *, dps: int = 9) -> float:
37
38
  R"""
38
39
  Area under the ΔHHI boundary.
39
40
 
@@ -56,7 +57,7 @@ def dh_area(_dh_val: float = 0.01, /, *, prec: int = 9) -> float:
56
57
  ----------
57
58
  _dh_val
58
59
  Change in concentration.
59
- prec
60
+ dps
60
61
  Specified precision in decimal places.
61
62
 
62
63
  Returns
@@ -70,13 +71,11 @@ def dh_area(_dh_val: float = 0.01, /, *, prec: int = 9) -> float:
70
71
 
71
72
  return round(
72
73
  float(_s_naught + (_dh_val / 2) * (mp.ln(1 - _s_naught) - mp.ln(_s_naught))),
73
- prec,
74
+ dps,
74
75
  )
75
76
 
76
77
 
77
- def hhi_delta_boundary(
78
- _dh_val: float = 0.01, /, *, prec: int = 5
79
- ) -> GuidelinesBoundary:
78
+ def hhi_delta_boundary(_dh_val: float = 0.01, /, *, dps: int = 5) -> GuidelinesBoundary:
80
79
  """
81
80
  Generate the list of share combination on the ΔHHI boundary.
82
81
 
@@ -84,7 +83,7 @@ def hhi_delta_boundary(
84
83
  ----------
85
84
  _dh_val:
86
85
  Merging-firms' ΔHHI bound.
87
- prec
86
+ dps
88
87
  Number of decimal places for rounding reported shares.
89
88
 
90
89
  Returns
@@ -106,20 +105,13 @@ def hhi_delta_boundary(
106
105
  np.column_stack((_s_1, _s_2)),
107
106
  np.array([(mpf("0.0"), mpf("1.0"))]),
108
107
  ))
109
- _dh_bdry_pts = np.vstack((np.flip(_dh_half, 0), np.flip(_dh_half[1:], 1)))
108
+ _dh_bdry_pts = np.vstack((_dh_half[::-1], _dh_half[1:, ::-1]))
110
109
 
111
- _s_1_pts, _s_2_pts = np.split(_dh_bdry_pts, 2, axis=1)
112
- return GuidelinesBoundary(
113
- np.column_stack((
114
- np.array(_s_1_pts, np.float64),
115
- np.array(_s_2_pts, np.float64),
116
- )),
117
- dh_area(_dh_val, prec=prec),
118
- )
110
+ return GuidelinesBoundary(_dh_bdry_pts, dh_area(_dh_val, dps=dps))
119
111
 
120
112
 
121
113
  def hhi_pre_contrib_boundary(
122
- _hhi_contrib: float = 0.03125, /, *, prec: int = 5
114
+ _hhi_contrib: float = 0.03125, /, *, dps: int = 5
123
115
  ) -> GuidelinesBoundary:
124
116
  """
125
117
  Share combinations on the premerger HHI contribution boundary.
@@ -128,7 +120,7 @@ def hhi_pre_contrib_boundary(
128
120
  ----------
129
121
  _hhi_contrib:
130
122
  Merging-firms' pre-merger HHI contribution bound.
131
- prec
123
+ dps
132
124
  Number of decimal places for rounding reported shares.
133
125
 
134
126
  Returns
@@ -139,19 +131,19 @@ def hhi_pre_contrib_boundary(
139
131
  _hhi_contrib = mpf(f"{_hhi_contrib}")
140
132
  _s_mid = mp.sqrt(_hhi_contrib / 2)
141
133
 
142
- _bdry_step_sz = mp.power(10, -prec)
134
+ _bdry_step_sz = mp.power(10, -dps)
143
135
  # Range-limit is 0 less a step, which is -1 * step-size
144
136
  _s_1 = np.array(mp.arange(_s_mid, -_bdry_step_sz, -_bdry_step_sz), np.float64)
145
137
  _s_2 = np.sqrt(_hhi_contrib - _s_1**2).astype(np.float64)
146
138
  _bdry_pts_mid = np.column_stack((_s_1, _s_2))
147
139
  return GuidelinesBoundary(
148
- np.vstack((np.flip(_bdry_pts_mid, 0), np.flip(_bdry_pts_mid[1:], 1))),
149
- round(float(mp.pi * _hhi_contrib / 4), prec),
140
+ np.vstack((_bdry_pts_mid[::-1], _bdry_pts_mid[1:, ::-1])),
141
+ round(float(mp.pi * _hhi_contrib / 4), dps),
150
142
  )
151
143
 
152
144
 
153
145
  def combined_share_boundary(
154
- _s_intcpt: float = 0.0625, /, *, prec: int = 10
146
+ _s_intcpt: float = 0.0625, /, *, dps: int = 10
155
147
  ) -> GuidelinesBoundary:
156
148
  """
157
149
  Share combinations on the merging-firms' combined share boundary.
@@ -164,7 +156,7 @@ def combined_share_boundary(
164
156
  ----------
165
157
  _s_intcpt:
166
158
  Merging-firms' combined share.
167
- prec
159
+ dps
168
160
  Number of decimal places for rounding reported shares.
169
161
 
170
162
  Returns
@@ -181,12 +173,12 @@ def combined_share_boundary(
181
173
  np.array(_s1_pts, np.float64),
182
174
  np.array(_s1_pts[::-1], np.float64),
183
175
  )),
184
- round(float(_s_intcpt * _s_mid), prec),
176
+ round(float(_s_intcpt * _s_mid), dps),
185
177
  )
186
178
 
187
179
 
188
180
  def hhi_post_contrib_boundary(
189
- _hhi_contrib: float = 0.800, /, *, prec: int = 10
181
+ _hhi_contrib: float = 0.800, /, *, dps: int = 10
190
182
  ) -> GuidelinesBoundary:
191
183
  """
192
184
  Share combinations on the postmerger HHI contribution boundary.
@@ -198,7 +190,7 @@ def hhi_post_contrib_boundary(
198
190
  ----------
199
191
  _hhi_contrib:
200
192
  Merging-firms' pre-merger HHI contribution bound.
201
- prec
193
+ dps
202
194
  Number of decimal places for rounding reported shares.
203
195
 
204
196
  Returns
@@ -206,7 +198,7 @@ def hhi_post_contrib_boundary(
206
198
  Array of share-pairs, area under boundary.
207
199
 
208
200
  """
209
- return combined_share_boundary(np.sqrt(_hhi_contrib), prec=prec)
201
+ return combined_share_boundary(np.sqrt(_hhi_contrib), dps=dps)
210
202
 
211
203
 
212
204
  def shrratio_boundary_wtd_avg(
@@ -219,7 +211,7 @@ def shrratio_boundary_wtd_avg(
219
211
  ] = "arithmetic mean",
220
212
  weighting: Literal["own-share", "cross-product-share", None] = "own-share",
221
213
  recapture_form: Literal["inside-out", "proportional"] = "inside-out",
222
- prec: int = 5,
214
+ dps: int = 5,
223
215
  ) -> GuidelinesBoundary:
224
216
  """
225
217
  Share combinations on the share-weighted average diversion ratio boundary.
@@ -237,7 +229,7 @@ def shrratio_boundary_wtd_avg(
237
229
  recapture_form
238
230
  Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
239
231
  value for both merging firms ("proportional").
240
- prec
232
+ dps
241
233
  Number of decimal places for rounding returned shares and area.
242
234
 
243
235
  Returns
@@ -309,7 +301,7 @@ def shrratio_boundary_wtd_avg(
309
301
  """
310
302
 
311
303
  _delta_star = mpf(f"{_delta_star}")
312
- _s_mid = _delta_star / (1 + _delta_star)
304
+ _s_mid = mp.fdiv(_delta_star, 1 + _delta_star)
313
305
 
314
306
  # initial conditions
315
307
  _gbdry_points = [(_s_mid, _s_mid)]
@@ -317,7 +309,7 @@ def shrratio_boundary_wtd_avg(
317
309
  _s_2_oddval, _s_2_oddsum, _s_2_evnsum = True, 0.0, 0.0
318
310
 
319
311
  # parameters for iteration
320
- _gbd_step_sz = mp.power(10, -prec)
312
+ _gbd_step_sz = mp.power(10, -dps)
321
313
  _theta = _gbd_step_sz * (10 if weighting == "cross-product-share" else 1)
322
314
  for _s_1 in mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz):
323
315
  # The wtd. avg. GUPPI is not always convex to the origin, so we
@@ -346,7 +338,7 @@ def shrratio_boundary_wtd_avg(
346
338
  )
347
339
 
348
340
  match agg_method:
349
- case "geometric":
341
+ case "geometric mean":
350
342
  _delta_test = mp.expm1(lerp(mp.log1p(_de_1), mp.log1p(_de_2), _r))
351
343
  case "distance":
352
344
  _delta_test = mp.sqrt(lerp(_de_1**2, _de_2**2, _r))
@@ -407,14 +399,13 @@ def shrratio_boundary_wtd_avg(
407
399
  # Area under boundary
408
400
  _gbdry_area_total = float(2 * _gbd_prtlarea - mp.power(_s_mid, "2"))
409
401
 
410
- _gbdry_points = np.vstack((_gbdry_points, (mpf("0.0"), _s_intcpt))).astype(
411
- np.float64
412
- )
402
+ _gbdry_points.append((mpf("0.0"), _s_intcpt))
403
+ _gbd_pts_arr = np.array(_gbdry_points).astype(np.float64)
413
404
 
414
405
  # Points defining boundary to point-of-symmetry
415
406
  return GuidelinesBoundary(
416
- np.vstack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
417
- round(float(_gbdry_area_total), prec),
407
+ np.vstack((_gbd_pts_arr[::-1], _gbd_pts_arr[1:, ::-1])),
408
+ round(float(_gbdry_area_total), dps),
418
409
  )
419
410
 
420
411
 
@@ -424,7 +415,7 @@ def shrratio_boundary_xact_avg(
424
415
  /,
425
416
  *,
426
417
  recapture_form: Literal["inside-out", "proportional"] = "inside-out",
427
- prec: int = 5,
418
+ dps: int = 5,
428
419
  ) -> GuidelinesBoundary:
429
420
  """
430
421
  Share combinations for the simple average GUPPI boundary with symmetric
@@ -472,7 +463,7 @@ def shrratio_boundary_xact_avg(
472
463
  recapture_form
473
464
  Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
474
465
  value for both merging firms ("proportional").
475
- prec
466
+ dps
476
467
  Number of decimal places for rounding returned shares.
477
468
 
478
469
  Returns
@@ -483,7 +474,7 @@ def shrratio_boundary_xact_avg(
483
474
 
484
475
  _delta_star = mpf(f"{_delta_star}")
485
476
  _s_mid = _delta_star / (1 + _delta_star)
486
- _gbd_step_sz = mp.power(10, -prec)
477
+ _gbd_step_sz = mp.power(10, -dps)
487
478
 
488
479
  _gbdry_points_start = np.array([(_s_mid, _s_mid)])
489
480
  _s_1 = np.array(mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz), np.float64)
@@ -523,7 +514,7 @@ def shrratio_boundary_xact_avg(
523
514
  np.einsum("i->", _nr_t2_mdr.astype(np.float64)),
524
515
  np.einsum("i->", _nr_t2_s1.astype(np.float64)),
525
516
  rtol=0,
526
- atol=0.5 * prec,
517
+ atol=0.5 * dps,
527
518
  ):
528
519
  raise RuntimeError(
529
520
  "Calculation of sq. root term in exact average GUPPI"
@@ -552,7 +543,162 @@ def shrratio_boundary_xact_avg(
552
543
 
553
544
  _gbdry_points = np.vstack((
554
545
  _gbdry_points_end,
555
- np.flip(_gbdry_points_inner, 0),
546
+ _gbdry_points_inner[::-1],
547
+ _gbdry_points_start,
548
+ _gbdry_points_inner[:, ::-1],
549
+ _gbdry_points_end[:, ::-1],
550
+ )).astype(np.float64)
551
+ _s_2 = np.concatenate((np.array([_s_mid], np.float64), _s_2))
552
+
553
+ _gbdry_ends = [0, -1]
554
+ _gbdry_odds = np.array(range(1, len(_s_2), 2), np.int64)
555
+ _gbdry_evns = np.array(range(2, len(_s_2), 2), np.int64)
556
+
557
+ # Double the are under the curve, and subtract the double counted bit.
558
+ _gbdry_area_simpson = 2 * _gbd_step_sz * (
559
+ (4 / 3) * np.sum(_s_2.take(_gbdry_odds))
560
+ + (2 / 3) * np.sum(_s_2.take(_gbdry_evns))
561
+ + (1 / 3) * np.sum(_s_2.take(_gbdry_ends))
562
+ ) - np.power(_s_mid, 2)
563
+
564
+ return GuidelinesBoundary(_gbdry_points, round(float(_gbdry_area_simpson), dps))
565
+
566
+
567
+ def shrratio_boundary_xact_avg_mp(
568
+ _delta_star: float = 0.075,
569
+ _r_val: float = DEFAULT_REC_RATE,
570
+ /,
571
+ *,
572
+ recapture_form: Literal["inside-out", "proportional"] = "inside-out",
573
+ dps: int = 5,
574
+ ) -> GuidelinesBoundary:
575
+ """
576
+ Share combinations for the simple average GUPPI boundary with symmetric
577
+ merging-firm margins.
578
+
579
+ Notes
580
+ -----
581
+ An analytical expression for the exact average boundary is derived
582
+ and plotted from the y-intercept to the ray of symmetry as follows::
583
+
584
+ from sympy import latex, plot as symplot, solve, symbols
585
+
586
+ s_1, s_2 = symbols("s_1 s_2")
587
+
588
+ g_val, r_val, m_val = 0.06, 0.80, 0.30
589
+ d_hat = g_val / (r_val * m_val)
590
+
591
+ # recapture_form = "inside-out"
592
+ sag = solve(
593
+ (s_2 / (1 - s_1))
594
+ + (s_1 / (1 - (r_val * s_2 + (1 - r_val) * s_1)))
595
+ - 2 * d_hat,
596
+ s_2
597
+ )[0]
598
+ symplot(
599
+ sag,
600
+ (s_1, 0., d_hat / (1 + d_hat)),
601
+ ylabel=s_2
602
+ )
603
+
604
+ # recapture_form = "proportional"
605
+ sag = solve((s_2/(1 - s_1)) + (s_1/(1 - s_2)) - 2 * d_hat, s_2)[0]
606
+ symplot(
607
+ sag,
608
+ (s_1, 0., d_hat / (1 + d_hat)),
609
+ ylabel=s_2
610
+ )
611
+
612
+ Parameters
613
+ ----------
614
+ _delta_star
615
+ Share ratio (:math:`\\overline{d} / \\overline{r}`).
616
+ _r_val
617
+ Recapture ratio
618
+ recapture_form
619
+ Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
620
+ value for both merging firms ("proportional").
621
+ dps
622
+ Number of decimal places for rounding returned shares.
623
+
624
+ Returns
625
+ -------
626
+ Array of share-pairs, area under boundary, area under boundary.
627
+
628
+ """
629
+
630
+ _delta_star = mpf(f"{_delta_star}")
631
+ _s_mid = _delta_star / (1 + _delta_star)
632
+ _gbd_step_sz = mp.power(10, -dps)
633
+
634
+ _gbdry_points_start = np.array([(_s_mid, _s_mid)])
635
+ _s_1 = np.array(mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz), np.float64)
636
+ if recapture_form == "inside-out":
637
+ _s_intcpt = mp.fdiv(
638
+ mp.fsub(
639
+ 2 * _delta_star * _r_val + 1, mp.fabs(2 * _delta_star * _r_val - 1)
640
+ ),
641
+ 2 * mpf(f"{_r_val}"),
642
+ )
643
+ _nr_t1 = 1 + 2 * _delta_star * _r_val * (1 - _s_1) - _s_1 * (1 - _r_val)
644
+
645
+ _nr_sqrt_mdr = 4 * _delta_star * _r_val
646
+ _nr_sqrt_mdr2 = _nr_sqrt_mdr * _r_val
647
+ _nr_sqrt_md2r2 = _nr_sqrt_mdr2 * _delta_star
648
+
649
+ _nr_sqrt_t1 = _nr_sqrt_md2r2 * (_s_1**2 - 2 * _s_1 + 1)
650
+ _nr_sqrt_t2 = _nr_sqrt_mdr2 * _s_1 * (_s_1 - 1)
651
+ _nr_sqrt_t3 = _nr_sqrt_mdr * (2 * _s_1 - _s_1**2 - 1)
652
+ _nr_sqrt_t4 = (_s_1**2) * (_r_val**2 - 6 * _r_val + 1)
653
+ _nr_sqrt_t5 = _s_1 * (6 * _r_val - 2) + 1
654
+
655
+ _nr_t2_mdr = _nr_sqrt_t1 + _nr_sqrt_t2 + _nr_sqrt_t3 + _nr_sqrt_t4 + _nr_sqrt_t5
656
+
657
+ # Alternative grouping of terms in np.sqrt
658
+ _nr_sqrt_s1sq = (_s_1**2) * (
659
+ _nr_sqrt_md2r2 + _nr_sqrt_mdr2 - _nr_sqrt_mdr + _r_val**2 - 6 * _r_val + 1
660
+ )
661
+ _nr_sqrt_s1 = _s_1 * (
662
+ -2 * _nr_sqrt_md2r2 - _nr_sqrt_mdr2 + 2 * _nr_sqrt_mdr + 6 * _r_val - 2
663
+ )
664
+ _nr_sqrt_nos1 = _nr_sqrt_md2r2 - _nr_sqrt_mdr + 1
665
+
666
+ _nr_t2_s1 = _nr_sqrt_s1sq + _nr_sqrt_s1 + _nr_sqrt_nos1
667
+
668
+ if not np.isclose(
669
+ np.einsum("i->", _nr_t2_mdr.astype(np.float64)),
670
+ np.einsum("i->", _nr_t2_s1.astype(np.float64)),
671
+ rtol=0,
672
+ atol=0.5 * dps,
673
+ ):
674
+ raise RuntimeError(
675
+ "Calculation of sq. root term in exact average GUPPI"
676
+ f"with recapture spec, {f'"{recapture_form}"'} is incorrect."
677
+ )
678
+
679
+ _s_2 = (_nr_t1 - np.sqrt(_nr_t2_s1)) / (2 * _r_val)
680
+
681
+ else:
682
+ _s_intcpt = mp.fsub(_delta_star + 1 / 2, mp.fabs(_delta_star - 1 / 2))
683
+ _s_2 = (
684
+ (1 / 2)
685
+ + _delta_star
686
+ - _delta_star * _s_1
687
+ - np.sqrt(
688
+ ((_delta_star**2) - 1) * (_s_1**2)
689
+ + (-2 * (_delta_star**2) + _delta_star + 1) * _s_1
690
+ + (_delta_star**2)
691
+ - _delta_star
692
+ + (1 / 4)
693
+ )
694
+ )
695
+
696
+ _gbdry_points_inner = np.column_stack((_s_1, _s_2))
697
+ _gbdry_points_end = np.array([(mpf("0.0"), _s_intcpt)], np.float64)
698
+
699
+ _gbdry_points = np.vstack((
700
+ _gbdry_points_end,
701
+ _gbdry_points_inner[::-1],
556
702
  _gbdry_points_start,
557
703
  np.flip(_gbdry_points_inner, 1),
558
704
  np.flip(_gbdry_points_end, 1),
@@ -570,11 +716,7 @@ def shrratio_boundary_xact_avg(
570
716
  + (1 / 3) * np.sum(_s_2.take(_gbdry_ends))
571
717
  ) - np.power(_s_mid, 2)
572
718
 
573
- _s_1_pts, _s_2_pts = np.split(_gbdry_points, 2, axis=1)
574
- return GuidelinesBoundary(
575
- np.column_stack((np.array(_s_1_pts), np.array(_s_2_pts))),
576
- round(float(_gbdry_area_simpson), prec),
577
- )
719
+ return GuidelinesBoundary(_gbdry_points, round(float(_gbdry_area_simpson), dps))
578
720
 
579
721
 
580
722
  def shrratio_boundary_min(
@@ -583,7 +725,7 @@ def shrratio_boundary_min(
583
725
  /,
584
726
  *,
585
727
  recapture_form: str = "inside-out",
586
- prec: int = 10,
728
+ dps: int = 10,
587
729
  ) -> GuidelinesBoundary:
588
730
  """
589
731
  Share combinations on the minimum GUPPI boundary, with symmetric
@@ -605,7 +747,7 @@ def shrratio_boundary_min(
605
747
  recapture_form
606
748
  Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
607
749
  value for both merging firms ("proportional").
608
- prec
750
+ dps
609
751
  Number of decimal places for rounding returned shares.
610
752
 
611
753
  Returns
@@ -640,12 +782,12 @@ def shrratio_boundary_min(
640
782
  _s1_pts, _gbd_area = np.array((0, _s_mid, _s_intcpt), np.float64), _s_mid
641
783
 
642
784
  return GuidelinesBoundary(
643
- np.column_stack((_s1_pts, _s1_pts[::-1])), round(float(_gbd_area), prec)
785
+ np.column_stack((_s1_pts, _s1_pts[::-1])), round(float(_gbd_area), dps)
644
786
  )
645
787
 
646
788
 
647
789
  def shrratio_boundary_max(
648
- _delta_star: float = 0.075, _r_val: float = DEFAULT_REC_RATE, /, *, prec: int = 10
790
+ _delta_star: float = 0.075, _r_val: float = DEFAULT_REC_RATE, /, *, dps: int = 10
649
791
  ) -> GuidelinesBoundary:
650
792
  """
651
793
  Share combinations on the minimum GUPPI boundary with symmetric
@@ -657,7 +799,7 @@ def shrratio_boundary_max(
657
799
  Share ratio (:math:`\\overline{d} / \\overline{r}`).
658
800
  _r_val
659
801
  Recapture ratio.
660
- prec
802
+ dps
661
803
  Number of decimal places for rounding returned shares.
662
804
 
663
805
  Returns
@@ -680,14 +822,14 @@ def shrratio_boundary_max(
680
822
  np.array(_s1_pts, np.float64),
681
823
  np.array(_s1_pts[::-1], np.float64),
682
824
  )),
683
- round(float(_s_intcpt * _s_mid), prec), # simplified calculation
825
+ round(float(_s_intcpt * _s_mid), dps), # simplified calculation
684
826
  )
685
827
 
686
828
 
687
829
  def _shrratio_boundary_intcpt(
688
830
  _s_2_pre: float,
689
- _delta_star: mpf,
690
- _r_val: mpf,
831
+ _delta_star: MPFloat,
832
+ _r_val: MPFloat,
691
833
  /,
692
834
  *,
693
835
  recapture_form: Literal["inside-out", "proportional"],
@@ -717,11 +859,11 @@ def _shrratio_boundary_intcpt(
717
859
 
718
860
 
719
861
  def lerp(
720
- _x1: int | float | mpf | ArrayDouble | ArrayBIGINT = 3,
721
- _x2: int | float | mpf | ArrayDouble | ArrayBIGINT = 1,
722
- _r: float | mpf = 0.25,
862
+ _x1: int | float | MPFloat | ArrayDouble | ArrayBIGINT = 3,
863
+ _x2: int | float | MPFloat | ArrayDouble | ArrayBIGINT = 1,
864
+ _r: float | MPFloat = 0.25,
723
865
  /,
724
- ) -> float | mpf | ArrayDouble:
866
+ ) -> float | MPFloat | ArrayDouble:
725
867
  """
726
868
  From the function of the same name in the C++ standard [2]_
727
869
 
@@ -17,16 +17,12 @@ from scipy.spatial.distance import minkowski as distance_function # type: ignor
17
17
  from sympy import lambdify, simplify, solve, symbols # type: ignore
18
18
 
19
19
  from .. import DEFAULT_REC_RATE, VERSION, ArrayDouble # noqa: TID252
20
- from .guidelines_boundary_functions import (
21
- GuidelinesBoundary,
22
- _shrratio_boundary_intcpt,
23
- lerp,
24
- )
20
+ from . import guidelines_boundary_functions as gbfn
25
21
 
26
22
  __version__ = VERSION
27
23
 
28
24
 
29
- mp.prec = 80
25
+ mp.dps = 32
30
26
  mp.trap_complex = True
31
27
 
32
28
 
@@ -37,7 +33,7 @@ class GuidelinesBoundaryCallable:
37
33
  s_naught: float = 0
38
34
 
39
35
 
40
- def dh_area_quad(_dh_val: float = 0.01, /, *, prec: int = 9) -> float:
36
+ def dh_area_quad(_dh_val: float = 0.01, /, *, dps: int = 9) -> float:
41
37
  """
42
38
  Area under the ΔHHI boundary.
43
39
 
@@ -49,7 +45,7 @@ def dh_area_quad(_dh_val: float = 0.01, /, *, prec: int = 9) -> float:
49
45
  ----------
50
46
  _dh_val
51
47
  Merging-firms' ΔHHI bound.
52
- prec
48
+ dps
53
49
  Specified precision in decimal places.
54
50
 
55
51
  Returns
@@ -65,7 +61,7 @@ def dh_area_quad(_dh_val: float = 0.01, /, *, prec: int = 9) -> float:
65
61
  float(
66
62
  _s_naught + mp.quad(lambda x: _dh_val / (2 * x), [_s_naught, 1 - _s_naught])
67
63
  ),
68
- prec,
64
+ dps,
69
65
  )
70
66
 
71
67
 
@@ -95,7 +91,7 @@ def hhi_delta_boundary_qdtr(_dh_val: float = 0.01, /) -> GuidelinesBoundaryCalla
95
91
 
96
92
  _hhi_bdry_area = 2 * (
97
93
  _s_nought
98
- + mp.quad(lambdify(_s_1, _hhi_bdry, "mpmath"), (_s_nought, 1 - _s_nought))
94
+ + mp.quad(lambdify(_s_1, _hhi_bdry, "mpmath"), (_s_nought, 1 - _s_nought)) # pyright: ignore
99
95
  )
100
96
 
101
97
  return GuidelinesBoundaryCallable(
@@ -163,7 +159,7 @@ def shrratio_boundary_qdtr_wtd_avg(
163
159
  2
164
160
  * (
165
161
  _s_naught
166
- + mp.quad(lambdify(_s_1, _bdry_func, "mpmath"), (_s_naught, _s_mid))
162
+ + mp.quad(lambdify(_s_1, _bdry_func, "mpmath"), (_s_naught, _s_mid)) # pyright: ignore
167
163
  )
168
164
  - (_s_mid**2 + _s_naught**2)
169
165
  )
@@ -193,7 +189,7 @@ def shrratio_boundary_qdtr_wtd_avg(
193
189
  ),
194
190
  (0, _s_mid),
195
191
  )
196
- ).real
192
+ ).real # pyright: ignore
197
193
  - _s_mid**2
198
194
  )
199
195
 
@@ -213,7 +209,7 @@ def shrratio_boundary_qdtr_wtd_avg(
213
209
 
214
210
  _bdry_func = solve(_bdry_eqn, _s_2)[0]
215
211
  _bdry_area = float(
216
- 2 * (mp.quad(lambdify(_s_1, _bdry_func, "mpmath"), (0, _s_mid)))
212
+ 2 * (mp.quad(lambdify(_s_1, _bdry_func, "mpmath"), (0, _s_mid))) # pyright: ignore
217
213
  - _s_mid**2
218
214
  )
219
215
 
@@ -230,8 +226,8 @@ def shrratio_boundary_distance(
230
226
  agg_method: Literal["arithmetic mean", "distance"] = "arithmetic mean",
231
227
  weighting: Literal["own-share", "cross-product-share"] | None = "own-share",
232
228
  recapture_form: Literal["inside-out", "proportional"] = "inside-out",
233
- prec: int = 5,
234
- ) -> GuidelinesBoundary:
229
+ dps: int = 5,
230
+ ) -> gbfn.GuidelinesBoundary:
235
231
  """
236
232
  Share combinations for the GUPPI boundaries using various aggregators with
237
233
  symmetric merging-firm margins.
@@ -255,7 +251,7 @@ def shrratio_boundary_distance(
255
251
  recapture_form
256
252
  Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
257
253
  value for both merging firms ("proportional").
258
- prec
254
+ dps
259
255
  Number of decimal places for rounding returned shares and area.
260
256
 
261
257
  Returns
@@ -274,7 +270,7 @@ def shrratio_boundary_distance(
274
270
 
275
271
  # parameters for iteration
276
272
  _weights_base = (mpf("0.5"),) * 2
277
- _gbd_step_sz = mp.power(10, -prec)
273
+ _gbd_step_sz = mp.power(10, -dps)
278
274
  _theta = _gbd_step_sz * (10 if weighting == "cross-product-share" else 1)
279
275
  for _s_1 in mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz):
280
276
  # The wtd. avg. GUPPI is not always convex to the origin, so we
@@ -289,7 +285,7 @@ def shrratio_boundary_distance(
289
285
  while True:
290
286
  _de_1 = _s_2 / (1 - _s_1)
291
287
  _de_2 = (
292
- _s_1 / (1 - lerp(_s_1, _s_2, _r_val))
288
+ _s_1 / (1 - gbfn.lerp(_s_1, _s_2, _r_val))
293
289
  if recapture_form == "inside-out"
294
290
  else _s_1 / (1 - _s_2)
295
291
  )
@@ -344,7 +340,7 @@ def shrratio_boundary_distance(
344
340
  else:
345
341
  _s_2_oddsum -= _s_1_pre
346
342
 
347
- _s_intcpt = _shrratio_boundary_intcpt(
343
+ _s_intcpt = gbfn._shrratio_boundary_intcpt(
348
344
  _s_1_pre,
349
345
  _delta_star,
350
346
  _r_val,
@@ -369,11 +365,9 @@ def shrratio_boundary_distance(
369
365
  # Area under boundary
370
366
  _gbdry_area_total = 2 * _gbd_prtlarea - mp.power(_s_mid, "2")
371
367
 
372
- _gbdry_points = np.vstack((_gbdry_points, (mpf("0.0"), _s_intcpt))).astype(
373
- np.float64
374
- )
368
+ _gbdry_points.append((mpf("0.0"), _s_intcpt))
375
369
  # Points defining boundary to point-of-symmetry
376
- return GuidelinesBoundary(
377
- np.vstack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
378
- round(float(_gbdry_area_total), prec),
370
+ return gbfn.GuidelinesBoundary(
371
+ np.vstack((_gbdry_points[::-1], np.flip(_gbdry_points[1:], 1))),
372
+ round(float(_gbdry_area_total), dps),
379
373
  )
@@ -19,7 +19,7 @@ from .. import VERSION, ArrayDouble # noqa: TID252
19
19
  __version__ = VERSION
20
20
 
21
21
  NTHREADS = 2 * cpu_count()
22
- DIST_PARMS_DEFAULT = np.array([0.0, 1.0], np.float64)
22
+ DEFAULT_DIST_PARMS = np.array([0.0, 1.0], np.float64)
23
23
 
24
24
 
25
25
  def prng(_s: SeedSequence | None = None, /) -> np.random.Generator:
@@ -139,7 +139,7 @@ class MultithreadedRNG:
139
139
  dist_type: Literal[
140
140
  "Beta", "Dirichlet", "Gaussian", "Normal", "Random", "Uniform"
141
141
  ] = "Uniform",
142
- dist_parms: ArrayDouble | None = DIST_PARMS_DEFAULT,
142
+ dist_parms: ArrayDouble | None = DEFAULT_DIST_PARMS,
143
143
  seed_sequence: SeedSequence | None = None,
144
144
  nthreads: int = NTHREADS,
145
145
  ):
@@ -166,7 +166,7 @@ class MultithreadedRNG:
166
166
 
167
167
  self.dist_type = dist_type
168
168
 
169
- if dist_parms is None or np.array_equal(dist_parms, DIST_PARMS_DEFAULT):
169
+ if dist_parms is None or np.array_equal(dist_parms, DEFAULT_DIST_PARMS):
170
170
  match dist_type:
171
171
  case "Uniform":
172
172
  self.dist_type = "Random"