mergeron 2025.739439.11__py3-none-any.whl → 2025.739439.13__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
@@ -15,7 +15,7 @@ from ruamel import yaml
15
15
 
16
16
  _PKG_NAME: str = Path(__file__).parent.name
17
17
 
18
- VERSION = "2025.739439.11"
18
+ VERSION = "2025.739439.13"
19
19
 
20
20
  __version__ = VERSION
21
21
 
@@ -30,7 +30,7 @@ created/reused.
30
30
  if not WORK_DIR.is_dir():
31
31
  WORK_DIR.mkdir(parents=False)
32
32
 
33
- DEFAULT_REC_RATIO = 0.85
33
+ DEFAULT_REC = 0.85
34
34
 
35
35
  EMPTY_ARRAYDOUBLE = np.array([], float)
36
36
  EMPTY_ARRAYINT = np.array([], int)
@@ -172,19 +172,19 @@ class Enameled(enum.Enum):
172
172
  @this_yaml.register_class
173
173
  @enum.unique
174
174
  class RECForm(str, Enameled):
175
- R"""For derivation of recapture ratio from market shares.
175
+ R"""For derivation of recapture rate from market shares.
176
176
 
177
177
  With :math:`\mathscr{N}` a set of firms, each supplying a
178
178
  single differentiated product, and :math:`\mathscr{M} \subset \mathscr{N}`
179
179
  a putative relevant product market, with
180
180
  :math:`d_{ij}` denoting diversion ratio from good :math:`i` to good :math:`j`,
181
181
  :math:`s_i` denoting market shares, and
182
- :math:`\overline{r}` the default market recapture ratio,
183
- market recapture ratios for the respective products may be specified
182
+ :math:`\overline{r}` the default market recapture rate,
183
+ market recapture rates for the respective products may be specified
184
184
  as having one of the following forms:
185
185
  """
186
186
 
187
- FIXED = "proportional"
187
+ FIXED = "fixed"
188
188
  R"""Given, :math:`\overline{r}`,
189
189
 
190
190
  .. math::
@@ -16,7 +16,7 @@ from attrs import Attribute, field, frozen, validators
16
16
  from mpmath import mp # type: ignore
17
17
 
18
18
  from .. import ( # noqa: TID252
19
- DEFAULT_REC_RATIO,
19
+ DEFAULT_REC,
20
20
  VERSION,
21
21
  ArrayDouble,
22
22
  HMGPubYear,
@@ -53,7 +53,7 @@ class GuidelinesThresholds:
53
53
  """
54
54
  Guidelines thresholds by Guidelines publication year.
55
55
 
56
- ΔHHI, Recapture Ratio, GUPPI, Diversion ratio, CMCR, and IPR thresholds
56
+ ΔHHI, Recapture Rate, GUPPI, Diversion ratio, CMCR, and IPR thresholds
57
57
  constructed from concentration standards in Guidelines published in
58
58
  1992, 2010, and 2023.
59
59
  """
@@ -68,7 +68,7 @@ class GuidelinesThresholds:
68
68
  """
69
69
  Negative presumption quantified on various measures.
70
70
 
71
- ΔHHI safeharbor bound, default recapture ratio, GUPPI bound,
71
+ ΔHHI safeharbor bound, default recapture rate, GUPPI bound,
72
72
  diversion ratio limit, CMCR, and IPR.
73
73
  """
74
74
 
@@ -76,7 +76,7 @@ class GuidelinesThresholds:
76
76
  """
77
77
  Presumption of harm defined in HMG.
78
78
 
79
- ΔHHI bound and corresponding default recapture ratio, GUPPI bound,
79
+ ΔHHI bound and corresponding default recapture rate, GUPPI bound,
80
80
  diversion ratio limit, CMCR, and IPR.
81
81
  """
82
82
 
@@ -85,7 +85,7 @@ class GuidelinesThresholds:
85
85
  Presumption of harm imputed from Guidelines.
86
86
 
87
87
  ΔHHI bound inferred from strict numbers-equivalent
88
- of (post-merger) HHI presumption, and corresponding default recapture ratio,
88
+ of (post-merger) HHI presumption, and corresponding default recapture rate,
89
89
  GUPPI bound, diversion ratio limit, CMCR, and IPR.
90
90
  """
91
91
 
@@ -208,13 +208,13 @@ class ConcentrationBoundary:
208
208
 
209
209
 
210
210
  @frozen
211
- class DiversionRatioBoundary:
211
+ class DiversionBoundary:
212
212
  """
213
213
  Diversion ratio specification, boundary coordinates, and area under boundary.
214
214
 
215
- Along with the default diversion ratio and recapture ratio,
215
+ Along with the default diversion ratio and recapture rate,
216
216
  a diversion ratio boundary specification includes the recapture form --
217
- whether fixed for both merging firms' products ("proportional") or
217
+ whether fixed for both merging firms' products ("fixed") or
218
218
  consistent with share-proportionality, i.e., "inside-out";
219
219
  the method of aggregating diversion ratios for the two products, and
220
220
  the precision for the estimate of area under the divertion ratio boundary
@@ -226,31 +226,26 @@ class DiversionRatioBoundary:
226
226
 
227
227
  @diversion_ratio.validator
228
228
  def _dvv(
229
- _instance: DiversionRatioBoundary,
230
- _attribute: Attribute[float],
231
- _value: float,
232
- /,
229
+ _instance: DiversionBoundary, _attribute: Attribute[float], _value: float, /
233
230
  ) -> None:
234
231
  if not (isinstance(_value, decimal.Decimal | float) and 0 <= _value <= 1):
235
232
  raise ValueError(
236
233
  "Margin-adjusted benchmark diversion share must lie between 0 and 1."
237
234
  )
238
235
 
239
- recapture_ratio: float = field(
240
- kw_only=False,
241
- default=DEFAULT_REC_RATIO,
242
- validator=validators.instance_of(float),
236
+ recapture_rate: float = field(
237
+ kw_only=False, default=DEFAULT_REC, validator=validators.instance_of(float)
243
238
  )
244
239
 
245
240
  recapture_form: RECForm | None = field(kw_only=True, default=RECForm.INOUT)
246
241
  R"""
247
- The form of the recapture ratio.
242
+ The form of the recapture rate.
248
243
 
249
- When :attr:`mergeron.RECForm.INOUT`, the recapture ratio for
244
+ When :attr:`mergeron.RECForm.INOUT`, the recapture rate for
250
245
  he product having the smaller market-share is assumed to equal the default,
251
- and the recapture ratio for the product with the larger market-share is
252
- computed assuming MNL demand. Fixed recapture ratios are specified as
253
- :attr:`mergeron.RECForm.FIXED`. (To specify that recapture ratios be
246
+ and the recapture rate for the product with the larger market-share is
247
+ computed assuming MNL demand. Fixed recapture rates are specified as
248
+ :attr:`mergeron.RECForm.FIXED`. (To specify that recapture rates be
254
249
  constructed from the generated purchase-probabilities for products in
255
250
  the market and for the outside good, specify :attr:`mergeron.RECForm.OUTIN`.)
256
251
 
@@ -270,19 +265,16 @@ class DiversionRatioBoundary:
270
265
 
271
266
  @recapture_form.validator
272
267
  def _rsv(
273
- _instance: DiversionRatioBoundary,
274
- _attribute: Attribute[RECForm],
275
- _value: RECForm,
276
- /,
268
+ _instance: DiversionBoundary, _attribute: Attribute[RECForm], _value: RECForm, /
277
269
  ) -> None:
278
270
  if _value and not (isinstance(_value, RECForm)):
279
271
  raise ValueError(f"Invalid recapture specification, {_value!r}.")
280
- if _value == RECForm.OUTIN and _instance.recapture_ratio:
272
+ if _value == RECForm.OUTIN and _instance.recapture_rate:
281
273
  raise ValueError(
282
274
  f"Invalid recapture specification, {_value!r}. "
283
275
  "You may consider specifying `mergeron.RECForm.INOUT` here, and "
284
- 'assigning the default recapture ratio as attribute, "recapture_ratio" of '
285
- "this `DiversionRatioBoundarySpec` object."
276
+ 'assigning the default recapture rate as attribute, "recapture_rate" of '
277
+ "this `DiversionBoundarySpec` object."
286
278
  )
287
279
  if _value is None and _instance.agg_method != UPPAggrSelector.MAX:
288
280
  raise ValueError(
@@ -325,7 +317,7 @@ class DiversionRatioBoundary:
325
317
  def __attrs_post_init__(self, /) -> None:
326
318
  """Initialize boundary and area based on other attributes."""
327
319
  share_ratio = critical_diversion_share(
328
- self.diversion_ratio, r_bar=self.recapture_ratio
320
+ self.diversion_ratio, r_bar=self.recapture_rate
329
321
  )
330
322
 
331
323
  upp_agg_kwargs: gbfn.DiversionShareBoundaryKeywords = {"dps": self.precision}
@@ -367,17 +359,13 @@ class DiversionRatioBoundary:
367
359
 
368
360
  upp_agg_kwargs |= {"agg_method": aggregator_, "weighting": wgt_type}
369
361
 
370
- boundary_ = upp_agg_fn(share_ratio, self.recapture_ratio, **upp_agg_kwargs) # type: ignore
362
+ boundary_ = upp_agg_fn(share_ratio, self.recapture_rate, **upp_agg_kwargs) # type: ignore
371
363
  object.__setattr__(self, "area", boundary_.area)
372
364
  object.__setattr__(self, "coordinates", boundary_.coordinates)
373
365
 
374
366
 
375
367
  def guppi_from_delta(
376
- _delta_bound: float = 0.01,
377
- /,
378
- *,
379
- m_star: float = 1.00,
380
- r_bar: float = DEFAULT_REC_RATIO,
368
+ _delta_bound: float = 0.01, /, *, m_star: float = 1.00, r_bar: float = DEFAULT_REC
381
369
  ) -> float:
382
370
  """
383
371
  Translate ∆HHI bound to GUPPI bound.
@@ -389,11 +377,11 @@ def guppi_from_delta(
389
377
  m_star
390
378
  Parametric price-cost margin.
391
379
  r_bar
392
- Default recapture ratio.
380
+ Default recapture rate.
393
381
 
394
382
  Returns
395
383
  -------
396
- GUPPI bound corresponding to ∆HHI bound, at given margin and recapture ratio.
384
+ GUPPI bound corresponding to ∆HHI bound, at given margin and recapture rate.
397
385
 
398
386
  """
399
387
  return gbfn.round_cust(
@@ -421,26 +409,22 @@ def critical_diversion_share(
421
409
  m_star
422
410
  Parametric price-cost margin.
423
411
  r_bar
424
- Default recapture ratio.
412
+ Default recapture rate.
425
413
 
426
414
  Returns
427
415
  -------
428
416
  Critical diversion share (diversion share bound) corresponding to the GUPPI bound
429
- for given margin and recapture ratio.
417
+ for given margin and recapture rate.
430
418
 
431
419
  """
432
420
  return gbfn.round_cust(_guppi_bound / (m_star * r_bar), frac=frac)
433
421
 
434
422
 
435
423
  def share_from_guppi(
436
- _guppi_bound: float = 0.065,
437
- /,
438
- *,
439
- m_star: float = 1.00,
440
- r_bar: float = DEFAULT_REC_RATIO,
424
+ _guppi_bound: float = 0.065, /, *, m_star: float = 1.00, r_bar: float = DEFAULT_REC
441
425
  ) -> float:
442
426
  """
443
- Symmetric-firm share for given GUPPI, margin, and recapture ratio.
427
+ Symmetric-firm share for given GUPPI, margin, and recapture rate.
444
428
 
445
429
  Parameters
446
430
  ----------
@@ -449,13 +433,13 @@ def share_from_guppi(
449
433
  m_star
450
434
  Parametric price-cost margin.
451
435
  r_bar
452
- Default recapture ratio.
436
+ Default recapture rate.
453
437
 
454
438
  Returns
455
439
  -------
456
440
  float
457
441
  Symmetric firm market share on GUPPI boundary, for given margin and
458
- recapture ratio.
442
+ recapture rate.
459
443
 
460
444
  """
461
445
  return gbfn.round_cust(
@@ -472,7 +456,7 @@ if __name__ == "__main__":
472
456
 
473
457
  for _typ in (
474
458
  ConcentrationBoundary,
475
- DiversionRatioBoundary,
459
+ DiversionBoundary,
476
460
  GuidelinesThresholds,
477
461
  HMGThresholds,
478
462
  ):
@@ -15,13 +15,7 @@ import matplotlib.ticker as mpt
15
15
  import numpy as np
16
16
  from mpmath import mp, mpf # type: ignore
17
17
 
18
- from .. import ( # noqa: TID252
19
- _PKG_NAME,
20
- DEFAULT_REC_RATIO,
21
- VERSION,
22
- ArrayBIGINT,
23
- ArrayDouble,
24
- )
18
+ from .. import _PKG_NAME, DEFAULT_REC, VERSION, ArrayDouble # noqa: TID252
25
19
  from . import GuidelinesBoundary, MPFloat
26
20
 
27
21
  __version__ = VERSION
@@ -33,7 +27,7 @@ mp.trap_complex = True
33
27
  class DiversionShareBoundaryKeywords(TypedDict, total=False):
34
28
  """Keyword arguments for functions generating share ratio boundaries."""
35
29
 
36
- recapture_form: Literal["inside-out", "proportional"]
30
+ recapture_form: Literal["inside-out", "fixed"]
37
31
  dps: int
38
32
  agg_method: Literal["arithmetic mean", "geometric mean", "distance"]
39
33
  weighting: Literal["own-share", "cross-product-share", None]
@@ -213,14 +207,14 @@ def hhi_post_contrib_boundary(
213
207
  # hand-rolled root finding
214
208
  def diversion_share_boundary_wtd_avg(
215
209
  _delta_star: float = 0.075,
216
- _r_val: float = DEFAULT_REC_RATIO,
210
+ _r_val: float = DEFAULT_REC,
217
211
  /,
218
212
  *,
219
213
  agg_method: Literal[
220
214
  "arithmetic mean", "geometric mean", "distance"
221
215
  ] = "arithmetic mean",
222
216
  weighting: Literal["own-share", "cross-product-share", None] = "own-share",
223
- recapture_form: Literal["inside-out", "proportional"] = "inside-out",
217
+ recapture_form: Literal["inside-out", "fixed"] = "inside-out",
224
218
  dps: int = 5,
225
219
  ) -> GuidelinesBoundary:
226
220
  R"""
@@ -231,14 +225,14 @@ def diversion_share_boundary_wtd_avg(
231
225
  _delta_star
232
226
  Diversion share, :math:`\overline{d} / \overline{r}` or :math:`\overline{g} / (m^* \cdot \overline{r})`.
233
227
  _r_val
234
- Recapture ratio.
228
+ Recapture rate.
235
229
  agg_method
236
230
  Whether "arithmetic mean", "geometric mean", or "distance".
237
231
  weighting
238
232
  Whether "own-share" or "cross-product-share" (or None for simple, unweighted average).
239
233
  recapture_form
240
- Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
241
- value for both merging firms ("proportional").
234
+ Whether recapture rate is share-proportional ("inside-out") or has fixed
235
+ value for both merging firms ("fixed").
242
236
  dps
243
237
  Number of decimal places for rounding returned shares and area.
244
238
 
@@ -281,7 +275,7 @@ def diversion_share_boundary_wtd_avg(
281
275
  (s_1, 0.0, d_hat / (1 + d_hat)), ylabel=s_2
282
276
  )
283
277
 
284
- # recapture_form == "proportional"
278
+ # recapture_form == "fixed"
285
279
  oswag = solve(
286
280
  s_1 * s_2 / (1 - s_1)
287
281
  + s_2 * s_1 / (1 - s_2)
@@ -417,10 +411,10 @@ def diversion_share_boundary_wtd_avg(
417
411
 
418
412
  def diversion_share_boundary_xact_avg(
419
413
  _delta_star: float = 0.075,
420
- _r_val: float = DEFAULT_REC_RATIO,
414
+ _r_val: float = DEFAULT_REC,
421
415
  /,
422
416
  *,
423
- recapture_form: Literal["inside-out", "proportional"] = "inside-out",
417
+ recapture_form: Literal["inside-out", "fixed"] = "inside-out",
424
418
  dps: int = 5,
425
419
  ) -> GuidelinesBoundary:
426
420
  R"""
@@ -451,7 +445,7 @@ def diversion_share_boundary_xact_avg(
451
445
  ylabel=s_2
452
446
  )
453
447
 
454
- # recapture_form = "proportional"
448
+ # recapture_form = "fixed"
455
449
  sag = solve((s_2/(1 - s_1)) + (s_1/(1 - s_2)) - 2 * d_hat, s_2)[0]
456
450
  symplot(
457
451
  sag,
@@ -464,10 +458,10 @@ def diversion_share_boundary_xact_avg(
464
458
  _delta_star
465
459
  Diversion share, :math:`\overline{d} / \overline{r}` or :math:`\overline{g} / (m^* \cdot \overline{r})`.
466
460
  _r_val
467
- Recapture ratio.
461
+ Recapture rate.
468
462
  recapture_form
469
- Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
470
- value for both merging firms ("proportional").
463
+ Whether recapture rate is share-proportional ("inside-out") or has fixed
464
+ value for both merging firms ("fixed").
471
465
  dps
472
466
  Number of decimal places for rounding returned shares.
473
467
 
@@ -572,10 +566,10 @@ def diversion_share_boundary_xact_avg(
572
566
 
573
567
  def diversion_share_boundary_min(
574
568
  _delta_star: float = 0.075,
575
- _r_val: float = DEFAULT_REC_RATIO,
569
+ _r_val: float = DEFAULT_REC,
576
570
  /,
577
571
  *,
578
- recapture_form: str = "inside-out",
572
+ recapture_form: Literal["inside-out", "fixed"] = "inside-out",
579
573
  dps: int = 10,
580
574
  ) -> GuidelinesBoundary:
581
575
  R"""
@@ -593,10 +587,10 @@ def diversion_share_boundary_min(
593
587
  _delta_star
594
588
  Diversion share, :math:`\overline{d} / \overline{r}` or :math:`\overline{g} / (m^* \cdot \overline{r})`.
595
589
  _r_val
596
- Recapture ratio.
590
+ Recapture rate.
597
591
  recapture_form
598
- Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
599
- value for both merging firms ("proportional").
592
+ Whether recapture rate is share-proportional ("inside-out") or has fixed
593
+ value for both merging firms ("fixed").
600
594
  dps
601
595
  Number of decimal places for rounding returned shares.
602
596
 
@@ -627,7 +621,7 @@ def diversion_share_boundary_min(
627
621
 
628
622
 
629
623
  def diversion_share_boundary_max(
630
- _delta_star: float = 0.075, _: float = DEFAULT_REC_RATIO, /, *, dps: int = 10
624
+ _delta_star: float = 0.075, _: float = DEFAULT_REC, /, *, dps: int = 10
631
625
  ) -> GuidelinesBoundary:
632
626
  R"""
633
627
  Share combinations on the minimum diversion-ratio/share-ratio boundary.
@@ -637,7 +631,7 @@ def diversion_share_boundary_max(
637
631
  _delta_star
638
632
  Diversion share, :math:`\overline{d} / \overline{r}` or :math:`\overline{g} / (m^* \cdot \overline{r})`.
639
633
  _
640
- Placeholder for recapture ratio included for consistency with other
634
+ Placeholder for recapture rate included for consistency with other
641
635
  share-ratio boundary functions.
642
636
  dps
643
637
  Number of decimal places for rounding returned shares.
@@ -664,7 +658,7 @@ def _diversion_share_boundary_intcpt(
664
658
  _r_val: MPFloat,
665
659
  /,
666
660
  *,
667
- recapture_form: Literal["inside-out", "proportional"],
661
+ recapture_form: Literal["inside-out", "fixed"],
668
662
  agg_method: Literal["arithmetic mean", "geometric mean", "distance"],
669
663
  weighting: Literal["cross-product-share", "own-share", None],
670
664
  ) -> float:
@@ -682,9 +676,7 @@ def _diversion_share_boundary_intcpt(
682
676
  ),
683
677
  2 * mpf(f"{_r_val}"),
684
678
  )
685
- case None if (
686
- agg_method == "arithmetic mean" and recapture_form == "proportional"
687
- ):
679
+ case None if agg_method == "arithmetic mean" and recapture_form == "fixed":
688
680
  _s_intcpt = mp.fsub(_delta_star + 1 / 2, mp.fabs(_delta_star - 1 / 2))
689
681
  case _:
690
682
  _s_intcpt = s_2_pre
@@ -692,7 +684,7 @@ def _diversion_share_boundary_intcpt(
692
684
  return _s_intcpt
693
685
 
694
686
 
695
- def lerp[LerpT: (float, MPFloat, ArrayDouble, ArrayBIGINT)](
687
+ def lerp[LerpT: (float, MPFloat, ArrayDouble)](
696
688
  _x1: LerpT, _x2: LerpT, _r: float | MPFloat = 0.25, /
697
689
  ) -> LerpT:
698
690
  R"""
@@ -66,7 +66,7 @@ def prng(_s: SeedSequence | None = None, /) -> np.random.Generator:
66
66
  )
67
67
 
68
68
 
69
- def gen_seed_seq_list_default(
69
+ def seed_sequencer(
70
70
  _len: int = 3, /, *, generated_entropy: Sequence[int] | None = None
71
71
  ) -> tuple[SeedSequence, ...]:
72
72
  R"""