mergeron 2024.739145.3__py3-none-any.whl → 2024.739145.5__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 CHANGED
@@ -8,7 +8,7 @@ from numpy.typing import NDArray
8
8
 
9
9
  _PKG_NAME: str = Path(__file__).parent.stem
10
10
 
11
- VERSION = "2024.739145.3"
11
+ VERSION = "2024.739145.5"
12
12
 
13
13
  __version__ = VERSION
14
14
 
@@ -30,7 +30,7 @@ type ArrayINT = NDArray[np.intp]
30
30
  type ArrayDouble = NDArray[np.double]
31
31
  type ArrayBIGINT = NDArray[np.int64]
32
32
 
33
- DEFAULT_REC_RATE = 0.85
33
+ DEFAULT_REC_RATIO = 0.85
34
34
 
35
35
 
36
36
  @enum.unique
@@ -6,6 +6,7 @@ with a canvas on which to draw boundaries for Guidelines standards.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ import decimal
9
10
  from dataclasses import dataclass
10
11
  from typing import Literal
11
12
 
@@ -14,13 +15,12 @@ from attrs import Attribute, field, frozen, validators
14
15
  from mpmath import mp, mpf # type: ignore
15
16
 
16
17
  from .. import ( # noqa: TID252
17
- DEFAULT_REC_RATE,
18
+ DEFAULT_REC_RATIO,
18
19
  VERSION,
19
20
  ArrayDouble,
20
21
  RECForm,
21
22
  UPPAggrSelector,
22
23
  )
23
- from . import MPFloat
24
24
  from . import guidelines_boundary_functions as gbfn
25
25
 
26
26
  __version__ = VERSION
@@ -29,7 +29,7 @@ __version__ = VERSION
29
29
  mp.dps = 32
30
30
  mp.trap_complex = True
31
31
 
32
- type HMGPubYear = Literal[1992, 2004, 2010, 2023]
32
+ type HMGPubYear = Literal[1982, 1984, 1992, 2010, 2023]
33
33
 
34
34
 
35
35
  @dataclass(frozen=True)
@@ -50,19 +50,15 @@ class GuidelinesThresholds:
50
50
 
51
51
  ΔHHI, Recapture Ratio, GUPPI, Diversion ratio, CMCR, and IPR thresholds
52
52
  constructed from concentration standards in Guidelines published in
53
- 1992, 2004, 2010, and 2023.
54
-
55
- The 2004 Guidelines refernced here are the EU Commission
56
- guidelines on assessment of horizontal mergers. These
57
- guidelines also define a presumption for mergers with
58
- post-merger HHI in [1000, 2000) and ΔHHI >= 250 points,
59
- whi is not modeled here.
60
-
61
- All other Guidelines modeled here are U.S. merger guidelines.
53
+ 1982, 1984, 1992, 2010, and 2023.
62
54
 
63
55
  """
64
56
 
65
- pub_year: HMGPubYear
57
+ pub_year: HMGPubYear = field(
58
+ kw_only=True,
59
+ default=2023,
60
+ validator=validators.in_([1982, 1984, 1992, 2010, 2023]),
61
+ )
66
62
  """
67
63
  Year of publication of the Guidelines
68
64
  """
@@ -100,9 +96,10 @@ class GuidelinesThresholds:
100
96
  # thus, here, the tentative delta safeharbor under
101
97
  # the 2023 Guidelines is 100 points
102
98
  _hhi_p, _dh_s, _dh_p = {
103
- 1992: (0.18, 0.005, 0.01),
99
+ 1982: (_s1982 := (0.18, 0.005, 0.01)),
100
+ 1984: _s1982,
101
+ 1992: _s1982,
104
102
  2010: (0.25, 0.01, 0.02),
105
- 2004: (0.20, 0.015, 0.025),
106
103
  2023: (0.18, 0.01, 0.01),
107
104
  }[self.pub_year]
108
105
 
@@ -112,52 +109,41 @@ class GuidelinesThresholds:
112
109
  HMGThresholds(
113
110
  _dh_s,
114
111
  _fc := int(np.ceil(1 / _hhi_p)),
115
- _r := gbfn.round_cust(_fc / (_fc + 1), frac=0.05),
116
- _g_s := guppi_from_delta(_dh_s, m_star=1.0, r_bar=_r),
117
- _dr := (1 - _r),
112
+ _r := float(_r_s := gbfn.round_cust(_fc / (_fc + 1), frac=0.05)),
113
+ _g := float(guppi_from_delta(_dh_s, m_star=1.0, r_bar=_r)),
114
+ _dr := float(1 - _r_s),
118
115
  _cmcr := 0.03, # Not strictly a Guidelines standard
119
- _ipr := _g_s, # Not strictly a Guidelines standard
116
+ _ipr := _g, # Not strictly a Guidelines standard
120
117
  ),
121
118
  )
122
119
 
123
120
  object.__setattr__(
124
- self,
125
- "presumption",
126
- HMGThresholds(
127
- _dh_p,
128
- _fc,
129
- _r,
130
- _g_p := guppi_from_delta(_dh_p, m_star=1.0, r_bar=_r),
131
- _dr,
132
- _cmcr,
133
- _ipr := _g_p,
134
- ),
121
+ self, "presumption", HMGThresholds(_dh_p, _fc, _r, _g, _dr, _cmcr, _ipr)
135
122
  )
136
123
 
137
- # imputed_presumption is relevant for 2010 Guidelines
138
- # merger to symmetry in numbers-equivalent of post-merger HHI
124
+ # imputed_presumption is relevant for presumptions implicating
125
+ # mergers *to* symmetry in numbers-equivalent of post-merger HHI
126
+ # as in 2010 U.S.Guidelines
139
127
  object.__setattr__(
140
128
  self,
141
129
  "imputed_presumption",
142
130
  (
143
131
  HMGThresholds(
144
- _dh_i := 2 * (0.5 / _fc) ** 2,
132
+ 2 * (0.5 / _fc) ** 2,
145
133
  _fc,
146
- _r_i := gbfn.round_cust((_fc - 1 / 2) / (_fc + 1 / 2), frac=0.05),
147
- _g_i := guppi_from_delta(_dh_p, m_star=1.0, r_bar=_r_i),
148
- 1 / 2 * (1 - _r_i),
134
+ float(
135
+ _r_i := gbfn.round_cust(
136
+ (_fc - 1 / 2) / (_fc + 1 / 2), frac=0.05
137
+ )
138
+ ),
139
+ _g,
140
+ float((1 - _r_i) / 2),
149
141
  _cmcr,
150
- _g_i,
142
+ _ipr := _g,
151
143
  )
152
- if self.pub_year in (2004, 2010)
144
+ if self.pub_year == 2010
153
145
  else HMGThresholds(
154
- _dh_i := 2 * (1 / (_fc + 1)) ** 2,
155
- _fc,
156
- _r,
157
- _g_i := guppi_from_delta(_dh_p, m_star=1.0, r_bar=_r),
158
- _dr,
159
- _cmcr,
160
- _g_i,
146
+ 2 * (1 / (_fc + 1)) ** 2, _fc, _r, _g, _dr, _cmcr, _ipr
161
147
  )
162
148
  ),
163
149
  )
@@ -169,10 +155,7 @@ class ConcentrationBoundary:
169
155
 
170
156
  measure_name: Literal[
171
157
  "ΔHHI", "Combined share", "Pre-merger HHI", "Post-merger HHI"
172
- ] = field(
173
- kw_only=False,
174
- default="ΔHHI", # pyright: ignore
175
- )
158
+ ] = field(kw_only=False, default="ΔHHI")
176
159
 
177
160
  @measure_name.validator # pyright: ignore
178
161
  def __mnv(
@@ -193,7 +176,7 @@ class ConcentrationBoundary:
193
176
  _instance: ConcentrationBoundary, _attribute: Attribute[float], _value: float, /
194
177
  ) -> None:
195
178
  if not 0 <= _value <= 1:
196
- raise ValueError("Concentration threshold must lie between 0 and 1.") # pyright: ignore
179
+ raise ValueError("Concentration threshold must lie between 0 and 1.")
197
180
 
198
181
  precision: int = field(
199
182
  kw_only=False, default=5, validator=validators.instance_of(int)
@@ -251,7 +234,9 @@ class DiversionRatioBoundary:
251
234
  )
252
235
 
253
236
  recapture_ratio: float = field(
254
- kw_only=False, default=DEFAULT_REC_RATE, validator=validators.instance_of(float)
237
+ kw_only=False,
238
+ default=DEFAULT_REC_RATIO,
239
+ validator=validators.instance_of(float),
255
240
  )
256
241
 
257
242
  recapture_form: RECForm | None = field(kw_only=True, default=RECForm.INOUT)
@@ -337,6 +322,7 @@ class DiversionRatioBoundary:
337
322
  "recapture_form": getattr(self.recapture_form, "value", "inside-out"),
338
323
  "dps": self.precision,
339
324
  }
325
+
340
326
  match self.agg_method:
341
327
  case UPPAggrSelector.DIS:
342
328
  _upp_agg_fn = gbfn.shrratio_boundary_wtd_avg
@@ -380,8 +366,8 @@ def guppi_from_delta(
380
366
  /,
381
367
  *,
382
368
  m_star: float = 1.00,
383
- r_bar: float = DEFAULT_REC_RATE,
384
- ) -> float:
369
+ r_bar: float = DEFAULT_REC_RATIO,
370
+ ) -> decimal.Decimal:
385
371
  """
386
372
  Translate ∆HHI bound to GUPPI bound.
387
373
 
@@ -407,13 +393,13 @@ def guppi_from_delta(
407
393
 
408
394
 
409
395
  def critical_share_ratio(
410
- _guppi_bound: float = 0.075,
396
+ _guppi_bound: float | decimal.Decimal = 0.075,
411
397
  /,
412
398
  *,
413
399
  m_star: float = 1.00,
414
400
  r_bar: float = 1.00,
415
401
  frac: float = 1e-16,
416
- ) -> MPFloat:
402
+ ) -> decimal.Decimal:
417
403
  """
418
404
  Corollary to GUPPI bound.
419
405
 
@@ -438,12 +424,12 @@ def critical_share_ratio(
438
424
 
439
425
 
440
426
  def share_from_guppi(
441
- _guppi_bound: float = 0.065,
427
+ _guppi_bound: float | decimal.Decimal = 0.065,
442
428
  /,
443
429
  *,
444
430
  m_star: float = 1.00,
445
- r_bar: float = DEFAULT_REC_RATE,
446
- ) -> float:
431
+ r_bar: float = DEFAULT_REC_RATIO,
432
+ ) -> decimal.Decimal:
447
433
  """
448
434
  Symmetric-firm share for given GUPPI, margin, and recapture ratio.
449
435
 
@@ -5,7 +5,7 @@ from typing import Any, Literal, TypedDict
5
5
  import numpy as np
6
6
  from mpmath import mp, mpf # type: ignore
7
7
 
8
- from .. import DEFAULT_REC_RATE, VERSION, ArrayBIGINT, ArrayDouble # noqa: TID252
8
+ from .. import DEFAULT_REC_RATIO, VERSION, ArrayBIGINT, ArrayDouble # noqa: TID252
9
9
  from . import MPFloat
10
10
 
11
11
  __version__ = VERSION
@@ -34,7 +34,7 @@ class GuidelinesBoundary:
34
34
  """Area under the boundary."""
35
35
 
36
36
 
37
- def dh_area(_dh_val: float | MPFloat = 0.01, /, *, dps: int = 9) -> float:
37
+ def dh_area(_delta_bound: float | MPFloat = 0.01, /, *, dps: int = 9) -> float:
38
38
  R"""
39
39
  Area under the ΔHHI boundary.
40
40
 
@@ -55,7 +55,7 @@ def dh_area(_dh_val: float | MPFloat = 0.01, /, *, dps: int = 9) -> float:
55
55
 
56
56
  Parameters
57
57
  ----------
58
- _dh_val
58
+ _delta_bound
59
59
  Change in concentration.
60
60
  dps
61
61
  Specified precision in decimal places.
@@ -66,22 +66,26 @@ def dh_area(_dh_val: float | MPFloat = 0.01, /, *, dps: int = 9) -> float:
66
66
 
67
67
  """
68
68
 
69
- _dh_val = mpf(f"{_dh_val}")
70
- _s_naught = (1 - mp.sqrt(1 - 2 * _dh_val)) / 2
69
+ _delta_bound = mpf(f"{_delta_bound}")
70
+ _s_naught = (1 - mp.sqrt(1 - 2 * _delta_bound)) / 2
71
71
 
72
72
  return round(
73
- float(_s_naught + (_dh_val / 2) * (mp.ln(1 - _s_naught) - mp.ln(_s_naught))),
73
+ float(
74
+ _s_naught + (_delta_bound / 2) * (mp.ln(1 - _s_naught) - mp.ln(_s_naught))
75
+ ),
74
76
  dps,
75
77
  )
76
78
 
77
79
 
78
- def hhi_delta_boundary(_dh_val: float = 0.01, /, *, dps: int = 5) -> GuidelinesBoundary:
80
+ def hhi_delta_boundary(
81
+ _delta_bound: float | decimal.Decimal | MPFloat = 0.01, /, *, dps: int = 5
82
+ ) -> GuidelinesBoundary:
79
83
  """
80
84
  Generate the list of share combination on the ΔHHI boundary.
81
85
 
82
86
  Parameters
83
87
  ----------
84
- _dh_val:
88
+ _delta_bound:
85
89
  Merging-firms' ΔHHI bound.
86
90
  dps
87
91
  Number of decimal places for rounding reported shares.
@@ -92,33 +96,32 @@ def hhi_delta_boundary(_dh_val: float = 0.01, /, *, dps: int = 5) -> GuidelinesB
92
96
 
93
97
  """
94
98
 
95
- _dh_val = mpf(f"{_dh_val}")
96
- _s_naught = 1 / 2 * (1 - mp.sqrt(1 - 2 * _dh_val))
97
- _s_mid = mp.sqrt(_dh_val / 2)
99
+ _delta_bound = mpf(f"{_delta_bound}")
100
+ _s_naught = 1 / 2 * (1 - mp.sqrt(1 - 2 * _delta_bound))
101
+ _s_mid = mp.sqrt(_delta_bound / 2)
98
102
 
99
103
  _dh_step_sz = mp.power(10, -6)
100
104
  _s_1 = np.array(mp.arange(_s_mid, _s_naught - mp.eps, -_dh_step_sz))
101
- _s_2 = _dh_val / (2 * _s_1)
102
105
 
103
106
  # Boundary points
104
107
  _dh_half = np.vstack((
105
- np.column_stack((_s_1, _s_2)).astype(np.float64),
108
+ np.column_stack((_s_1, _delta_bound / (2 * _s_1))).astype(np.float64),
106
109
  np.array([(mpf("0.0"), mpf("1.0"))], np.float64),
107
110
  ))
108
111
  _dh_bdry_pts = np.vstack((_dh_half[::-1], _dh_half[1:, ::-1]))
109
112
 
110
- return GuidelinesBoundary(_dh_bdry_pts, dh_area(_dh_val, dps=dps))
113
+ return GuidelinesBoundary(_dh_bdry_pts, dh_area(_delta_bound, dps=dps))
111
114
 
112
115
 
113
116
  def hhi_pre_contrib_boundary(
114
- _hhi_contrib: float = 0.03125, /, *, dps: int = 5
117
+ _hhi_bound: float | decimal.Decimal | MPFloat = 0.03125, /, *, dps: int = 5
115
118
  ) -> GuidelinesBoundary:
116
119
  """
117
120
  Share combinations on the premerger HHI contribution boundary.
118
121
 
119
122
  Parameters
120
123
  ----------
121
- _hhi_contrib:
124
+ _hhi_bound:
122
125
  Merging-firms' pre-merger HHI contribution bound.
123
126
  dps
124
127
  Number of decimal places for rounding reported shares.
@@ -128,23 +131,23 @@ def hhi_pre_contrib_boundary(
128
131
  Array of share-pairs, area under boundary.
129
132
 
130
133
  """
131
- _hhi_contrib = mpf(f"{_hhi_contrib}")
132
- _s_mid = mp.sqrt(_hhi_contrib / 2)
134
+ _hhi_bound = mpf(f"{_hhi_bound}")
135
+ _s_mid = mp.sqrt(_hhi_bound / 2)
133
136
 
134
137
  _bdry_step_sz = mp.power(10, -dps)
135
138
  # Range-limit is 0 less a step, which is -1 * step-size
136
139
  _s_1 = np.array(mp.arange(_s_mid, -_bdry_step_sz, -_bdry_step_sz))
137
- _s_2 = np.sqrt(_hhi_contrib - _s_1**2)
140
+ _s_2 = np.sqrt(_hhi_bound - _s_1**2)
138
141
  _bdry_pts_mid = np.column_stack((_s_1, _s_2)).astype(np.float64)
139
142
 
140
143
  return GuidelinesBoundary(
141
144
  np.vstack((_bdry_pts_mid[::-1], _bdry_pts_mid[1:, ::-1])),
142
- round(float(mp.pi * _hhi_contrib / 4), dps),
145
+ round(float(mp.pi * _hhi_bound / 4), dps),
143
146
  )
144
147
 
145
148
 
146
149
  def combined_share_boundary(
147
- _s_intcpt: float = 0.0625, /, *, dps: int = 10
150
+ _s_intcpt: float | decimal.Decimal | MPFloat = 0.0625, /, *, dps: int = 10
148
151
  ) -> GuidelinesBoundary:
149
152
  """
150
153
  Share combinations on the merging-firms' combined share boundary.
@@ -168,18 +171,14 @@ def combined_share_boundary(
168
171
  _s_intcpt = mpf(f"{_s_intcpt}")
169
172
  _s_mid = _s_intcpt / 2
170
173
 
171
- _s1_pts = (0, _s_mid, _s_intcpt)
174
+ _s1_pts = np.array([0, _s_mid, _s_intcpt], np.float64)
172
175
  return GuidelinesBoundary(
173
- np.column_stack((
174
- np.array(_s1_pts, np.float64),
175
- np.array(_s1_pts[::-1], np.float64),
176
- )),
177
- round(float(_s_intcpt * _s_mid), dps),
176
+ np.column_stack((_s1_pts, _s1_pts[::-1])), round(float(_s_intcpt * _s_mid), dps)
178
177
  )
179
178
 
180
179
 
181
180
  def hhi_post_contrib_boundary(
182
- _hhi_contrib: float = 0.800, /, *, dps: int = 10
181
+ _hhi_bound: float | decimal.Decimal | MPFloat = 0.800, /, *, dps: int = 10
183
182
  ) -> GuidelinesBoundary:
184
183
  """
185
184
  Share combinations on the postmerger HHI contribution boundary.
@@ -189,7 +188,7 @@ def hhi_post_contrib_boundary(
189
188
 
190
189
  Parameters
191
190
  ----------
192
- _hhi_contrib:
191
+ _hhi_bound:
193
192
  Merging-firms' pre-merger HHI contribution bound.
194
193
  dps
195
194
  Number of decimal places for rounding reported shares.
@@ -199,12 +198,17 @@ def hhi_post_contrib_boundary(
199
198
  Array of share-pairs, area under boundary.
200
199
 
201
200
  """
202
- return combined_share_boundary(np.sqrt(_hhi_contrib), dps=dps)
201
+ return combined_share_boundary(
202
+ _hhi_bound.sqrt()
203
+ if isinstance(_hhi_bound, decimal.Decimal | mpf)
204
+ else np.sqrt(_hhi_bound),
205
+ dps=dps,
206
+ )
203
207
 
204
208
 
205
209
  def shrratio_boundary_wtd_avg(
206
- _delta_star: float = 0.075,
207
- _r_val: float = DEFAULT_REC_RATE,
210
+ _delta_star: float | decimal.Decimal | MPFloat = 0.075,
211
+ _r_val: float = DEFAULT_REC_RATIO,
208
212
  /,
209
213
  *,
210
214
  agg_method: Literal[
@@ -305,7 +309,7 @@ def shrratio_boundary_wtd_avg(
305
309
  _s_mid = mp.fdiv(_delta_star, 1 + _delta_star)
306
310
 
307
311
  # initial conditions
308
- _gbdry_points: list[tuple[MPFloat, MPFloat]] | ArrayDouble = [(_s_mid, _s_mid)]
312
+ _gbdry_points = [(_s_mid, _s_mid)]
309
313
  _s_1_pre, _s_2_pre = _s_mid, _s_mid
310
314
  _s_2_oddval, _s_2_oddsum, _s_2_evnsum = True, 0.0, 0.0
311
315
 
@@ -401,18 +405,18 @@ def shrratio_boundary_wtd_avg(
401
405
  _gbdry_area_total = float(2 * _gbd_prtlarea - mp.power(_s_mid, "2"))
402
406
 
403
407
  _gbdry_points.append((mpf("0.0"), _s_intcpt))
404
- _gbdry_points = np.array(_gbdry_points).astype(np.float64)
408
+ _gbdry_array = np.array(_gbdry_points).astype(np.float64)
405
409
 
406
410
  # Points defining boundary to point-of-symmetry
407
411
  return GuidelinesBoundary(
408
- np.vstack((_gbdry_points[::-1], _gbdry_points[1:, ::-1])),
412
+ np.vstack((_gbdry_array[::-1], _gbdry_array[1:, ::-1])),
409
413
  round(float(_gbdry_area_total), dps),
410
414
  )
411
415
 
412
416
 
413
417
  def shrratio_boundary_xact_avg(
414
- _delta_star: float = 0.075,
415
- _r_val: float = DEFAULT_REC_RATE,
418
+ _delta_star: float | decimal.Decimal | MPFloat = 0.075,
419
+ _r_val: float = DEFAULT_REC_RATIO,
416
420
  /,
417
421
  *,
418
422
  recapture_form: Literal["inside-out", "proportional"] = "inside-out",
@@ -566,8 +570,8 @@ def shrratio_boundary_xact_avg(
566
570
 
567
571
 
568
572
  def shrratio_boundary_xact_avg_mp(
569
- _delta_star: float = 0.075,
570
- _r_val: float = DEFAULT_REC_RATE,
573
+ _delta_star: float | decimal.Decimal | MPFloat = 0.075,
574
+ _r_val: float = DEFAULT_REC_RATIO,
571
575
  /,
572
576
  *,
573
577
  recapture_form: Literal["inside-out", "proportional"] = "inside-out",
@@ -721,8 +725,8 @@ def shrratio_boundary_xact_avg_mp(
721
725
 
722
726
 
723
727
  def shrratio_boundary_min(
724
- _delta_star: float = 0.075,
725
- _r_val: float = DEFAULT_REC_RATE,
728
+ _delta_star: float | decimal.Decimal | MPFloat = 0.075,
729
+ _r_val: float = DEFAULT_REC_RATIO,
726
730
  /,
727
731
  *,
728
732
  recapture_form: str = "inside-out",
@@ -788,7 +792,11 @@ def shrratio_boundary_min(
788
792
 
789
793
 
790
794
  def shrratio_boundary_max(
791
- _delta_star: float = 0.075, _r_val: float = DEFAULT_REC_RATE, /, *, dps: int = 10
795
+ _delta_star: float | decimal.Decimal | MPFloat = 0.075,
796
+ _r_val: float = DEFAULT_REC_RATIO,
797
+ /,
798
+ *,
799
+ dps: int = 10,
792
800
  ) -> GuidelinesBoundary:
793
801
  """
794
802
  Share combinations on the minimum GUPPI boundary with symmetric
@@ -851,7 +859,9 @@ def _shrratio_boundary_intcpt(
851
859
  ),
852
860
  2 * mpf(f"{_r_val}"),
853
861
  )
854
- case None if agg_method == "arithmetic mean" and recapture_form == "proportional":
862
+ case None if (
863
+ agg_method == "arithmetic mean" and recapture_form == "proportional"
864
+ ):
855
865
  _s_intcpt = mp.fsub(_delta_star + 1 / 2, mp.fabs(_delta_star - 1 / 2))
856
866
  case _:
857
867
  _s_intcpt = _s_2_pre
@@ -859,12 +869,9 @@ def _shrratio_boundary_intcpt(
859
869
  return _s_intcpt
860
870
 
861
871
 
862
- def lerp(
863
- _x1: int | float | MPFloat | ArrayDouble | ArrayBIGINT = 3,
864
- _x2: int | float | MPFloat | ArrayDouble | ArrayBIGINT = 1,
865
- _r: float | MPFloat = 0.25,
866
- /,
867
- ) -> float | MPFloat | ArrayDouble:
872
+ def lerp[LerpT: (float, MPFloat, ArrayDouble, ArrayBIGINT)](
873
+ _x1: LerpT, _x2: LerpT, _r: float = 0.25, /
874
+ ) -> LerpT:
868
875
  """
869
876
  From the function of the same name in the C++ standard [2]_
870
877
 
@@ -901,19 +908,17 @@ def lerp(
901
908
  return _x1
902
909
  elif _r == 1:
903
910
  return _x2
904
- elif _r == 0.5:
905
- return 1 / 2 * (_x1 + _x2)
906
911
  else:
907
- return _r * _x2 + (1 - _r) * _x1
912
+ return _r * _x2 + (1 - _r) * _x1 # pyright: ignore
908
913
 
909
914
 
910
915
  def round_cust(
911
- _num: float = 0.060215,
916
+ _num: float | decimal.Decimal | MPFloat = 0.060215,
912
917
  /,
913
918
  *,
914
919
  frac: float = 0.005,
915
920
  rounding_mode: str = "ROUND_HALF_UP",
916
- ) -> float:
921
+ ) -> decimal.Decimal:
917
922
  """
918
923
  Custom rounding, to the nearest 0.5% by default.
919
924
 
@@ -955,12 +960,12 @@ def round_cust(
955
960
  ):
956
961
  raise ValueError(
957
962
  f"Value, {f'"{rounding_mode}"'} is invalid for rounding_mode."
958
- "Documentation for the, \"decimal\" built-in lists valid rounding modes."
963
+ 'Documentation for the, "decimal" built-in lists valid rounding modes.'
959
964
  )
960
965
 
961
966
  _n, _f, _e = (decimal.Decimal(f"{_g}") for _g in [_num, frac, 1])
962
967
 
963
- return float(_f * (_n / _f).quantize(_e, rounding=rounding_mode))
968
+ return _f * (_n / _f).quantize(_e, rounding=rounding_mode)
964
969
 
965
970
 
966
971
  def boundary_plot(*, mktshares_plot_flag: bool = True) -> tuple[Any, ...]:
@@ -16,7 +16,7 @@ from mpmath import mp, mpf # type: ignore
16
16
  from scipy.spatial.distance import minkowski as distance_function # type: ignore
17
17
  from sympy import lambdify, simplify, solve, symbols # type: ignore
18
18
 
19
- from .. import DEFAULT_REC_RATE, VERSION, ArrayDouble # noqa: TID252
19
+ from .. import DEFAULT_REC_RATIO, VERSION, ArrayDouble # noqa: TID252
20
20
  from . import guidelines_boundary_functions as gbfn
21
21
 
22
22
  __version__ = VERSION
@@ -101,7 +101,7 @@ def hhi_delta_boundary_qdtr(_dh_val: float = 0.01, /) -> GuidelinesBoundaryCalla
101
101
 
102
102
  def shrratio_boundary_qdtr_wtd_avg(
103
103
  _delta_star: float = 0.075,
104
- _r_val: float = DEFAULT_REC_RATE,
104
+ _r_val: float = DEFAULT_REC_RATIO,
105
105
  /,
106
106
  *,
107
107
  weighting: Literal["own-share", "cross-product-share"] | None = "own-share",
@@ -220,7 +220,7 @@ def shrratio_boundary_qdtr_wtd_avg(
220
220
 
221
221
  def shrratio_boundary_distance(
222
222
  _delta_star: float = 0.075,
223
- _r_val: float = DEFAULT_REC_RATE,
223
+ _r_val: float = DEFAULT_REC_RATIO,
224
224
  /,
225
225
  *,
226
226
  agg_method: Literal["arithmetic mean", "distance"] = "arithmetic mean",
mergeron/gen/__init__.py CHANGED
@@ -15,7 +15,7 @@ from attrs import Attribute, cmp_using, field, frozen, validators
15
15
  from numpy.random import SeedSequence
16
16
 
17
17
  from .. import ( # noqa: TID252
18
- DEFAULT_REC_RATE,
18
+ DEFAULT_REC_RATIO,
19
19
  VERSION,
20
20
  ArrayBIGINT,
21
21
  ArrayBoolean,
@@ -183,7 +183,7 @@ class ShareSpec:
183
183
  recapture_form: RECForm = field(default=RECForm.INOUT)
184
184
  """See :class:`mergeron.RECForm`"""
185
185
 
186
- recapture_ratio: float | None = field(default=DEFAULT_REC_RATE)
186
+ recapture_ratio: float | None = field(default=DEFAULT_REC_RATIO)
187
187
  """A value between 0 and 1.
188
188
 
189
189
  :code:`None` if market share specification requires direct generation of
@@ -194,8 +194,7 @@ class ShareSpec:
194
194
  in published merger guidelines. Accordingly, the recapture ratio rounded to
195
195
  the nearest 5% is:
196
196
 
197
- * 0.85, **7-to-6 merger from symmetry**; US Guidelines, 1992, 2023
198
- * 0.80, **6-to-5 merger to symmetry**; EU Guidelines for horizontal mergers, 2004
197
+ * 0.85, **7-to-6 merger from symmetry**; US Guidelines, 1982, 1984, 1992, 2023
199
198
  * 0.80, 5-to-4 merger from symmetry
200
199
  * 0.80, **5-to-4 merger to symmetry**; US Guidelines, 2010
201
200
 
@@ -13,7 +13,7 @@ from attrs import Attribute, define, field, validators
13
13
  from joblib import Parallel, cpu_count, delayed # type: ignore
14
14
  from numpy.random import SeedSequence
15
15
 
16
- from .. import DEFAULT_REC_RATE, VERSION, RECForm # noqa: TID252 # noqa
16
+ from .. import DEFAULT_REC_RATIO, VERSION, RECForm # noqa: TID252 # noqa
17
17
  from ..core import guidelines_boundaries as gbl # noqa: TID252
18
18
  from ..core.guidelines_boundaries import HMGThresholds # noqa: TID252
19
19
  from . import (
@@ -74,7 +74,7 @@ class MarketSample:
74
74
  share_spec: ShareSpec = field(
75
75
  kw_only=True,
76
76
  default=ShareSpec(
77
- SHRDistribution.UNI, None, None, RECForm.INOUT, DEFAULT_REC_RATE
77
+ SHRDistribution.UNI, None, None, RECForm.INOUT, DEFAULT_REC_RATIO
78
78
  ),
79
79
  validator=validators.instance_of(ShareSpec),
80
80
  )
@@ -11,7 +11,7 @@ import numpy as np
11
11
  from attrs import evolve
12
12
  from numpy.random import SeedSequence
13
13
 
14
- from .. import DEFAULT_REC_RATE, VERSION, ArrayDouble, RECForm # noqa: TID252
14
+ from .. import DEFAULT_REC_RATIO, VERSION, ArrayDouble, RECForm # noqa: TID252
15
15
  from ..core.empirical_margin_distribution import mgn_data_resampler # noqa: TID252
16
16
  from ..core.pseudorandom_numbers import ( # noqa: TID252
17
17
  DEFAULT_DIST_PARMS,
@@ -100,7 +100,7 @@ def gen_share_data(
100
100
 
101
101
  # If recapture_form == "inside-out", recalculate _aggregate_purchase_prob
102
102
  _frmshr_array = _mkt_share_sample.mktshr_array[:, :2]
103
- _r_bar = _share_spec.recapture_ratio or DEFAULT_REC_RATE
103
+ _r_bar = _share_spec.recapture_ratio or DEFAULT_REC_RATIO
104
104
  if _recapture_form == RECForm.INOUT:
105
105
  _mkt_share_sample = ShareDataSample(
106
106
  _mkt_share_sample.mktshr_array,
@@ -266,7 +266,7 @@ def gen_market_shares_dirichlet_multimarket(
266
266
  else:
267
267
 
268
268
  def _gen_dir_alphas(_fcv: int) -> ArrayDouble:
269
- return np.array(_dir_alphas_full[:_fcv], dtype=np.float64) # type: ignore
269
+ return np.array(_dir_alphas_full[:_fcv], dtype=np.float64)
270
270
 
271
271
  _fcounts = prng(_fcount_rng_seed_seq).choice(
272
272
  _fcount_keys, size=(_s_size, 1), p=_choice_wts
@@ -604,8 +604,7 @@ def gen_margin_price_data(
604
604
  del _price_array_here
605
605
  case _:
606
606
  raise ValueError(
607
- f"Specitication of price distribution"
608
- f' "{_price_spec.value}" is invalid.'
607
+ f'Specification of price distribution, "{_price_spec.value}" is invalid.'
609
608
  )
610
609
  if _price_spec != PriceSpec.CSY:
611
610
  _margin_data = _gen_margin_data(
mergeron/gen/upp_tests.py CHANGED
@@ -373,7 +373,7 @@ def save_array_to_hdf5(
373
373
  *,
374
374
  saved_array_name_suffix: str | None = None,
375
375
  ) -> None:
376
- _h5_array_name = f"{_array_name}_{saved_array_name_suffix or ""}".rstrip("_")
376
+ _h5_array_name = f"{_array_name}_{saved_array_name_suffix or ''}".rstrip("_")
377
377
 
378
378
  with suppress(ptb.NoSuchNodeError):
379
379
  _h5_file.remove_node(_h5_group, name=_array_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mergeron
3
- Version: 2024.739145.3
3
+ Version: 2024.739145.5
4
4
  Summary: Merger Policy Analysis using Python
5
5
  License: MIT
6
6
  Keywords: merger policy analysis,merger guidelines,merger screening,policy presumptions,concentration standards,upward pricing pressure,GUPPI
@@ -16,6 +16,7 @@ Classifier: Operating System :: OS Independent
16
16
  Classifier: Programming Language :: Python
17
17
  Classifier: Programming Language :: Python :: 3
18
18
  Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
19
20
  Classifier: Programming Language :: Python :: 3 :: Only
20
21
  Classifier: Programming Language :: Python :: Implementation :: CPython
21
22
  Requires-Dist: aenum (>=3.1.15,<4.0.0)
@@ -1,11 +1,10 @@
1
- mergeron/License.txt,sha256=7iX-y0EyjkbVJKJLS4ZKzuuE1wd0lryfsD_IytLG8lQ,1246
2
- mergeron/__init__.py,sha256=ZEg7CbRUEZAhsZG0G_wV-Hodno70_tZh9RN1hZ5sO6Q,1476
1
+ mergeron/__init__.py,sha256=AC6G15BvvMrueNoem4otWbhncZEtc8FnLfDcm2LoNOE,1477
3
2
  mergeron/core/__init__.py,sha256=jPGd0okmvNOdWnTu4biR4hqnL29IERaY4Olv8mS02ko,188
4
3
  mergeron/core/empirical_margin_distribution.py,sha256=iU72c6rPwqduH8GlvES1na2uvw5qXq0IQfsTWnL_ueQ,8726
5
4
  mergeron/core/ftc_merger_investigations_data.py,sha256=_Qno1_oWcHmDd60j8YX6BLUSLeAn-DU6KpvMOcbCIaE,28728
6
- mergeron/core/guidelines_boundaries.py,sha256=sFC4kRjH4ndINluwxBBftBWcn5g4Vfq2ezhzzbpnlGE,15765
7
- mergeron/core/guidelines_boundary_functions.py,sha256=6Kiugn8w-byaBvow5b4kJJtA6SuXO-oOkCrRUtD06zQ,34626
8
- mergeron/core/guidelines_boundary_functions_extra.py,sha256=AZKkLPjiMtBaQIKj1bFs5xgV9xSntlHkf-pc7j4OkVk,11289
5
+ mergeron/core/guidelines_boundaries.py,sha256=uKRIwTrGXKf8CbabjjqRcMO4wGvtAUrd2MrMICzgNvg,15336
6
+ mergeron/core/guidelines_boundary_functions.py,sha256=SoTamDsKrThqDfoNTHeGp2ntiwhzscWmkAbIWrBtUq4,34885
7
+ mergeron/core/guidelines_boundary_functions_extra.py,sha256=ytTWxYk7FkGLQubkQXrniwP_2ZlYssp4rmOxy4_7480,11292
9
8
  mergeron/core/pseudorandom_numbers.py,sha256=ps5H3n7jC5iJq_ulrmGvTAFmMeNXq-7IPWQQog7q5TY,9225
10
9
  mergeron/data/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
11
10
  mergeron/data/damodaran_margin_data.xls,sha256=Qggl1p5nkOMJI8YUXhkwXQRz-OhRSqBTzz57N0JQyYA,79360
@@ -13,12 +12,12 @@ mergeron/data/damodaran_margin_data_dict.msgpack,sha256=sr6s4L69kposEpzGI7jpPb4U
13
12
  mergeron/data/ftc_invdata.msgpack,sha256=WBFHgi7Ld4R-h2zL2Zc3TOIlKqVrbVFMH1LoI4-T-M0,264664
14
13
  mergeron/demo/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
15
14
  mergeron/demo/visualize_empirical_margin_distribution.py,sha256=_1SWKqFJNqKV_yA3v2tmzl8Th3CC3SXpb6VGiwGGuN0,2373
16
- mergeron/gen/__init__.py,sha256=hrOACw-loPDXiPTP-5wjpu7cW6T5ade6eVW-CtNGEXg,17287
17
- mergeron/gen/data_generation.py,sha256=wyrSfoDf3F5RVAqfzOv27R9x97_4Ciz6OmXH_w8PHbA,16870
18
- mergeron/gen/data_generation_functions.py,sha256=Lr9co1qylkmAyu8OPUVwYpE3KvxU-97glqmJ04E-LTA,28977
15
+ mergeron/gen/__init__.py,sha256=6A1HVewEEwLo4JtZZ61ShzhU2phEeNfTxmTPlpi5LXY,17215
16
+ mergeron/gen/data_generation.py,sha256=nzCWVJBXYxloR6J6MamFM0MUbDzguhARCAEksYkX1Dw,16872
17
+ mergeron/gen/data_generation_functions.py,sha256=QmM89KzDP-8hz4ibjWDiEn_KVulgUN_be19j-P9LdWU,28944
19
18
  mergeron/gen/enforcement_stats.py,sha256=ZjrV_VkFMF0D1myc-fj-W99M1EhJMA9-nCfyE5g9e54,10890
20
- mergeron/gen/upp_tests.py,sha256=VWxGVi6DQrGxcQsaNtXNB2qDu-WYm9DuY851fHW3j-o,12548
19
+ mergeron/gen/upp_tests.py,sha256=vv9gBHQzabYxgcOBofTPHuNael8SbUAMfNW9c2H2C84,12548
21
20
  mergeron/py.typed,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
22
- mergeron-2024.739145.3.dist-info/METADATA,sha256=16hzR2LygxlFSoEAat6HJgiTthxbYhzsKBxHAtKtZN8,14432
23
- mergeron-2024.739145.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
24
- mergeron-2024.739145.3.dist-info/RECORD,,
21
+ mergeron-2024.739145.5.dist-info/METADATA,sha256=_Ywnp2xKUSmbtRB4pTG3N4VrHaKOXSI-9lKU0gIB4HE,14483
22
+ mergeron-2024.739145.5.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
23
+ mergeron-2024.739145.5.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 1.9.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
mergeron/License.txt DELETED
@@ -1,16 +0,0 @@
1
- mergeron
2
- ========
3
-
4
- Copyright 2017-2024 S. Murthy Kambhampaty
5
-
6
- MIT License
7
- -----------
8
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
-
12
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13
-
14
- Exceptions
15
- ----------
16
- Modules provided in the mergeron.ext subpackage are redistributed under the license published within each module.