mergeron 2024.738953.1__py3-none-any.whl → 2024.738972.0__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/License.txt +1 -1
- mergeron/core/__init__.py +3 -3
- mergeron/core/excel_helper.py +3 -1
- mergeron/core/ftc_merger_investigations_data.py +13 -16
- mergeron/core/guidelines_boundaries.py +48 -45
- mergeron/core/guidelines_boundaries_specialized_functions.py +24 -21
- mergeron/gen/__init__.py +72 -80
- mergeron/gen/{_data_generation_functions_nonpublic.py → _data_generation_functions.py} +103 -47
- mergeron/gen/data_generation.py +42 -42
- mergeron/gen/investigations_stats.py +1 -1
- mergeron/gen/market_sample.py +79 -0
- mergeron/gen/upp_tests.py +143 -98
- {mergeron-2024.738953.1.dist-info → mergeron-2024.738972.0.dist-info}/METADATA +32 -17
- {mergeron-2024.738953.1.dist-info → mergeron-2024.738972.0.dist-info}/RECORD +15 -14
- {mergeron-2024.738953.1.dist-info → mergeron-2024.738972.0.dist-info}/WHEEL +0 -0
mergeron/License.txt
CHANGED
mergeron/core/__init__.py
CHANGED
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from importlib.metadata import version
|
|
4
4
|
|
|
5
|
-
from attrs import Attribute,
|
|
5
|
+
from attrs import Attribute, field, frozen, validators
|
|
6
6
|
|
|
7
7
|
from .. import _PKG_NAME, RECConstants, UPPAggrSelector # noqa: TID252
|
|
8
8
|
|
|
@@ -38,7 +38,7 @@ def _rec_spec_validator(
|
|
|
38
38
|
)
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
@
|
|
41
|
+
@frozen
|
|
42
42
|
class UPPBoundarySpec:
|
|
43
43
|
share_ratio: float = field(
|
|
44
44
|
kw_only=False,
|
|
@@ -54,7 +54,7 @@ class UPPBoundarySpec:
|
|
|
54
54
|
default=UPPAggrSelector.MAX,
|
|
55
55
|
validator=validators.instance_of(UPPAggrSelector),
|
|
56
56
|
)
|
|
57
|
-
|
|
57
|
+
recapture_form: RECConstants | None = field(
|
|
58
58
|
kw_only=True,
|
|
59
59
|
default=RECConstants.INOUT,
|
|
60
60
|
validator=(
|
mergeron/core/excel_helper.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Methods for writing data from Python to fresh Excel workbooks using
|
|
3
3
|
the third-party package, `xlsxwriter`.
|
|
4
4
|
|
|
5
5
|
Includes a flexible system of defining cell formats.
|
|
@@ -27,6 +27,8 @@ __version__ = version(_PKG_NAME)
|
|
|
27
27
|
class CFmtParent(dict[str, Any], enum.ReprEnum): # type: ignore
|
|
28
28
|
"""Unique mappings defining xlsxwirter Workbook formats"""
|
|
29
29
|
|
|
30
|
+
...
|
|
31
|
+
|
|
30
32
|
|
|
31
33
|
class CFmt(CFmtParent):
|
|
32
34
|
"""
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Methods to parse FTC Merger Investigations Data, downloading source documents
|
|
3
3
|
as necessary
|
|
4
4
|
|
|
5
5
|
NOTES
|
|
@@ -16,7 +16,6 @@ from pathlib import Path
|
|
|
16
16
|
from types import MappingProxyType
|
|
17
17
|
from typing import Any, NamedTuple, TypeAlias
|
|
18
18
|
|
|
19
|
-
import fitz # type: ignore
|
|
20
19
|
import msgpack # type: ignore
|
|
21
20
|
import msgpack_numpy as m # type: ignore
|
|
22
21
|
import numpy as np
|
|
@@ -146,7 +145,7 @@ def construct_data(
|
|
|
146
145
|
)
|
|
147
146
|
return MappingProxyType(_invdata)
|
|
148
147
|
|
|
149
|
-
_invdata = dict(
|
|
148
|
+
_invdata = dict(_parse_invdata()) # Convert immutable to mutable
|
|
150
149
|
|
|
151
150
|
# Add some data periods (
|
|
152
151
|
# only periods ending in 2011, others have few observations and
|
|
@@ -385,21 +384,9 @@ def _invdata_build_aggregate_table(
|
|
|
385
384
|
)
|
|
386
385
|
|
|
387
386
|
|
|
388
|
-
def
|
|
389
|
-
_invdata_docnames: Sequence[str] = (
|
|
390
|
-
"040831horizmergersdata96-03.pdf",
|
|
391
|
-
"p035603horizmergerinvestigationdata1996-2005.pdf",
|
|
392
|
-
"081201hsrmergerdata.pdf",
|
|
393
|
-
"130104horizontalmergerreport.pdf",
|
|
394
|
-
),
|
|
395
|
-
) -> INVData:
|
|
387
|
+
def _parse_invdata() -> INVData:
|
|
396
388
|
"""Parse FTC merger investigations data reports to structured data.
|
|
397
389
|
|
|
398
|
-
Parameters
|
|
399
|
-
----------
|
|
400
|
-
_invdata_docnames
|
|
401
|
-
Names of PDF files reporting FTC merger investigations data.
|
|
402
|
-
|
|
403
390
|
Returns
|
|
404
391
|
-------
|
|
405
392
|
Immutable dictionary of merger investigations data, keyed to
|
|
@@ -408,6 +395,16 @@ def parse_invdata(
|
|
|
408
395
|
by range of HHI and ∆HHI.
|
|
409
396
|
|
|
410
397
|
"""
|
|
398
|
+
import fitz # type: ignore
|
|
399
|
+
# user must install pymupdf to make this function operable
|
|
400
|
+
|
|
401
|
+
_invdata_docnames: Sequence[str] = (
|
|
402
|
+
"040831horizmergersdata96-03.pdf",
|
|
403
|
+
"p035603horizmergerinvestigationdata1996-2005.pdf",
|
|
404
|
+
"081201hsrmergerdata.pdf",
|
|
405
|
+
"130104horizontalmergerreport.pdf",
|
|
406
|
+
)
|
|
407
|
+
|
|
411
408
|
_invdata: dict[str, dict[str, dict[str, INVTableData]]] = {}
|
|
412
409
|
|
|
413
410
|
for _invdata_docname in _invdata_docnames:
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Methods for defining and analyzing boundaries for Guidelines standards,
|
|
3
3
|
with a canvas on which to draw boundaries for Guidelines standards.
|
|
4
4
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import decimal
|
|
8
|
-
from collections.abc import Callable
|
|
9
8
|
from dataclasses import dataclass
|
|
10
9
|
from importlib.metadata import version
|
|
11
10
|
from typing import Any, Literal, TypeAlias
|
|
12
11
|
|
|
13
12
|
import numpy as np
|
|
14
|
-
from attrs import
|
|
13
|
+
from attrs import field, frozen
|
|
15
14
|
from mpmath import mp, mpf # type: ignore
|
|
16
15
|
from numpy.typing import NDArray
|
|
17
16
|
|
|
@@ -24,7 +23,7 @@ __version__ = version(_PKG_NAME)
|
|
|
24
23
|
mp.prec = 80
|
|
25
24
|
mp.trap_complex = True
|
|
26
25
|
|
|
27
|
-
HMGPubYear: TypeAlias = Literal[1992, 2010, 2023]
|
|
26
|
+
HMGPubYear: TypeAlias = Literal[1992, 2004, 2010, 2023]
|
|
28
27
|
|
|
29
28
|
|
|
30
29
|
@dataclass(slots=True, frozen=True)
|
|
@@ -43,25 +42,28 @@ class GuidelinesBoundary:
|
|
|
43
42
|
area: float
|
|
44
43
|
|
|
45
44
|
|
|
46
|
-
@
|
|
47
|
-
class GuidelinesBoundaryCallable:
|
|
48
|
-
boundary_function: Callable[[NDArray[np.float64]], NDArray[np.float64]]
|
|
49
|
-
area: float
|
|
50
|
-
s_naught: float = 0
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@define(slots=True, frozen=True)
|
|
45
|
+
@frozen
|
|
54
46
|
class GuidelinesThresholds:
|
|
55
47
|
"""
|
|
56
48
|
Guidelines threholds by Guidelines publication year
|
|
57
49
|
|
|
58
50
|
ΔHHI, Recapture Rate, GUPPI, Diversion ratio, CMCR, and IPR thresholds
|
|
59
|
-
constructed from concentration standards
|
|
51
|
+
constructed from concentration standards in Guidelines published in
|
|
52
|
+
1992, 2004, 2010, and 2023.
|
|
53
|
+
|
|
54
|
+
The 2004 Guidelines refernced here are the EU Commission
|
|
55
|
+
guidelines on assessment of horizontal mergers. These
|
|
56
|
+
guidelines also define a presumption for mergers with
|
|
57
|
+
post-merger HHI in [1000, 2000) and ΔHHI >= 250 points,
|
|
58
|
+
whi is not modeled here.
|
|
59
|
+
|
|
60
|
+
All other Guidelines modeled here are U.S. merger guidelines.
|
|
61
|
+
|
|
60
62
|
"""
|
|
61
63
|
|
|
62
64
|
pub_year: HMGPubYear
|
|
63
65
|
"""
|
|
64
|
-
Year of publication of the
|
|
66
|
+
Year of publication of the Guidelines
|
|
65
67
|
"""
|
|
66
68
|
|
|
67
69
|
safeharbor: HMGThresholds = field(kw_only=True, default=None)
|
|
@@ -99,6 +101,7 @@ class GuidelinesThresholds:
|
|
|
99
101
|
_hhi_p, _dh_s, _dh_p = {
|
|
100
102
|
1992: (0.18, 0.005, 0.01),
|
|
101
103
|
2010: (0.25, 0.01, 0.02),
|
|
104
|
+
2004: (0.20, 0.015, 0.015),
|
|
102
105
|
2023: (0.18, 0.01, 0.01),
|
|
103
106
|
}[self.pub_year]
|
|
104
107
|
|
|
@@ -507,7 +510,7 @@ def boundary_plot(*, mktshares_plot_flag: bool = True) -> tuple[Any, ...]:
|
|
|
507
510
|
return plt, _fig, _ax_out, _set_axis_def
|
|
508
511
|
|
|
509
512
|
|
|
510
|
-
def dh_area(_dh_val: float = 0.01, /, *,
|
|
513
|
+
def dh_area(_dh_val: float = 0.01, /, *, prec: int = 9) -> float:
|
|
511
514
|
R"""
|
|
512
515
|
Area under the ΔHHI boundary.
|
|
513
516
|
|
|
@@ -530,7 +533,7 @@ def dh_area(_dh_val: float = 0.01, /, *, dh_dps: int = 9) -> float:
|
|
|
530
533
|
----------
|
|
531
534
|
_dh_val
|
|
532
535
|
Change in concentration.
|
|
533
|
-
|
|
536
|
+
prec
|
|
534
537
|
Specified precision in decimal places.
|
|
535
538
|
|
|
536
539
|
Returns
|
|
@@ -544,11 +547,11 @@ def dh_area(_dh_val: float = 0.01, /, *, dh_dps: int = 9) -> float:
|
|
|
544
547
|
|
|
545
548
|
return round(
|
|
546
549
|
float(_s_naught + (_dh_val / 2) * (mp.ln(1 - _s_naught) - mp.ln(_s_naught))),
|
|
547
|
-
|
|
550
|
+
prec,
|
|
548
551
|
)
|
|
549
552
|
|
|
550
553
|
|
|
551
|
-
def dh_area_quad(_dh_val: float = 0.01, /, *,
|
|
554
|
+
def dh_area_quad(_dh_val: float = 0.01, /, *, prec: int = 9) -> float:
|
|
552
555
|
"""
|
|
553
556
|
Area under the ΔHHI boundary.
|
|
554
557
|
|
|
@@ -560,7 +563,7 @@ def dh_area_quad(_dh_val: float = 0.01, /, *, dh_dps: int = 9) -> float:
|
|
|
560
563
|
----------
|
|
561
564
|
_dh_val
|
|
562
565
|
Merging-firms' ΔHHI bound.
|
|
563
|
-
|
|
566
|
+
prec
|
|
564
567
|
Specified precision in decimal places.
|
|
565
568
|
|
|
566
569
|
Returns
|
|
@@ -576,7 +579,7 @@ def dh_area_quad(_dh_val: float = 0.01, /, *, dh_dps: int = 9) -> float:
|
|
|
576
579
|
float(
|
|
577
580
|
_s_naught + mp.quad(lambda x: _dh_val / (2 * x), [_s_naught, 1 - _s_naught])
|
|
578
581
|
),
|
|
579
|
-
|
|
582
|
+
prec,
|
|
580
583
|
)
|
|
581
584
|
|
|
582
585
|
|
|
@@ -590,7 +593,7 @@ def delta_hhi_boundary(
|
|
|
590
593
|
----------
|
|
591
594
|
_dh_val:
|
|
592
595
|
Merging-firms' ΔHHI bound.
|
|
593
|
-
|
|
596
|
+
prec
|
|
594
597
|
Number of decimal places for rounding reported shares.
|
|
595
598
|
|
|
596
599
|
Returns
|
|
@@ -620,7 +623,7 @@ def delta_hhi_boundary(
|
|
|
620
623
|
np.array(_s_1_pts, np.float64),
|
|
621
624
|
np.array(_s_2_pts, np.float64),
|
|
622
625
|
)),
|
|
623
|
-
dh_area(_dh_val,
|
|
626
|
+
dh_area(_dh_val, prec=prec),
|
|
624
627
|
)
|
|
625
628
|
|
|
626
629
|
|
|
@@ -697,7 +700,7 @@ def shrratio_boundary(_bdry_spec: UPPBoundarySpec) -> GuidelinesBoundary:
|
|
|
697
700
|
return shrratio_boundary_xact_avg(
|
|
698
701
|
_bdry_spec.share_ratio,
|
|
699
702
|
_bdry_spec.rec,
|
|
700
|
-
|
|
703
|
+
recapture_form=_bdry_spec.recapture_form.value, # type: ignore
|
|
701
704
|
prec=_bdry_spec.precision,
|
|
702
705
|
)
|
|
703
706
|
case UPPAggrSelector.MAX:
|
|
@@ -708,7 +711,7 @@ def shrratio_boundary(_bdry_spec: UPPBoundarySpec) -> GuidelinesBoundary:
|
|
|
708
711
|
return shrratio_boundary_min(
|
|
709
712
|
_bdry_spec.share_ratio,
|
|
710
713
|
_bdry_spec.rec,
|
|
711
|
-
|
|
714
|
+
recapture_form=_bdry_spec.recapture_form.value, # type: ignore
|
|
712
715
|
prec=_bdry_spec.precision,
|
|
713
716
|
)
|
|
714
717
|
case UPPAggrSelector.DIS:
|
|
@@ -717,7 +720,7 @@ def shrratio_boundary(_bdry_spec: UPPBoundarySpec) -> GuidelinesBoundary:
|
|
|
717
720
|
_bdry_spec.rec,
|
|
718
721
|
agg_method="distance",
|
|
719
722
|
weighting=None,
|
|
720
|
-
|
|
723
|
+
recapture_form=_bdry_spec.recapture_form.value, # type: ignore
|
|
721
724
|
prec=_bdry_spec.precision,
|
|
722
725
|
)
|
|
723
726
|
case _:
|
|
@@ -738,7 +741,7 @@ def shrratio_boundary(_bdry_spec: UPPBoundarySpec) -> GuidelinesBoundary:
|
|
|
738
741
|
_bdry_spec.rec,
|
|
739
742
|
agg_method=_agg_method, # type: ignore
|
|
740
743
|
weighting=_weighting, # type: ignore
|
|
741
|
-
|
|
744
|
+
recapture_form=_bdry_spec.recapture_form.value, # type: ignore
|
|
742
745
|
prec=_bdry_spec.precision,
|
|
743
746
|
)
|
|
744
747
|
|
|
@@ -788,7 +791,7 @@ def shrratio_boundary_min(
|
|
|
788
791
|
_r_val: float = 0.80,
|
|
789
792
|
/,
|
|
790
793
|
*,
|
|
791
|
-
|
|
794
|
+
recapture_form: str = "inside-out",
|
|
792
795
|
prec: int = 10,
|
|
793
796
|
) -> GuidelinesBoundary:
|
|
794
797
|
"""
|
|
@@ -808,7 +811,7 @@ def shrratio_boundary_min(
|
|
|
808
811
|
Margin-adjusted benchmark share ratio.
|
|
809
812
|
_r_val
|
|
810
813
|
Recapture ratio.
|
|
811
|
-
|
|
814
|
+
recapture_form
|
|
812
815
|
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
813
816
|
value for both merging firms ("proportional").
|
|
814
817
|
prec
|
|
@@ -824,7 +827,7 @@ def shrratio_boundary_min(
|
|
|
824
827
|
_s_intcpt = mpf("1.00")
|
|
825
828
|
_s_mid = _delta_star / (1 + _delta_star)
|
|
826
829
|
|
|
827
|
-
if
|
|
830
|
+
if recapture_form == "inside-out":
|
|
828
831
|
# ## Plot envelope of GUPPI boundaries with r_k = r_bar if s_k = min(_s_1, _s_2)
|
|
829
832
|
# ## See (s_i, s_j) in equation~(44), or thereabouts, in paper
|
|
830
833
|
_smin_nr = _delta_star * (1 - _r_val)
|
|
@@ -857,7 +860,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
857
860
|
*,
|
|
858
861
|
agg_method: Literal["arithmetic", "geometric", "distance"] = "arithmetic",
|
|
859
862
|
weighting: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
860
|
-
|
|
863
|
+
recapture_form: Literal["inside-out", "proportional"] = "inside-out",
|
|
861
864
|
prec: int = 5,
|
|
862
865
|
) -> GuidelinesBoundary:
|
|
863
866
|
"""
|
|
@@ -874,7 +877,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
874
877
|
Whether "arithmetic", "geometric", or "distance".
|
|
875
878
|
weighting
|
|
876
879
|
Whether "own-share" or "cross-product-share" (or None for simple, unweighted average).
|
|
877
|
-
|
|
880
|
+
recapture_form
|
|
878
881
|
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
879
882
|
value for both merging firms ("proportional").
|
|
880
883
|
prec
|
|
@@ -895,7 +898,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
895
898
|
g_val, r_val, m_val = 0.06, 0.80, 0.30
|
|
896
899
|
delta_star = g_val / (r_val * m_val)
|
|
897
900
|
|
|
898
|
-
#
|
|
901
|
+
# recapture_form == "inside-out"
|
|
899
902
|
oswag = solve(
|
|
900
903
|
s_1 * s_2 / (1 - s_1)
|
|
901
904
|
+ s_2 * s_1 / (1 - (r_val * s_2 + (1 - r_val) * s_1))
|
|
@@ -920,7 +923,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
920
923
|
ylabel=s_2
|
|
921
924
|
)
|
|
922
925
|
|
|
923
|
-
#
|
|
926
|
+
# recapture_form == "proportional"
|
|
924
927
|
oswag = solve(
|
|
925
928
|
s_1 * s_2 / (1 - s_1)
|
|
926
929
|
+ s_2 * s_1 / (1 - s_2)
|
|
@@ -973,7 +976,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
973
976
|
_de_1 = _s_2 / (1 - _s_1)
|
|
974
977
|
_de_2 = (
|
|
975
978
|
_s_1 / (1 - lerp(_s_1, _s_2, _r_val))
|
|
976
|
-
if
|
|
979
|
+
if recapture_form == "inside-out"
|
|
977
980
|
else _s_1 / (1 - _s_2)
|
|
978
981
|
)
|
|
979
982
|
|
|
@@ -1025,7 +1028,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
1025
1028
|
_s_1_pre,
|
|
1026
1029
|
_delta_star,
|
|
1027
1030
|
_r_val,
|
|
1028
|
-
|
|
1031
|
+
recapture_form=recapture_form,
|
|
1029
1032
|
agg_method=agg_method,
|
|
1030
1033
|
weighting=weighting,
|
|
1031
1034
|
)
|
|
@@ -1063,7 +1066,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1063
1066
|
_r_val: float = 0.80,
|
|
1064
1067
|
/,
|
|
1065
1068
|
*,
|
|
1066
|
-
|
|
1069
|
+
recapture_form: Literal["inside-out", "proportional"] = "inside-out",
|
|
1067
1070
|
prec: int = 5,
|
|
1068
1071
|
) -> GuidelinesBoundary:
|
|
1069
1072
|
"""
|
|
@@ -1082,7 +1085,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1082
1085
|
g_val, r_val, m_val = 0.06, 0.80, 0.30
|
|
1083
1086
|
d_hat = g_val / (r_val * m_val)
|
|
1084
1087
|
|
|
1085
|
-
#
|
|
1088
|
+
# recapture_form = "inside-out"
|
|
1086
1089
|
sag = solve(
|
|
1087
1090
|
(s_2 / (1 - s_1))
|
|
1088
1091
|
+ (s_1 / (1 - (r_val * s_2 + (1 - r_val) * s_1)))
|
|
@@ -1095,7 +1098,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1095
1098
|
ylabel=s_2
|
|
1096
1099
|
)
|
|
1097
1100
|
|
|
1098
|
-
#
|
|
1101
|
+
# recapture_form = "proportional"
|
|
1099
1102
|
sag = solve((s_2/(1 - s_1)) + (s_1/(1 - s_2)) - 2 * d_hat, s_2)[0]
|
|
1100
1103
|
symplot(
|
|
1101
1104
|
sag,
|
|
@@ -1109,7 +1112,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1109
1112
|
Margin-adjusted benchmark share ratio.
|
|
1110
1113
|
_r_val
|
|
1111
1114
|
Recapture ratio
|
|
1112
|
-
|
|
1115
|
+
recapture_form
|
|
1113
1116
|
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
1114
1117
|
value for both merging firms ("proportional").
|
|
1115
1118
|
prec
|
|
@@ -1127,14 +1130,14 @@ def shrratio_boundary_xact_avg(
|
|
|
1127
1130
|
|
|
1128
1131
|
_gbdry_points_start = np.array([(_s_mid, _s_mid)])
|
|
1129
1132
|
_s_1 = np.array(mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz), np.float64)
|
|
1130
|
-
if
|
|
1133
|
+
if recapture_form == "inside-out":
|
|
1131
1134
|
_s_intcpt = mp.fdiv(
|
|
1132
1135
|
mp.fsub(
|
|
1133
1136
|
2 * _delta_star * _r_val + 1, mp.fabs(2 * _delta_star * _r_val - 1)
|
|
1134
1137
|
),
|
|
1135
1138
|
2 * mpf(f"{_r_val}"),
|
|
1136
1139
|
)
|
|
1137
|
-
_nr_t1 = 1 + 2 * _delta_star * _r_val * (1 - _s_1) - _s_1 * (1 - _r_val)
|
|
1140
|
+
_nr_t1 = 1 + 2 * _delta_star * _r_val * (1 - _s_1) - _s_1 * (1 - _r_val)
|
|
1138
1141
|
|
|
1139
1142
|
_nr_sqrt_mdr = 4 * _delta_star * _r_val
|
|
1140
1143
|
_nr_sqrt_mdr2 = _nr_sqrt_mdr * _r_val
|
|
@@ -1159,7 +1162,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1159
1162
|
|
|
1160
1163
|
_nr_t2_s1 = _nr_sqrt_s1sq + _nr_sqrt_s1 + _nr_sqrt_nos1
|
|
1161
1164
|
|
|
1162
|
-
if not np.isclose(
|
|
1165
|
+
if not np.isclose(
|
|
1163
1166
|
np.einsum("i->", _nr_t2_mdr.astype(np.float64)),
|
|
1164
1167
|
np.einsum("i->", _nr_t2_s1.astype(np.float64)),
|
|
1165
1168
|
rtol=0,
|
|
@@ -1167,7 +1170,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1167
1170
|
):
|
|
1168
1171
|
raise RuntimeError(
|
|
1169
1172
|
"Calculation of sq. root term in exact average GUPPI"
|
|
1170
|
-
f"with recapture spec, {f'"{
|
|
1173
|
+
f"with recapture spec, {f'"{recapture_form}"'} is incorrect."
|
|
1171
1174
|
)
|
|
1172
1175
|
|
|
1173
1176
|
_s_2 = (_nr_t1 - np.sqrt(_nr_t2_s1)) / (2 * _r_val)
|
|
@@ -1223,7 +1226,7 @@ def _shrratio_boundary_intcpt(
|
|
|
1223
1226
|
_r_val: mpf,
|
|
1224
1227
|
/,
|
|
1225
1228
|
*,
|
|
1226
|
-
|
|
1229
|
+
recapture_form: Literal["inside-out", "proportional"],
|
|
1227
1230
|
agg_method: Literal["arithmetic", "geometric", "distance"],
|
|
1228
1231
|
weighting: Literal["cross-product-share", "own-share"] | None,
|
|
1229
1232
|
) -> float:
|
|
@@ -1234,7 +1237,7 @@ def _shrratio_boundary_intcpt(
|
|
|
1234
1237
|
_s_intcpt = mpf("1.0")
|
|
1235
1238
|
case None if agg_method == "distance":
|
|
1236
1239
|
_s_intcpt = _delta_star * mp.sqrt("2")
|
|
1237
|
-
case None if agg_method == "arithmetic" and
|
|
1240
|
+
case None if agg_method == "arithmetic" and recapture_form == "inside-out":
|
|
1238
1241
|
_s_intcpt = mp.fdiv(
|
|
1239
1242
|
mp.fsub(
|
|
1240
1243
|
2 * _delta_star * _r_val + 1, mp.fabs(2 * _delta_star * _r_val - 1)
|
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Specialized
|
|
2
|
+
Specialized methods for defining and analyzing boundaries for Guidelines standards.
|
|
3
3
|
|
|
4
|
-
These
|
|
4
|
+
These methods provide improved precision or demonstrate additional methods, but tend
|
|
5
5
|
to have poor performance
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from dataclasses import dataclass
|
|
9
11
|
from importlib.metadata import version
|
|
10
12
|
from typing import Literal
|
|
11
13
|
|
|
12
14
|
import numpy as np
|
|
13
15
|
from mpmath import mp, mpf # type: ignore
|
|
16
|
+
from numpy.typing import NDArray
|
|
14
17
|
from scipy.spatial.distance import minkowski as distance_function # type: ignore
|
|
15
18
|
from sympy import lambdify, simplify, solve, symbols
|
|
16
19
|
|
|
17
20
|
from .. import _PKG_NAME # noqa: TID252
|
|
18
|
-
from .guidelines_boundaries import
|
|
19
|
-
GuidelinesBoundary,
|
|
20
|
-
GuidelinesBoundaryCallable,
|
|
21
|
-
_shrratio_boundary_intcpt,
|
|
22
|
-
lerp,
|
|
23
|
-
)
|
|
21
|
+
from .guidelines_boundaries import GuidelinesBoundary, _shrratio_boundary_intcpt, lerp
|
|
24
22
|
|
|
25
23
|
__version__ = version(_PKG_NAME)
|
|
26
24
|
|
|
@@ -29,7 +27,14 @@ mp.prec = 80
|
|
|
29
27
|
mp.trap_complex = True
|
|
30
28
|
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
@dataclass(slots=True, frozen=True)
|
|
31
|
+
class GuidelinesBoundaryCallable:
|
|
32
|
+
boundary_function: Callable[[NDArray[np.float64]], NDArray[np.float64]]
|
|
33
|
+
area: float
|
|
34
|
+
s_naught: float = 0
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def delta_hhi_boundary_qdtr(_dh_val: float = 0.01, /) -> GuidelinesBoundaryCallable:
|
|
33
38
|
"""
|
|
34
39
|
Generate the list of share combination on the ΔHHI boundary.
|
|
35
40
|
|
|
@@ -37,8 +42,6 @@ def delta_hhi_boundary_qdtr(_dh_val: float = 0.01) -> GuidelinesBoundaryCallable
|
|
|
37
42
|
----------
|
|
38
43
|
_dh_val:
|
|
39
44
|
Merging-firms' ΔHHI bound.
|
|
40
|
-
prec
|
|
41
|
-
Number of decimal places for rounding reported shares.
|
|
42
45
|
|
|
43
46
|
Returns
|
|
44
47
|
-------
|
|
@@ -71,7 +74,7 @@ def shrratio_boundary_qdtr_wtd_avg(
|
|
|
71
74
|
/,
|
|
72
75
|
*,
|
|
73
76
|
weighting: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
74
|
-
|
|
77
|
+
recapture_form: Literal["inside-out", "proportional"] = "inside-out",
|
|
75
78
|
) -> GuidelinesBoundaryCallable:
|
|
76
79
|
"""
|
|
77
80
|
Share combinations for the share-weighted average GUPPI boundary with symmetric
|
|
@@ -85,7 +88,7 @@ def shrratio_boundary_qdtr_wtd_avg(
|
|
|
85
88
|
recapture ratio
|
|
86
89
|
weighting
|
|
87
90
|
Whether "own-share" or "cross-product-share" (or None for simple, unweighted average)
|
|
88
|
-
|
|
91
|
+
recapture_form
|
|
89
92
|
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
90
93
|
value for both merging firms ("proportional").
|
|
91
94
|
|
|
@@ -109,7 +112,7 @@ def shrratio_boundary_qdtr_wtd_avg(
|
|
|
109
112
|
* _s_1
|
|
110
113
|
/ (
|
|
111
114
|
(1 - (_r_val * _s_2 + (1 - _r_val) * _s_1))
|
|
112
|
-
if
|
|
115
|
+
if recapture_form == "inside-out"
|
|
113
116
|
else (1 - _s_2)
|
|
114
117
|
)
|
|
115
118
|
- (_s_1 + _s_2) * _delta_star
|
|
@@ -118,7 +121,7 @@ def shrratio_boundary_qdtr_wtd_avg(
|
|
|
118
121
|
_bdry_func = solve(_bdry_eqn, _s_2)[0] # type: ignore
|
|
119
122
|
_s_naught = (
|
|
120
123
|
float(solve(simplify(_bdry_eqn.subs({_s_2: 1 - _s_1})), _s_1)[0]) # type: ignore
|
|
121
|
-
if
|
|
124
|
+
if recapture_form == "inside-out"
|
|
122
125
|
else 0
|
|
123
126
|
)
|
|
124
127
|
_bdry_area = float(
|
|
@@ -139,7 +142,7 @@ def shrratio_boundary_qdtr_wtd_avg(
|
|
|
139
142
|
* _s_1
|
|
140
143
|
/ (
|
|
141
144
|
(1 - (_r_val * _s_2 + (1 - _r_val) * _s_1))
|
|
142
|
-
if
|
|
145
|
+
if recapture_form == "inside-out"
|
|
143
146
|
else (1 - _s_2)
|
|
144
147
|
)
|
|
145
148
|
- (_s_1 + _s_2) * _d_star
|
|
@@ -167,7 +170,7 @@ def shrratio_boundary_qdtr_wtd_avg(
|
|
|
167
170
|
* _s_1
|
|
168
171
|
/ (
|
|
169
172
|
(1 - (_r_val * _s_2 + (1 - _r_val) * _s_1))
|
|
170
|
-
if
|
|
173
|
+
if recapture_form == "inside-out"
|
|
171
174
|
else (1 - _s_2)
|
|
172
175
|
)
|
|
173
176
|
- _delta_star
|
|
@@ -191,7 +194,7 @@ def shrratio_boundary_distance(
|
|
|
191
194
|
*,
|
|
192
195
|
agg_method: Literal["arithmetic", "distance"] = "arithmetic",
|
|
193
196
|
weighting: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
194
|
-
|
|
197
|
+
recapture_form: Literal["inside-out", "proportional"] = "inside-out",
|
|
195
198
|
prec: int = 5,
|
|
196
199
|
) -> GuidelinesBoundary:
|
|
197
200
|
"""
|
|
@@ -214,7 +217,7 @@ def shrratio_boundary_distance(
|
|
|
214
217
|
Whether "arithmetic", "geometric", or "distance".
|
|
215
218
|
weighting
|
|
216
219
|
Whether "own-share" or "cross-product-share".
|
|
217
|
-
|
|
220
|
+
recapture_form
|
|
218
221
|
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
219
222
|
value for both merging firms ("proportional").
|
|
220
223
|
prec
|
|
@@ -252,7 +255,7 @@ def shrratio_boundary_distance(
|
|
|
252
255
|
_de_1 = _s_2 / (1 - _s_1)
|
|
253
256
|
_de_2 = (
|
|
254
257
|
_s_1 / (1 - lerp(_s_1, _s_2, _r_val))
|
|
255
|
-
if
|
|
258
|
+
if recapture_form == "inside-out"
|
|
256
259
|
else _s_1 / (1 - _s_2)
|
|
257
260
|
)
|
|
258
261
|
|
|
@@ -310,7 +313,7 @@ def shrratio_boundary_distance(
|
|
|
310
313
|
_s_1_pre,
|
|
311
314
|
_delta_star,
|
|
312
315
|
_r_val,
|
|
313
|
-
|
|
316
|
+
recapture_form=recapture_form,
|
|
314
317
|
agg_method=agg_method,
|
|
315
318
|
weighting=weighting,
|
|
316
319
|
)
|