mergeron 2024.738949.5__py3-none-any.whl → 2024.738949.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mergeron might be problematic. Click here for more details.
- mergeron/__init__.py +29 -0
- mergeron/core/__init__.py +65 -1
- mergeron/core/excel_helper.py +5 -12
- mergeron/core/guidelines_boundaries.py +116 -537
- mergeron/core/guidelines_boundaries_specialized_functions.py +341 -0
- mergeron/core/pseudorandom_numbers.py +1 -1
- mergeron/examples/concentration_as_diversion.py +45 -50
- mergeron/examples/enforcement_boundaries_for_mergers_with_asymmetric_shares.py +13 -7
- mergeron/examples/investigations_stats_obs_tables.py +13 -11
- mergeron/examples/investigations_stats_sim_tables.py +11 -12
- mergeron/examples/plotSafeHarbs_symbolically.py +7 -5
- mergeron/examples/sound_guppi_safeharbor.py +6 -7
- mergeron/examples/visualize_guidelines_tests.py +3 -5
- mergeron/gen/__init__.py +9 -33
- mergeron/gen/_data_generation_functions_nonpublic.py +5 -6
- mergeron/gen/data_generation.py +1 -2
- mergeron/gen/upp_tests.py +7 -7
- {mergeron-2024.738949.5.dist-info → mergeron-2024.738949.6.dist-info}/METADATA +1 -1
- {mergeron-2024.738949.5.dist-info → mergeron-2024.738949.6.dist-info}/RECORD +20 -19
- {mergeron-2024.738949.5.dist-info → mergeron-2024.738949.6.dist-info}/WHEEL +0 -0
|
@@ -14,10 +14,9 @@ import numpy as np
|
|
|
14
14
|
from attrs import define, field
|
|
15
15
|
from mpmath import mp, mpf # type: ignore
|
|
16
16
|
from numpy.typing import NDArray
|
|
17
|
-
from scipy.spatial.distance import minkowski as distance_function
|
|
18
|
-
from sympy import lambdify, simplify, solve, symbols
|
|
19
17
|
|
|
20
|
-
from .. import _PKG_NAME # noqa: TID252
|
|
18
|
+
from .. import _PKG_NAME, UPPAggrSelector # noqa: TID252
|
|
19
|
+
from . import UPPBoundarySpec
|
|
21
20
|
|
|
22
21
|
__version__ = version(_PKG_NAME)
|
|
23
22
|
|
|
@@ -28,6 +27,16 @@ mp.trap_complex = True
|
|
|
28
27
|
HMGPubYear: TypeAlias = Literal[1992, 2010, 2023]
|
|
29
28
|
|
|
30
29
|
|
|
30
|
+
@dataclass(slots=True, frozen=True)
|
|
31
|
+
class HMGThresholds:
|
|
32
|
+
delta: float
|
|
33
|
+
rec: float
|
|
34
|
+
guppi: float
|
|
35
|
+
divr: float
|
|
36
|
+
cmcr: float
|
|
37
|
+
ipr: float
|
|
38
|
+
|
|
39
|
+
|
|
31
40
|
@dataclass(slots=True, frozen=True)
|
|
32
41
|
class GuidelinesBoundary:
|
|
33
42
|
coordinates: NDArray[np.float64]
|
|
@@ -41,16 +50,6 @@ class GuidelinesBoundaryCallable:
|
|
|
41
50
|
s_naught: float = 0
|
|
42
51
|
|
|
43
52
|
|
|
44
|
-
@define(slots=True, frozen=True)
|
|
45
|
-
class HMGThresholds:
|
|
46
|
-
delta: float
|
|
47
|
-
rec: float
|
|
48
|
-
guppi: float
|
|
49
|
-
divr: float
|
|
50
|
-
cmcr: float
|
|
51
|
-
ipr: float
|
|
52
|
-
|
|
53
|
-
|
|
54
53
|
@define(slots=True, frozen=True)
|
|
55
54
|
class GuidelinesThresholds:
|
|
56
55
|
"""
|
|
@@ -90,7 +89,7 @@ class GuidelinesThresholds:
|
|
|
90
89
|
diversion ratio limit, CMCR, and IPR
|
|
91
90
|
"""
|
|
92
91
|
|
|
93
|
-
def __attrs_post_init__(self, /):
|
|
92
|
+
def __attrs_post_init__(self, /) -> None:
|
|
94
93
|
# In the 2023 Guidlines, the agencies do not define a
|
|
95
94
|
# negative presumption, or safeharbor. Practically speaking,
|
|
96
95
|
# given resource constraints and loss aversion, it is likely
|
|
@@ -541,11 +540,11 @@ def dh_area(_dh_val: float = 0.01, /, *, dh_dps: int = 9) -> float:
|
|
|
541
540
|
"""
|
|
542
541
|
|
|
543
542
|
_dh_val = mpf(f"{_dh_val}")
|
|
544
|
-
|
|
545
|
-
_s1_one = 1 - _s1_zero
|
|
543
|
+
_s_naught = (1 - mp.sqrt(1 - 2 * _dh_val)) / 2
|
|
546
544
|
|
|
547
545
|
return round(
|
|
548
|
-
float(
|
|
546
|
+
float(_s_naught + (_dh_val / 2) * (mp.ln(1 - _s_naught) - mp.ln(_s_naught))),
|
|
547
|
+
dh_dps,
|
|
549
548
|
)
|
|
550
549
|
|
|
551
550
|
|
|
@@ -571,17 +570,18 @@ def dh_area_quad(_dh_val: float = 0.01, /, *, dh_dps: int = 9) -> float:
|
|
|
571
570
|
"""
|
|
572
571
|
|
|
573
572
|
_dh_val = mpf(f"{_dh_val}")
|
|
574
|
-
|
|
575
|
-
_s1_one = 1 - _s1_zero
|
|
573
|
+
_s_naught = (1 - mp.sqrt(1 - 2 * _dh_val)) / 2
|
|
576
574
|
|
|
577
575
|
return round(
|
|
578
|
-
float(
|
|
576
|
+
float(
|
|
577
|
+
_s_naught + mp.quad(lambda x: _dh_val / (2 * x), [_s_naught, 1 - _s_naught])
|
|
578
|
+
),
|
|
579
579
|
dh_dps,
|
|
580
580
|
)
|
|
581
581
|
|
|
582
582
|
|
|
583
583
|
def delta_hhi_boundary(
|
|
584
|
-
_dh_val: float = 0.01, /, *,
|
|
584
|
+
_dh_val: float = 0.01, /, *, prec: int = 5
|
|
585
585
|
) -> GuidelinesBoundary:
|
|
586
586
|
"""
|
|
587
587
|
Generate the list of share combination on the ΔHHI boundary.
|
|
@@ -600,19 +600,19 @@ def delta_hhi_boundary(
|
|
|
600
600
|
"""
|
|
601
601
|
|
|
602
602
|
_dh_val = mpf(f"{_dh_val}")
|
|
603
|
-
|
|
604
|
-
|
|
603
|
+
_s_naught = 1 / 2 * (1 - mp.sqrt(1 - 2 * _dh_val))
|
|
604
|
+
_s_mid = mp.sqrt(_dh_val / 2)
|
|
605
605
|
|
|
606
606
|
_dh_step_sz = mp.power(10, -6)
|
|
607
|
-
_s_1 = np.array(mp.arange(
|
|
607
|
+
_s_1 = np.array(mp.arange(_s_mid, _s_naught - mp.eps, -_dh_step_sz))
|
|
608
608
|
_s_2 = _dh_val / (2 * _s_1)
|
|
609
609
|
|
|
610
610
|
# Boundary points
|
|
611
|
-
|
|
612
|
-
np.array([(mpf("0.0"), mpf("1.0"))]),
|
|
611
|
+
_dh_half = np.row_stack((
|
|
613
612
|
np.column_stack((_s_1, _s_2)),
|
|
614
|
-
np.array([(mpf("
|
|
613
|
+
np.array([(mpf("0.0"), mpf("1.0"))]),
|
|
615
614
|
))
|
|
615
|
+
_dh_bdry_pts = np.row_stack((np.flip(_dh_half, 0), np.flip(_dh_half[1:], 1)))
|
|
616
616
|
|
|
617
617
|
_s_1_pts, _s_2_pts = np.split(_dh_bdry_pts, 2, axis=1)
|
|
618
618
|
return GuidelinesBoundary(
|
|
@@ -620,43 +620,7 @@ def delta_hhi_boundary(
|
|
|
620
620
|
np.array(_s_1_pts, np.float64),
|
|
621
621
|
np.array(_s_2_pts, np.float64),
|
|
622
622
|
)),
|
|
623
|
-
dh_area(_dh_val, dh_dps=
|
|
624
|
-
)
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
def delta_hhi_boundary_qdtr(_dh_val: float = 0.01) -> GuidelinesBoundaryCallable:
|
|
628
|
-
"""
|
|
629
|
-
Generate the list of share combination on the ΔHHI boundary.
|
|
630
|
-
|
|
631
|
-
Parameters
|
|
632
|
-
----------
|
|
633
|
-
_dh_val:
|
|
634
|
-
Merging-firms' ΔHHI bound.
|
|
635
|
-
dh_dps
|
|
636
|
-
Number of decimal places for rounding reported shares.
|
|
637
|
-
|
|
638
|
-
Returns
|
|
639
|
-
-------
|
|
640
|
-
Callable to generate array of share-pairs, area under boundary.
|
|
641
|
-
|
|
642
|
-
"""
|
|
643
|
-
|
|
644
|
-
_dh_val = mpf(f"{_dh_val}")
|
|
645
|
-
|
|
646
|
-
_s_1, _s_2 = symbols("s_1, s_2", positive=True)
|
|
647
|
-
|
|
648
|
-
_hhi_eqn = _s_2 - 0.01 / (2 * _s_1)
|
|
649
|
-
|
|
650
|
-
_hhi_bdry = solve(_hhi_eqn, _s_2)[0]
|
|
651
|
-
_s_nought = float(solve(_hhi_eqn.subs({_s_2: 1 - _s_1}), _s_1)[0])
|
|
652
|
-
|
|
653
|
-
_hhi_bdry_area = 2 * (
|
|
654
|
-
_s_nought
|
|
655
|
-
+ mp.quad(lambdify(_s_1, _hhi_bdry, "mpmath"), (_s_nought, 1 - _s_nought))
|
|
656
|
-
)
|
|
657
|
-
|
|
658
|
-
return GuidelinesBoundaryCallable(
|
|
659
|
-
lambdify(_s_1, _hhi_bdry, "numpy"), _hhi_bdry_area, _s_nought
|
|
623
|
+
dh_area(_dh_val, dh_dps=prec),
|
|
660
624
|
)
|
|
661
625
|
|
|
662
626
|
|
|
@@ -727,8 +691,60 @@ def hhi_pre_contrib_boundary(
|
|
|
727
691
|
)
|
|
728
692
|
|
|
729
693
|
|
|
694
|
+
def shrratio_boundary(_bdry_spec: UPPBoundarySpec) -> GuidelinesBoundary:
|
|
695
|
+
match _bdry_spec.agg_method:
|
|
696
|
+
case UPPAggrSelector.AVG:
|
|
697
|
+
return shrratio_boundary_xact_avg(
|
|
698
|
+
_bdry_spec.share_ratio,
|
|
699
|
+
_bdry_spec.rec,
|
|
700
|
+
recapture_spec=_bdry_spec.recapture_spec.value, # type: ignore
|
|
701
|
+
prec=_bdry_spec.precision,
|
|
702
|
+
)
|
|
703
|
+
case UPPAggrSelector.MAX:
|
|
704
|
+
return shrratio_boundary_max(
|
|
705
|
+
_bdry_spec.share_ratio, _bdry_spec.rec, prec=_bdry_spec.precision
|
|
706
|
+
)
|
|
707
|
+
case UPPAggrSelector.MIN:
|
|
708
|
+
return shrratio_boundary_min(
|
|
709
|
+
_bdry_spec.share_ratio,
|
|
710
|
+
_bdry_spec.rec,
|
|
711
|
+
recapture_spec=_bdry_spec.recapture_spec.value, # type: ignore
|
|
712
|
+
prec=_bdry_spec.precision,
|
|
713
|
+
)
|
|
714
|
+
case UPPAggrSelector.DIS:
|
|
715
|
+
return shrratio_boundary_wtd_avg(
|
|
716
|
+
_bdry_spec.share_ratio,
|
|
717
|
+
_bdry_spec.rec,
|
|
718
|
+
agg_method="distance",
|
|
719
|
+
weighting=None,
|
|
720
|
+
recapture_spec=_bdry_spec.recapture_spec.value, # type: ignore
|
|
721
|
+
prec=_bdry_spec.precision,
|
|
722
|
+
)
|
|
723
|
+
case _:
|
|
724
|
+
_weighting = (
|
|
725
|
+
"cross-product-share"
|
|
726
|
+
if _bdry_spec.agg_method.value.startswith("cross-product-share")
|
|
727
|
+
else "own-share"
|
|
728
|
+
)
|
|
729
|
+
|
|
730
|
+
_agg_method = (
|
|
731
|
+
"arithmetic"
|
|
732
|
+
if _bdry_spec.agg_method.value.endswith("average")
|
|
733
|
+
else "distance"
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
return shrratio_boundary_wtd_avg(
|
|
737
|
+
_bdry_spec.share_ratio,
|
|
738
|
+
_bdry_spec.rec,
|
|
739
|
+
agg_method=_agg_method, # type: ignore
|
|
740
|
+
weighting=_weighting, # type: ignore
|
|
741
|
+
recapture_spec=_bdry_spec.recapture_spec.value, # type: ignore
|
|
742
|
+
prec=_bdry_spec.precision,
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
|
|
730
746
|
def shrratio_boundary_max(
|
|
731
|
-
_delta_star: float = 0.075, _r_val: float = 0.80, /, *,
|
|
747
|
+
_delta_star: float = 0.075, _r_val: float = 0.80, /, *, prec: int = 10
|
|
732
748
|
) -> GuidelinesBoundary:
|
|
733
749
|
"""
|
|
734
750
|
Share combinations on the minimum GUPPI boundary with symmetric
|
|
@@ -740,7 +756,7 @@ def shrratio_boundary_max(
|
|
|
740
756
|
Margin-adjusted benchmark share ratio.
|
|
741
757
|
_r_val
|
|
742
758
|
Recapture ratio.
|
|
743
|
-
|
|
759
|
+
prec
|
|
744
760
|
Number of decimal places for rounding returned shares.
|
|
745
761
|
|
|
746
762
|
Returns
|
|
@@ -749,12 +765,6 @@ def shrratio_boundary_max(
|
|
|
749
765
|
|
|
750
766
|
"""
|
|
751
767
|
|
|
752
|
-
if _delta_star > 1:
|
|
753
|
-
raise ValueError(
|
|
754
|
-
"Invalid combination specified; "
|
|
755
|
-
"Margin-adjusted benchmark share ratio cannot exceed 1."
|
|
756
|
-
)
|
|
757
|
-
|
|
758
768
|
# _r_val is not needed for max boundary, but is specified for consistency
|
|
759
769
|
# of function call with other shrratio_mgnsym_boundary functions
|
|
760
770
|
del _r_val
|
|
@@ -769,7 +779,7 @@ def shrratio_boundary_max(
|
|
|
769
779
|
np.array(_s1_pts, np.float64),
|
|
770
780
|
np.array(_s1_pts[::-1], np.float64),
|
|
771
781
|
)),
|
|
772
|
-
round(float(_s_intcpt * _s_mid),
|
|
782
|
+
round(float(_s_intcpt * _s_mid), prec), # simplified calculation
|
|
773
783
|
)
|
|
774
784
|
|
|
775
785
|
|
|
@@ -779,7 +789,7 @@ def shrratio_boundary_min(
|
|
|
779
789
|
/,
|
|
780
790
|
*,
|
|
781
791
|
recapture_spec: str = "inside-out",
|
|
782
|
-
|
|
792
|
+
prec: int = 10,
|
|
783
793
|
) -> GuidelinesBoundary:
|
|
784
794
|
"""
|
|
785
795
|
Share combinations on the minimum GUPPI boundary, with symmetric
|
|
@@ -801,7 +811,7 @@ def shrratio_boundary_min(
|
|
|
801
811
|
recapture_spec
|
|
802
812
|
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
803
813
|
value for both merging firms ("proportional").
|
|
804
|
-
|
|
814
|
+
prec
|
|
805
815
|
Number of decimal places for rounding returned shares.
|
|
806
816
|
|
|
807
817
|
Returns
|
|
@@ -810,14 +820,6 @@ def shrratio_boundary_min(
|
|
|
810
820
|
|
|
811
821
|
"""
|
|
812
822
|
|
|
813
|
-
if _delta_star > 1:
|
|
814
|
-
raise ValueError("Margin-adjusted benchmark share ratio cannot exceed 1.")
|
|
815
|
-
|
|
816
|
-
if recapture_spec not in (_recspecs := ("inside-out", "proportional")):
|
|
817
|
-
raise ValueError(
|
|
818
|
-
f"Recapture_spec value, {f'"{recapture_spec}"'} not in {_recspecs!r}"
|
|
819
|
-
)
|
|
820
|
-
|
|
821
823
|
_delta_star = mpf(f"{_delta_star}")
|
|
822
824
|
_s_intcpt = mpf("1.00")
|
|
823
825
|
_s_mid = _delta_star / (1 + _delta_star)
|
|
@@ -844,131 +846,7 @@ def shrratio_boundary_min(
|
|
|
844
846
|
_s1_pts, _gbd_area = np.array((0, _s_mid, _s_intcpt), np.float64), _s_mid
|
|
845
847
|
|
|
846
848
|
return GuidelinesBoundary(
|
|
847
|
-
np.column_stack((_s1_pts, _s1_pts[::-1])), round(float(_gbd_area),
|
|
848
|
-
)
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
def shrratio_boundary_qdtr_wtd_avg(
|
|
852
|
-
_delta_star: float = 0.075,
|
|
853
|
-
_r_val: float = 0.80,
|
|
854
|
-
/,
|
|
855
|
-
*,
|
|
856
|
-
wgtng_policy: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
857
|
-
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
858
|
-
) -> GuidelinesBoundaryCallable:
|
|
859
|
-
"""
|
|
860
|
-
Share combinations for the share-weighted average GUPPI boundary with symmetric
|
|
861
|
-
merging-firm margins.
|
|
862
|
-
|
|
863
|
-
Parameters
|
|
864
|
-
----------
|
|
865
|
-
_delta_star
|
|
866
|
-
corollary to GUPPI bound (:math:`\\overline{g} / (m^* \\cdot \\overline{r})`)
|
|
867
|
-
_r_val
|
|
868
|
-
recapture ratio
|
|
869
|
-
wgtng_policy
|
|
870
|
-
Whether "own-share" or "cross-product-share" (or None for simple, unweighted average)
|
|
871
|
-
recapture_spec
|
|
872
|
-
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
873
|
-
value for both merging firms ("proportional").
|
|
874
|
-
|
|
875
|
-
Returns
|
|
876
|
-
-------
|
|
877
|
-
Array of share-pairs, area under boundary.
|
|
878
|
-
|
|
879
|
-
"""
|
|
880
|
-
|
|
881
|
-
if _delta_star > 1:
|
|
882
|
-
raise ValueError(
|
|
883
|
-
"Margin-adjusted benchmark share ratio, `_delta_star` cannot exceed 1."
|
|
884
|
-
)
|
|
885
|
-
|
|
886
|
-
_delta_star = mpf(f"{_delta_star}")
|
|
887
|
-
_s_mid = _delta_star / (1 + _delta_star)
|
|
888
|
-
_s_naught = 0
|
|
889
|
-
|
|
890
|
-
_s_1, _s_2 = symbols("s_1:3", positive=True)
|
|
891
|
-
|
|
892
|
-
match wgtng_policy:
|
|
893
|
-
case "own-share":
|
|
894
|
-
_bdry_eqn = (
|
|
895
|
-
_s_1 * _s_2 / (1 - _s_1)
|
|
896
|
-
+ _s_2
|
|
897
|
-
* _s_1
|
|
898
|
-
/ (
|
|
899
|
-
(1 - (_r_val * _s_2 + (1 - _r_val) * _s_1))
|
|
900
|
-
if recapture_spec == "inside-out"
|
|
901
|
-
else (1 - _s_2)
|
|
902
|
-
)
|
|
903
|
-
- (_s_1 + _s_2) * _delta_star
|
|
904
|
-
)
|
|
905
|
-
|
|
906
|
-
_bdry_func = solve(_bdry_eqn, _s_2)[0]
|
|
907
|
-
_s_naught = (
|
|
908
|
-
float(solve(simplify(_bdry_eqn.subs({_s_2: 1 - _s_1})), _s_1)[0])
|
|
909
|
-
if recapture_spec == "inside-out"
|
|
910
|
-
else 0
|
|
911
|
-
)
|
|
912
|
-
_bdry_area = float(
|
|
913
|
-
2
|
|
914
|
-
* (
|
|
915
|
-
_s_naught
|
|
916
|
-
+ mp.quad(lambdify(_s_1, _bdry_func, "mpmath"), (_s_naught, _s_mid))
|
|
917
|
-
)
|
|
918
|
-
- (_s_mid**2 + _s_naught**2)
|
|
919
|
-
)
|
|
920
|
-
|
|
921
|
-
case "cross-product-share":
|
|
922
|
-
mp.trap_complex = False
|
|
923
|
-
_d_star = symbols("d", positive=True)
|
|
924
|
-
_bdry_eqn = (
|
|
925
|
-
_s_2 * _s_2 / (1 - _s_1)
|
|
926
|
-
+ _s_1
|
|
927
|
-
* _s_1
|
|
928
|
-
/ (
|
|
929
|
-
(1 - (_r_val * _s_2 + (1 - _r_val) * _s_1))
|
|
930
|
-
if recapture_spec == "inside-out"
|
|
931
|
-
else (1 - _s_2)
|
|
932
|
-
)
|
|
933
|
-
- (_s_1 + _s_2) * _d_star
|
|
934
|
-
)
|
|
935
|
-
|
|
936
|
-
_bdry_func = solve(_bdry_eqn, _s_2)[1]
|
|
937
|
-
_bdry_area = float(
|
|
938
|
-
2
|
|
939
|
-
* (
|
|
940
|
-
mp.quad(
|
|
941
|
-
lambdify(
|
|
942
|
-
_s_1, _bdry_func.subs({_d_star: _delta_star}), "mpmath"
|
|
943
|
-
),
|
|
944
|
-
(0, _s_mid),
|
|
945
|
-
)
|
|
946
|
-
).real
|
|
947
|
-
- _s_mid**2
|
|
948
|
-
)
|
|
949
|
-
|
|
950
|
-
case _:
|
|
951
|
-
_bdry_eqn = (
|
|
952
|
-
1 / 2 * _s_2 / (1 - _s_1)
|
|
953
|
-
+ 1
|
|
954
|
-
/ 2
|
|
955
|
-
* _s_1
|
|
956
|
-
/ (
|
|
957
|
-
(1 - (_r_val * _s_2 + (1 - _r_val) * _s_1))
|
|
958
|
-
if recapture_spec == "inside-out"
|
|
959
|
-
else (1 - _s_2)
|
|
960
|
-
)
|
|
961
|
-
- _delta_star
|
|
962
|
-
)
|
|
963
|
-
|
|
964
|
-
_bdry_func = solve(_bdry_eqn, _s_2)[0]
|
|
965
|
-
_bdry_area = float(
|
|
966
|
-
2 * (mp.quad(lambdify(_s_1, _bdry_func, "mpmath"), (0, _s_mid)))
|
|
967
|
-
- _s_mid**2
|
|
968
|
-
)
|
|
969
|
-
|
|
970
|
-
return GuidelinesBoundaryCallable(
|
|
971
|
-
lambdify(_s_1, _bdry_func, "numpy"), _bdry_area, _s_naught
|
|
849
|
+
np.column_stack((_s1_pts, _s1_pts[::-1])), round(float(_gbd_area), prec)
|
|
972
850
|
)
|
|
973
851
|
|
|
974
852
|
|
|
@@ -977,10 +855,10 @@ def shrratio_boundary_wtd_avg(
|
|
|
977
855
|
_r_val: float = 0.80,
|
|
978
856
|
/,
|
|
979
857
|
*,
|
|
980
|
-
|
|
981
|
-
|
|
858
|
+
agg_method: Literal["arithmetic", "geometric", "distance"] = "arithmetic",
|
|
859
|
+
weighting: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
982
860
|
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
983
|
-
|
|
861
|
+
prec: int = 5,
|
|
984
862
|
) -> GuidelinesBoundary:
|
|
985
863
|
"""
|
|
986
864
|
Share combinations for the share-weighted average GUPPI boundary with symmetric
|
|
@@ -992,14 +870,14 @@ def shrratio_boundary_wtd_avg(
|
|
|
992
870
|
corollary to GUPPI bound (:math:`\\overline{g} / (m^* \\cdot \\overline{r})`)
|
|
993
871
|
_r_val
|
|
994
872
|
recapture ratio
|
|
995
|
-
|
|
873
|
+
agg_method
|
|
996
874
|
Whether "arithmetic", "geometric", or "distance".
|
|
997
|
-
|
|
875
|
+
weighting
|
|
998
876
|
Whether "own-share" or "cross-product-share" (or None for simple, unweighted average).
|
|
999
877
|
recapture_spec
|
|
1000
878
|
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
1001
879
|
value for both merging firms ("proportional").
|
|
1002
|
-
|
|
880
|
+
prec
|
|
1003
881
|
Number of decimal places for rounding returned shares and area.
|
|
1004
882
|
|
|
1005
883
|
Returns
|
|
@@ -1070,11 +948,6 @@ def shrratio_boundary_wtd_avg(
|
|
|
1070
948
|
|
|
1071
949
|
"""
|
|
1072
950
|
|
|
1073
|
-
if _delta_star > 1:
|
|
1074
|
-
raise ValueError(
|
|
1075
|
-
"Margin-adjusted benchmark share ratio, `_delta_star` cannot exceed 1."
|
|
1076
|
-
)
|
|
1077
|
-
|
|
1078
951
|
_delta_star = mpf(f"{_delta_star}")
|
|
1079
952
|
_s_mid = _delta_star / (1 + _delta_star)
|
|
1080
953
|
|
|
@@ -1084,8 +957,8 @@ def shrratio_boundary_wtd_avg(
|
|
|
1084
957
|
_s_2_oddval, _s_2_oddsum, _s_2_evnsum = True, 0, 0
|
|
1085
958
|
|
|
1086
959
|
# parameters for iteration
|
|
1087
|
-
_gbd_step_sz = mp.power(10, -
|
|
1088
|
-
_theta = _gbd_step_sz * (10 if
|
|
960
|
+
_gbd_step_sz = mp.power(10, -prec)
|
|
961
|
+
_theta = _gbd_step_sz * (10 if weighting == "cross-product-share" else 1)
|
|
1089
962
|
for _s_1 in mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz):
|
|
1090
963
|
# The wtd. avg. GUPPI is not always convex to the origin, so we
|
|
1091
964
|
# increment _s_2 after each iteration in which our algorithm
|
|
@@ -1106,13 +979,13 @@ def shrratio_boundary_wtd_avg(
|
|
|
1106
979
|
|
|
1107
980
|
_r = (
|
|
1108
981
|
mp.fdiv(
|
|
1109
|
-
_s_1 if
|
|
982
|
+
_s_1 if weighting == "cross-product-share" else _s_2, _s_1 + _s_2
|
|
1110
983
|
)
|
|
1111
|
-
if
|
|
984
|
+
if weighting
|
|
1112
985
|
else 0.5
|
|
1113
986
|
)
|
|
1114
987
|
|
|
1115
|
-
match
|
|
988
|
+
match agg_method:
|
|
1116
989
|
case "geometric":
|
|
1117
990
|
_delta_test = mp.expm1(lerp(mp.log1p(_de_1), mp.log1p(_de_2), _r))
|
|
1118
991
|
case "distance":
|
|
@@ -1122,7 +995,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
1122
995
|
|
|
1123
996
|
_test_flag, _incr_decr = (
|
|
1124
997
|
(_delta_test > _delta_star, -1)
|
|
1125
|
-
if
|
|
998
|
+
if weighting == "cross-product-share"
|
|
1126
999
|
else (_delta_test < _delta_star, 1)
|
|
1127
1000
|
)
|
|
1128
1001
|
|
|
@@ -1153,11 +1026,11 @@ def shrratio_boundary_wtd_avg(
|
|
|
1153
1026
|
_delta_star,
|
|
1154
1027
|
_r_val,
|
|
1155
1028
|
recapture_spec=recapture_spec,
|
|
1156
|
-
|
|
1157
|
-
|
|
1029
|
+
agg_method=agg_method,
|
|
1030
|
+
weighting=weighting,
|
|
1158
1031
|
)
|
|
1159
1032
|
|
|
1160
|
-
if
|
|
1033
|
+
if weighting == "own-share":
|
|
1161
1034
|
_gbd_prtlarea = (
|
|
1162
1035
|
_gbd_step_sz * (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_2_pre) / 3
|
|
1163
1036
|
)
|
|
@@ -1181,7 +1054,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
1181
1054
|
# Points defining boundary to point-of-symmetry
|
|
1182
1055
|
return GuidelinesBoundary(
|
|
1183
1056
|
np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
|
|
1184
|
-
round(float(_gbdry_area_total),
|
|
1057
|
+
round(float(_gbdry_area_total), prec),
|
|
1185
1058
|
)
|
|
1186
1059
|
|
|
1187
1060
|
|
|
@@ -1191,7 +1064,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1191
1064
|
/,
|
|
1192
1065
|
*,
|
|
1193
1066
|
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
1194
|
-
|
|
1067
|
+
prec: int = 5,
|
|
1195
1068
|
) -> GuidelinesBoundary:
|
|
1196
1069
|
"""
|
|
1197
1070
|
Share combinations for the simple average GUPPI boundary with symmetric
|
|
@@ -1239,7 +1112,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1239
1112
|
recapture_spec
|
|
1240
1113
|
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
1241
1114
|
value for both merging firms ("proportional").
|
|
1242
|
-
|
|
1115
|
+
prec
|
|
1243
1116
|
Number of decimal places for rounding returned shares.
|
|
1244
1117
|
|
|
1245
1118
|
Returns
|
|
@@ -1248,18 +1121,9 @@ def shrratio_boundary_xact_avg(
|
|
|
1248
1121
|
|
|
1249
1122
|
"""
|
|
1250
1123
|
|
|
1251
|
-
if _delta_star > 1:
|
|
1252
|
-
raise ValueError(
|
|
1253
|
-
"Invalid combination specified; "
|
|
1254
|
-
"Margin-adjusted benchmark share ratio cannot exceed 1."
|
|
1255
|
-
)
|
|
1256
|
-
|
|
1257
|
-
if recapture_spec not in (_recspecs := ("inside-out", "proportional")):
|
|
1258
|
-
raise ValueError(f"Recapture spec must be one of {_recspecs:!}")
|
|
1259
|
-
|
|
1260
1124
|
_delta_star = mpf(f"{_delta_star}")
|
|
1261
1125
|
_s_mid = _delta_star / (1 + _delta_star)
|
|
1262
|
-
_gbd_step_sz = mp.power(10, -
|
|
1126
|
+
_gbd_step_sz = mp.power(10, -prec)
|
|
1263
1127
|
|
|
1264
1128
|
_gbdry_points_start = np.array([(_s_mid, _s_mid)])
|
|
1265
1129
|
_s_1 = np.array(mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz), np.float64)
|
|
@@ -1296,10 +1160,10 @@ def shrratio_boundary_xact_avg(
|
|
|
1296
1160
|
_nr_t2_s1 = _nr_sqrt_s1sq + _nr_sqrt_s1 + _nr_sqrt_nos1
|
|
1297
1161
|
|
|
1298
1162
|
if not np.isclose( # type: ignore
|
|
1299
|
-
np.einsum("i->", _nr_t2_mdr.astype(np.float64)),
|
|
1300
|
-
np.einsum("i->", _nr_t2_s1.astype(np.float64)),
|
|
1163
|
+
np.einsum("i->", _nr_t2_mdr.astype(np.float64)),
|
|
1164
|
+
np.einsum("i->", _nr_t2_s1.astype(np.float64)),
|
|
1301
1165
|
rtol=0,
|
|
1302
|
-
atol=0.5 *
|
|
1166
|
+
atol=0.5 * prec,
|
|
1303
1167
|
):
|
|
1304
1168
|
raise RuntimeError(
|
|
1305
1169
|
"Calculation of sq. root term in exact average GUPPI"
|
|
@@ -1349,292 +1213,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1349
1213
|
_s_1_pts, _s_2_pts = np.split(_gbdry_points, 2, axis=1)
|
|
1350
1214
|
return GuidelinesBoundary(
|
|
1351
1215
|
np.column_stack((np.array(_s_1_pts), np.array(_s_2_pts))),
|
|
1352
|
-
round(float(_gbdry_area_simpson),
|
|
1353
|
-
)
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
def shrratio_boundary_avg(
|
|
1357
|
-
_delta_star: float = 0.075,
|
|
1358
|
-
_r_val: float = 0.80,
|
|
1359
|
-
/,
|
|
1360
|
-
*,
|
|
1361
|
-
avg_method: Literal["arithmetic", "geometric", "distance"] = "arithmetic",
|
|
1362
|
-
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
1363
|
-
gbd_dps: int = 5,
|
|
1364
|
-
) -> GuidelinesBoundary:
|
|
1365
|
-
"""
|
|
1366
|
-
Share combinations along the average GUPPI boundary, with
|
|
1367
|
-
symmetric merging-firm margins.
|
|
1368
|
-
|
|
1369
|
-
Reimplements the unweighted average and distance estimations from function,
|
|
1370
|
-
`shrratio_boundary_wtd_avg`. This reimplementation
|
|
1371
|
-
is primarifly useful for testing the output of `shrratio_boundary_wtd_avg`
|
|
1372
|
-
as it tests considerably slower.
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
Parameters
|
|
1376
|
-
----------
|
|
1377
|
-
_delta_star
|
|
1378
|
-
Margin-adjusted benchmark share ratio.
|
|
1379
|
-
_r_val
|
|
1380
|
-
Recapture ratio.
|
|
1381
|
-
avg_method
|
|
1382
|
-
Whether "arithmetic", "geometric", or "distance".
|
|
1383
|
-
recapture_spec
|
|
1384
|
-
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
1385
|
-
value for both merging firms ("proportional").
|
|
1386
|
-
gbd_dps
|
|
1387
|
-
Number of decimal places for rounding returned shares.
|
|
1388
|
-
|
|
1389
|
-
Returns
|
|
1390
|
-
-------
|
|
1391
|
-
Array of share-pairs, area under boundary.
|
|
1392
|
-
|
|
1393
|
-
"""
|
|
1394
|
-
|
|
1395
|
-
if _delta_star > 1:
|
|
1396
|
-
raise ValueError(
|
|
1397
|
-
"Invalid combination specified; "
|
|
1398
|
-
"Margin-adjusted benchmark share ratio cannot exceed 1."
|
|
1399
|
-
)
|
|
1400
|
-
|
|
1401
|
-
if avg_method not in (_avgmthds := ("arithmetic", "geometric", "distance")):
|
|
1402
|
-
raise ValueError(
|
|
1403
|
-
f"Averarging method, {f'"{avg_method}"'} is invalid. "
|
|
1404
|
-
f"Must be one of, {_avgmthds!r}."
|
|
1405
|
-
)
|
|
1406
|
-
|
|
1407
|
-
if recapture_spec not in (_recspecs := ("inside-out", "proportional")):
|
|
1408
|
-
raise ValueError(
|
|
1409
|
-
f"Recapture spec, {f'"{recapture_spec}"'} is invalid. "
|
|
1410
|
-
f"Must be one of {_recspecs!r}."
|
|
1411
|
-
)
|
|
1412
|
-
|
|
1413
|
-
_delta_star = mpf(f"{_delta_star}")
|
|
1414
|
-
_s_mid = _delta_star / (1 + _delta_star)
|
|
1415
|
-
|
|
1416
|
-
# initial conditions
|
|
1417
|
-
_s_2 = _s_mid
|
|
1418
|
-
_s_2_oddval = True
|
|
1419
|
-
_s_2_oddsum = 0
|
|
1420
|
-
_s_2_evnsum = 0
|
|
1421
|
-
_gbdry_points = [(_s_mid, _s_mid)]
|
|
1422
|
-
|
|
1423
|
-
# parameters for iteration
|
|
1424
|
-
_gbd_step_sz = mp.power(10, -gbd_dps)
|
|
1425
|
-
for _s_1 in mp.arange(_s_mid, 0, -_gbd_step_sz):
|
|
1426
|
-
_s_1 -= _gbd_step_sz
|
|
1427
|
-
while True:
|
|
1428
|
-
_delta_12 = _s_2 / (1 - _s_1)
|
|
1429
|
-
_delta_21 = (
|
|
1430
|
-
_s_1 / (1 - _s_2)
|
|
1431
|
-
if recapture_spec == "proportional"
|
|
1432
|
-
else _s_1 / (1 - lerp(_s_1, _s_2, _r_val))
|
|
1433
|
-
)
|
|
1434
|
-
|
|
1435
|
-
match avg_method:
|
|
1436
|
-
case "geometric":
|
|
1437
|
-
_delta_test = mp.sqrt(_delta_12 * _delta_21)
|
|
1438
|
-
case "distance":
|
|
1439
|
-
# _delta_test = mp.sqrt(mp.fdiv((_delta_12**2 + _delta_21**2), "2"))
|
|
1440
|
-
_delta_test = mp.sqrt(
|
|
1441
|
-
mp.fdiv(
|
|
1442
|
-
mp.fsum(
|
|
1443
|
-
mp.power(f"{_g}", "2") for _g in (_delta_12, _delta_21)
|
|
1444
|
-
),
|
|
1445
|
-
"2",
|
|
1446
|
-
)
|
|
1447
|
-
)
|
|
1448
|
-
case _:
|
|
1449
|
-
_delta_test = mp.fdiv(_delta_12 + _delta_21, "2")
|
|
1450
|
-
|
|
1451
|
-
if _delta_test < _delta_star:
|
|
1452
|
-
_s_2 += _gbd_step_sz
|
|
1453
|
-
else:
|
|
1454
|
-
break
|
|
1455
|
-
|
|
1456
|
-
_gbdry_points.append((_s_1, _s_2))
|
|
1457
|
-
|
|
1458
|
-
_s_2_oddsum += _s_2 if _s_2_oddval else 0
|
|
1459
|
-
_s_2_evnsum += _s_2 if not _s_2_oddval else 0
|
|
1460
|
-
_s_2_oddval = not _s_2_oddval
|
|
1461
|
-
|
|
1462
|
-
# Starting at _s_id - _gbd_step_sz means _s_1 is not always
|
|
1463
|
-
# an even multiple of _gbd_step_sz
|
|
1464
|
-
_s_intcpt = _s_2
|
|
1465
|
-
|
|
1466
|
-
_gbd_prtlarea = 2 * _gbd_step_sz * (
|
|
1467
|
-
mp.fmul(4, _s_2_oddsum)
|
|
1468
|
-
+ mp.fmul(2, _s_2_evnsum)
|
|
1469
|
-
+ mp.fmul(1, _s_mid + _s_intcpt)
|
|
1470
|
-
) / 3 - mp.power(_s_mid, 2)
|
|
1471
|
-
|
|
1472
|
-
_gbdry_points = np.array(_gbdry_points, np.float64)
|
|
1473
|
-
return GuidelinesBoundary(
|
|
1474
|
-
np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
|
|
1475
|
-
round(float(_gbd_prtlarea), gbd_dps),
|
|
1476
|
-
)
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
def shrratio_boundary_distance(
|
|
1480
|
-
_delta_star: float = 0.075,
|
|
1481
|
-
_r_val: float = 0.80,
|
|
1482
|
-
/,
|
|
1483
|
-
*,
|
|
1484
|
-
avg_method: Literal["arithmetic", "distance"] = "arithmetic",
|
|
1485
|
-
wgtng_policy: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
1486
|
-
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
1487
|
-
gbd_dps: int = 5,
|
|
1488
|
-
) -> GuidelinesBoundary:
|
|
1489
|
-
"""
|
|
1490
|
-
Share combinations for the GUPPI boundaries using various aggregators with
|
|
1491
|
-
symmetric merging-firm margins.
|
|
1492
|
-
|
|
1493
|
-
Reimplements the arithmetic-averages and distance estimations from function,
|
|
1494
|
-
`shrratio_boundary_wtd_avg`but uses the Minkowski-distance function,
|
|
1495
|
-
`scipy.spatial.distance.minkowski` for all aggregators. This reimplementation
|
|
1496
|
-
is useful for testing the output of `shrratio_boundary_wtd_avg`
|
|
1497
|
-
but runs considerably slower.
|
|
1498
|
-
|
|
1499
|
-
Parameters
|
|
1500
|
-
----------
|
|
1501
|
-
_delta_star
|
|
1502
|
-
corollary to GUPPI bound (:math:`\\overline{g} / (m^* \\cdot \\overline{r})`)
|
|
1503
|
-
_r_val
|
|
1504
|
-
recapture ratio
|
|
1505
|
-
avg_method
|
|
1506
|
-
Whether "arithmetic", "geometric", or "distance".
|
|
1507
|
-
wgtng_policy
|
|
1508
|
-
Whether "own-share" or "cross-product-share".
|
|
1509
|
-
recapture_spec
|
|
1510
|
-
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
1511
|
-
value for both merging firms ("proportional").
|
|
1512
|
-
gbd_dps
|
|
1513
|
-
Number of decimal places for rounding returned shares and area.
|
|
1514
|
-
|
|
1515
|
-
Returns
|
|
1516
|
-
-------
|
|
1517
|
-
Array of share-pairs, area under boundary.
|
|
1518
|
-
|
|
1519
|
-
"""
|
|
1520
|
-
|
|
1521
|
-
if _delta_star > 1:
|
|
1522
|
-
raise ValueError(
|
|
1523
|
-
"Margin-adjusted benchmark share ratio, `_delta_star` cannot exceed 1."
|
|
1524
|
-
)
|
|
1525
|
-
|
|
1526
|
-
_delta_star = mpf(f"{_delta_star}")
|
|
1527
|
-
_s_mid = _delta_star / (1 + _delta_star)
|
|
1528
|
-
|
|
1529
|
-
# initial conditions
|
|
1530
|
-
_gbdry_points = [(_s_mid, _s_mid)]
|
|
1531
|
-
_s_1_pre, _s_2_pre = _s_mid, _s_mid
|
|
1532
|
-
_s_2_oddval, _s_2_oddsum, _s_2_evnsum = True, 0, 0
|
|
1533
|
-
|
|
1534
|
-
# parameters for iteration
|
|
1535
|
-
_weights_base = (mpf("0.5"),) * 2
|
|
1536
|
-
_gbd_step_sz = mp.power(10, -gbd_dps)
|
|
1537
|
-
_theta = _gbd_step_sz * (10 if wgtng_policy == "cross-product-share" else 1)
|
|
1538
|
-
for _s_1 in mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz):
|
|
1539
|
-
# The wtd. avg. GUPPI is not always convex to the origin, so we
|
|
1540
|
-
# increment _s_2 after each iteration in which our algorithm
|
|
1541
|
-
# finds (s1, s2) on the boundary
|
|
1542
|
-
_s_2 = _s_2_pre * (1 + _theta)
|
|
1543
|
-
|
|
1544
|
-
if (_s_1 + _s_2) > mpf("0.99875"):
|
|
1545
|
-
# 1: # We lose accuracy at 3-9s and up
|
|
1546
|
-
break
|
|
1547
|
-
|
|
1548
|
-
while True:
|
|
1549
|
-
_de_1 = _s_2 / (1 - _s_1)
|
|
1550
|
-
_de_2 = (
|
|
1551
|
-
_s_1 / (1 - lerp(_s_1, _s_2, _r_val))
|
|
1552
|
-
if recapture_spec == "inside-out"
|
|
1553
|
-
else _s_1 / (1 - _s_2)
|
|
1554
|
-
)
|
|
1555
|
-
|
|
1556
|
-
_weights_i = (
|
|
1557
|
-
(
|
|
1558
|
-
_w1 := mp.fdiv(
|
|
1559
|
-
_s_2 if wgtng_policy == "cross-product-share" else _s_1,
|
|
1560
|
-
_s_1 + _s_2,
|
|
1561
|
-
),
|
|
1562
|
-
1 - _w1,
|
|
1563
|
-
)
|
|
1564
|
-
if wgtng_policy
|
|
1565
|
-
else _weights_base
|
|
1566
|
-
)
|
|
1567
|
-
|
|
1568
|
-
match avg_method:
|
|
1569
|
-
case "arithmetic":
|
|
1570
|
-
_delta_test = distance_function(
|
|
1571
|
-
(_de_1, _de_2), (0.0, 0.0), p=1, w=_weights_i
|
|
1572
|
-
)
|
|
1573
|
-
case "distance":
|
|
1574
|
-
_delta_test = distance_function(
|
|
1575
|
-
(_de_1, _de_2), (0.0, 0.0), p=2, w=_weights_i
|
|
1576
|
-
)
|
|
1577
|
-
|
|
1578
|
-
_test_flag, _incr_decr = (
|
|
1579
|
-
(_delta_test > _delta_star, -1)
|
|
1580
|
-
if wgtng_policy == "cross-product-share"
|
|
1581
|
-
else (_delta_test < _delta_star, 1)
|
|
1582
|
-
)
|
|
1583
|
-
|
|
1584
|
-
if _test_flag:
|
|
1585
|
-
_s_2 += _incr_decr * _gbd_step_sz
|
|
1586
|
-
else:
|
|
1587
|
-
break
|
|
1588
|
-
|
|
1589
|
-
# Build-up boundary points
|
|
1590
|
-
_gbdry_points.append((_s_1, _s_2))
|
|
1591
|
-
|
|
1592
|
-
# Build up area terms
|
|
1593
|
-
_s_2_oddsum += _s_2 if _s_2_oddval else 0
|
|
1594
|
-
_s_2_evnsum += _s_2 if not _s_2_oddval else 0
|
|
1595
|
-
_s_2_oddval = not _s_2_oddval
|
|
1596
|
-
|
|
1597
|
-
# Hold share points
|
|
1598
|
-
_s_2_pre = _s_2
|
|
1599
|
-
_s_1_pre = _s_1
|
|
1600
|
-
|
|
1601
|
-
if _s_2_oddval:
|
|
1602
|
-
_s_2_evnsum -= _s_2_pre
|
|
1603
|
-
else:
|
|
1604
|
-
_s_2_oddsum -= _s_1_pre
|
|
1605
|
-
|
|
1606
|
-
_s_intcpt = _shrratio_boundary_intcpt(
|
|
1607
|
-
_s_1_pre,
|
|
1608
|
-
_delta_star,
|
|
1609
|
-
_r_val,
|
|
1610
|
-
recapture_spec=recapture_spec,
|
|
1611
|
-
avg_method=avg_method,
|
|
1612
|
-
wgtng_policy=wgtng_policy,
|
|
1613
|
-
)
|
|
1614
|
-
|
|
1615
|
-
if wgtng_policy == "own-share":
|
|
1616
|
-
_gbd_prtlarea = (
|
|
1617
|
-
_gbd_step_sz * (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_2_pre) / 3
|
|
1618
|
-
)
|
|
1619
|
-
# Area under boundary
|
|
1620
|
-
_gbdry_area_total = 2 * (_s_1_pre + _gbd_prtlarea) - (
|
|
1621
|
-
mp.power(_s_mid, "2") + mp.power(_s_1_pre, "2")
|
|
1622
|
-
)
|
|
1623
|
-
|
|
1624
|
-
else:
|
|
1625
|
-
_gbd_prtlarea = (
|
|
1626
|
-
_gbd_step_sz * (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_intcpt) / 3
|
|
1627
|
-
)
|
|
1628
|
-
# Area under boundary
|
|
1629
|
-
_gbdry_area_total = 2 * _gbd_prtlarea - mp.power(_s_mid, "2")
|
|
1630
|
-
|
|
1631
|
-
_gbdry_points = np.row_stack((_gbdry_points, (mpf("0.0"), _s_intcpt))).astype(
|
|
1632
|
-
np.float64
|
|
1633
|
-
)
|
|
1634
|
-
# Points defining boundary to point-of-symmetry
|
|
1635
|
-
return GuidelinesBoundary(
|
|
1636
|
-
np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
|
|
1637
|
-
round(float(_gbdry_area_total), gbd_dps),
|
|
1216
|
+
round(float(_gbdry_area_simpson), prec),
|
|
1638
1217
|
)
|
|
1639
1218
|
|
|
1640
1219
|
|
|
@@ -1645,24 +1224,24 @@ def _shrratio_boundary_intcpt(
|
|
|
1645
1224
|
/,
|
|
1646
1225
|
*,
|
|
1647
1226
|
recapture_spec: Literal["inside-out", "proportional"],
|
|
1648
|
-
|
|
1649
|
-
|
|
1227
|
+
agg_method: Literal["arithmetic", "geometric", "distance"],
|
|
1228
|
+
weighting: Literal["cross-product-share", "own-share"] | None,
|
|
1650
1229
|
) -> float:
|
|
1651
|
-
match
|
|
1230
|
+
match weighting:
|
|
1652
1231
|
case "cross-product-share":
|
|
1653
|
-
_s_intcpt = _delta_star
|
|
1232
|
+
_s_intcpt: float = _delta_star
|
|
1654
1233
|
case "own-share":
|
|
1655
1234
|
_s_intcpt = mpf("1.0")
|
|
1656
|
-
case None if
|
|
1235
|
+
case None if agg_method == "distance":
|
|
1657
1236
|
_s_intcpt = _delta_star * mp.sqrt("2")
|
|
1658
|
-
case None if
|
|
1237
|
+
case None if agg_method == "arithmetic" and recapture_spec == "inside-out":
|
|
1659
1238
|
_s_intcpt = mp.fdiv(
|
|
1660
1239
|
mp.fsub(
|
|
1661
1240
|
2 * _delta_star * _r_val + 1, mp.fabs(2 * _delta_star * _r_val - 1)
|
|
1662
1241
|
),
|
|
1663
1242
|
2 * mpf(f"{_r_val}"),
|
|
1664
1243
|
)
|
|
1665
|
-
case None if
|
|
1244
|
+
case None if agg_method == "arithmetic":
|
|
1666
1245
|
_s_intcpt = mp.fsub(_delta_star + 1 / 2, mp.fabs(_delta_star - 1 / 2))
|
|
1667
1246
|
case _:
|
|
1668
1247
|
_s_intcpt = _s_2_pre
|