mergeron 2024.738949.1__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 +194 -400
- mergeron/core/guidelines_boundaries_specialized_functions.py +341 -0
- mergeron/core/pseudorandom_numbers.py +1 -1
- mergeron/examples/concentration_as_diversion.py +97 -83
- 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.1.dist-info → mergeron-2024.738949.6.dist-info}/METADATA +1 -1
- {mergeron-2024.738949.1.dist-info → mergeron-2024.738949.6.dist-info}/RECORD +20 -19
- {mergeron-2024.738949.1.dist-info → mergeron-2024.738949.6.dist-info}/WHEEL +0 -0
|
@@ -5,6 +5,7 @@ with a canvas on which to draw boundaries for Guidelines standards.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import decimal
|
|
8
|
+
from collections.abc import Callable
|
|
8
9
|
from dataclasses import dataclass
|
|
9
10
|
from importlib.metadata import version
|
|
10
11
|
from typing import Any, Literal, TypeAlias
|
|
@@ -13,9 +14,9 @@ import numpy as np
|
|
|
13
14
|
from attrs import define, field
|
|
14
15
|
from mpmath import mp, mpf # type: ignore
|
|
15
16
|
from numpy.typing import NDArray
|
|
16
|
-
from scipy.spatial.distance import minkowski as distance_function
|
|
17
17
|
|
|
18
|
-
from .. import _PKG_NAME # noqa: TID252
|
|
18
|
+
from .. import _PKG_NAME, UPPAggrSelector # noqa: TID252
|
|
19
|
+
from . import UPPBoundarySpec
|
|
19
20
|
|
|
20
21
|
__version__ = version(_PKG_NAME)
|
|
21
22
|
|
|
@@ -27,12 +28,6 @@ HMGPubYear: TypeAlias = Literal[1992, 2010, 2023]
|
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
@dataclass(slots=True, frozen=True)
|
|
30
|
-
class GuidelinesBoundary:
|
|
31
|
-
coordinates: NDArray[np.float64]
|
|
32
|
-
area: float
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@define(slots=True, frozen=True)
|
|
36
31
|
class HMGThresholds:
|
|
37
32
|
delta: float
|
|
38
33
|
rec: float
|
|
@@ -42,6 +37,19 @@ class HMGThresholds:
|
|
|
42
37
|
ipr: float
|
|
43
38
|
|
|
44
39
|
|
|
40
|
+
@dataclass(slots=True, frozen=True)
|
|
41
|
+
class GuidelinesBoundary:
|
|
42
|
+
coordinates: NDArray[np.float64]
|
|
43
|
+
area: float
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass(slots=True, frozen=True)
|
|
47
|
+
class GuidelinesBoundaryCallable:
|
|
48
|
+
boundary_function: Callable[[NDArray[np.float64]], NDArray[np.float64]]
|
|
49
|
+
area: float
|
|
50
|
+
s_naught: float = 0
|
|
51
|
+
|
|
52
|
+
|
|
45
53
|
@define(slots=True, frozen=True)
|
|
46
54
|
class GuidelinesThresholds:
|
|
47
55
|
"""
|
|
@@ -81,7 +89,7 @@ class GuidelinesThresholds:
|
|
|
81
89
|
diversion ratio limit, CMCR, and IPR
|
|
82
90
|
"""
|
|
83
91
|
|
|
84
|
-
def __attrs_post_init__(self, /):
|
|
92
|
+
def __attrs_post_init__(self, /) -> None:
|
|
85
93
|
# In the 2023 Guidlines, the agencies do not define a
|
|
86
94
|
# negative presumption, or safeharbor. Practically speaking,
|
|
87
95
|
# given resource constraints and loss aversion, it is likely
|
|
@@ -278,7 +286,12 @@ def gbd_from_dsf(
|
|
|
278
286
|
|
|
279
287
|
|
|
280
288
|
def critical_shrratio(
|
|
281
|
-
_gbd: float = 0.06,
|
|
289
|
+
_gbd: float = 0.06,
|
|
290
|
+
/,
|
|
291
|
+
*,
|
|
292
|
+
m_star: float = 1.00,
|
|
293
|
+
r_bar: float = 0.80,
|
|
294
|
+
frac: float = 1e-16,
|
|
282
295
|
) -> mpf:
|
|
283
296
|
"""
|
|
284
297
|
Corollary to GUPPI bound.
|
|
@@ -298,7 +311,7 @@ def critical_shrratio(
|
|
|
298
311
|
for given margin and recapture rate.
|
|
299
312
|
|
|
300
313
|
"""
|
|
301
|
-
return mpf(f"{_gbd}") / mp.fmul(f"{m_star}", f"{r_bar}")
|
|
314
|
+
return round_cust(mpf(f"{_gbd}") / mp.fmul(f"{m_star}", f"{r_bar}"), frac=frac)
|
|
302
315
|
|
|
303
316
|
|
|
304
317
|
def shr_from_gbd(
|
|
@@ -371,18 +384,18 @@ def boundary_plot(*, mktshares_plot_flag: bool = True) -> tuple[Any, ...]:
|
|
|
371
384
|
r"\setsansfont{Fira Sans Light}",
|
|
372
385
|
R"\setmonofont[Scale=MatchLowercase,]{Fira Mono}",
|
|
373
386
|
R"\defaultfontfeatures[\rmfamily]{",
|
|
374
|
-
R"
|
|
375
|
-
R"
|
|
376
|
-
R"
|
|
387
|
+
R" Ligatures={TeX, Common},",
|
|
388
|
+
R" Numbers={Proportional, Lining},",
|
|
389
|
+
R" }",
|
|
377
390
|
R"\defaultfontfeatures[\sffamily]{",
|
|
378
|
-
R"
|
|
379
|
-
R"
|
|
380
|
-
R"
|
|
381
|
-
R"
|
|
391
|
+
R" Ligatures={TeX, Common},",
|
|
392
|
+
R" Numbers={Monospaced, Lining},",
|
|
393
|
+
R" LetterSpace=0.50,",
|
|
394
|
+
R" }",
|
|
382
395
|
R"\usepackage[",
|
|
383
|
-
R"
|
|
384
|
-
R"
|
|
385
|
-
R"
|
|
396
|
+
R" activate={true, nocompatibility},",
|
|
397
|
+
R" tracking=true,",
|
|
398
|
+
R" ]{microtype}",
|
|
386
399
|
]),
|
|
387
400
|
})
|
|
388
401
|
|
|
@@ -527,11 +540,11 @@ def dh_area(_dh_val: float = 0.01, /, *, dh_dps: int = 9) -> float:
|
|
|
527
540
|
"""
|
|
528
541
|
|
|
529
542
|
_dh_val = mpf(f"{_dh_val}")
|
|
530
|
-
|
|
531
|
-
_s1_one = 1 - _s1_zero
|
|
543
|
+
_s_naught = (1 - mp.sqrt(1 - 2 * _dh_val)) / 2
|
|
532
544
|
|
|
533
545
|
return round(
|
|
534
|
-
float(
|
|
546
|
+
float(_s_naught + (_dh_val / 2) * (mp.ln(1 - _s_naught) - mp.ln(_s_naught))),
|
|
547
|
+
dh_dps,
|
|
535
548
|
)
|
|
536
549
|
|
|
537
550
|
|
|
@@ -557,17 +570,18 @@ def dh_area_quad(_dh_val: float = 0.01, /, *, dh_dps: int = 9) -> float:
|
|
|
557
570
|
"""
|
|
558
571
|
|
|
559
572
|
_dh_val = mpf(f"{_dh_val}")
|
|
560
|
-
|
|
561
|
-
_s1_one = 1 - _s1_zero
|
|
573
|
+
_s_naught = (1 - mp.sqrt(1 - 2 * _dh_val)) / 2
|
|
562
574
|
|
|
563
575
|
return round(
|
|
564
|
-
float(
|
|
576
|
+
float(
|
|
577
|
+
_s_naught + mp.quad(lambda x: _dh_val / (2 * x), [_s_naught, 1 - _s_naught])
|
|
578
|
+
),
|
|
565
579
|
dh_dps,
|
|
566
580
|
)
|
|
567
581
|
|
|
568
582
|
|
|
569
583
|
def delta_hhi_boundary(
|
|
570
|
-
_dh_val: float = 0.01, /, *,
|
|
584
|
+
_dh_val: float = 0.01, /, *, prec: int = 5
|
|
571
585
|
) -> GuidelinesBoundary:
|
|
572
586
|
"""
|
|
573
587
|
Generate the list of share combination on the ΔHHI boundary.
|
|
@@ -586,19 +600,16 @@ def delta_hhi_boundary(
|
|
|
586
600
|
"""
|
|
587
601
|
|
|
588
602
|
_dh_val = mpf(f"{_dh_val}")
|
|
589
|
-
|
|
590
|
-
_s1_one = 1 - _s1_zero
|
|
591
|
-
|
|
603
|
+
_s_naught = 1 / 2 * (1 - mp.sqrt(1 - 2 * _dh_val))
|
|
592
604
|
_s_mid = mp.sqrt(_dh_val / 2)
|
|
593
605
|
|
|
594
606
|
_dh_step_sz = mp.power(10, -6)
|
|
595
|
-
_s_1 = np.array(mp.arange(_s_mid,
|
|
607
|
+
_s_1 = np.array(mp.arange(_s_mid, _s_naught - mp.eps, -_dh_step_sz))
|
|
596
608
|
_s_2 = _dh_val / (2 * _s_1)
|
|
597
609
|
|
|
598
610
|
# Boundary points
|
|
599
611
|
_dh_half = np.row_stack((
|
|
600
612
|
np.column_stack((_s_1, _s_2)),
|
|
601
|
-
np.array([(_s1_zero, _s1_one)]),
|
|
602
613
|
np.array([(mpf("0.0"), mpf("1.0"))]),
|
|
603
614
|
))
|
|
604
615
|
_dh_bdry_pts = np.row_stack((np.flip(_dh_half, 0), np.flip(_dh_half[1:], 1)))
|
|
@@ -609,7 +620,7 @@ def delta_hhi_boundary(
|
|
|
609
620
|
np.array(_s_1_pts, np.float64),
|
|
610
621
|
np.array(_s_2_pts, np.float64),
|
|
611
622
|
)),
|
|
612
|
-
dh_area(_dh_val, dh_dps=
|
|
623
|
+
dh_area(_dh_val, dh_dps=prec),
|
|
613
624
|
)
|
|
614
625
|
|
|
615
626
|
|
|
@@ -680,8 +691,60 @@ def hhi_pre_contrib_boundary(
|
|
|
680
691
|
)
|
|
681
692
|
|
|
682
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
|
+
|
|
683
746
|
def shrratio_boundary_max(
|
|
684
|
-
_delta_star: float = 0.075, _r_val: float = 0.80, /, *,
|
|
747
|
+
_delta_star: float = 0.075, _r_val: float = 0.80, /, *, prec: int = 10
|
|
685
748
|
) -> GuidelinesBoundary:
|
|
686
749
|
"""
|
|
687
750
|
Share combinations on the minimum GUPPI boundary with symmetric
|
|
@@ -693,7 +756,7 @@ def shrratio_boundary_max(
|
|
|
693
756
|
Margin-adjusted benchmark share ratio.
|
|
694
757
|
_r_val
|
|
695
758
|
Recapture ratio.
|
|
696
|
-
|
|
759
|
+
prec
|
|
697
760
|
Number of decimal places for rounding returned shares.
|
|
698
761
|
|
|
699
762
|
Returns
|
|
@@ -702,12 +765,6 @@ def shrratio_boundary_max(
|
|
|
702
765
|
|
|
703
766
|
"""
|
|
704
767
|
|
|
705
|
-
if _delta_star > 1:
|
|
706
|
-
raise ValueError(
|
|
707
|
-
"Invalid combination specified; "
|
|
708
|
-
"Margin-adjusted benchmark share ratio cannot exceed 1."
|
|
709
|
-
)
|
|
710
|
-
|
|
711
768
|
# _r_val is not needed for max boundary, but is specified for consistency
|
|
712
769
|
# of function call with other shrratio_mgnsym_boundary functions
|
|
713
770
|
del _r_val
|
|
@@ -722,7 +779,7 @@ def shrratio_boundary_max(
|
|
|
722
779
|
np.array(_s1_pts, np.float64),
|
|
723
780
|
np.array(_s1_pts[::-1], np.float64),
|
|
724
781
|
)),
|
|
725
|
-
round(float(_s_intcpt * _s_mid),
|
|
782
|
+
round(float(_s_intcpt * _s_mid), prec), # simplified calculation
|
|
726
783
|
)
|
|
727
784
|
|
|
728
785
|
|
|
@@ -732,7 +789,7 @@ def shrratio_boundary_min(
|
|
|
732
789
|
/,
|
|
733
790
|
*,
|
|
734
791
|
recapture_spec: str = "inside-out",
|
|
735
|
-
|
|
792
|
+
prec: int = 10,
|
|
736
793
|
) -> GuidelinesBoundary:
|
|
737
794
|
"""
|
|
738
795
|
Share combinations on the minimum GUPPI boundary, with symmetric
|
|
@@ -754,7 +811,7 @@ def shrratio_boundary_min(
|
|
|
754
811
|
recapture_spec
|
|
755
812
|
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
756
813
|
value for both merging firms ("proportional").
|
|
757
|
-
|
|
814
|
+
prec
|
|
758
815
|
Number of decimal places for rounding returned shares.
|
|
759
816
|
|
|
760
817
|
Returns
|
|
@@ -763,14 +820,6 @@ def shrratio_boundary_min(
|
|
|
763
820
|
|
|
764
821
|
"""
|
|
765
822
|
|
|
766
|
-
if _delta_star > 1:
|
|
767
|
-
raise ValueError("Margin-adjusted benchmark share ratio cannot exceed 1.")
|
|
768
|
-
|
|
769
|
-
if recapture_spec not in (_recspecs := ("inside-out", "proportional")):
|
|
770
|
-
raise ValueError(
|
|
771
|
-
f"Recapture_spec value, {f'"{recapture_spec}"'} not in {_recspecs!r}"
|
|
772
|
-
)
|
|
773
|
-
|
|
774
823
|
_delta_star = mpf(f"{_delta_star}")
|
|
775
824
|
_s_intcpt = mpf("1.00")
|
|
776
825
|
_s_mid = _delta_star / (1 + _delta_star)
|
|
@@ -797,7 +846,7 @@ def shrratio_boundary_min(
|
|
|
797
846
|
_s1_pts, _gbd_area = np.array((0, _s_mid, _s_intcpt), np.float64), _s_mid
|
|
798
847
|
|
|
799
848
|
return GuidelinesBoundary(
|
|
800
|
-
np.column_stack((_s1_pts, _s1_pts[::-1])), round(float(_gbd_area),
|
|
849
|
+
np.column_stack((_s1_pts, _s1_pts[::-1])), round(float(_gbd_area), prec)
|
|
801
850
|
)
|
|
802
851
|
|
|
803
852
|
|
|
@@ -806,25 +855,45 @@ def shrratio_boundary_wtd_avg(
|
|
|
806
855
|
_r_val: float = 0.80,
|
|
807
856
|
/,
|
|
808
857
|
*,
|
|
809
|
-
|
|
810
|
-
|
|
858
|
+
agg_method: Literal["arithmetic", "geometric", "distance"] = "arithmetic",
|
|
859
|
+
weighting: Literal["own-share", "cross-product-share"] | None = "own-share",
|
|
811
860
|
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
812
|
-
|
|
861
|
+
prec: int = 5,
|
|
813
862
|
) -> GuidelinesBoundary:
|
|
814
863
|
"""
|
|
815
864
|
Share combinations for the share-weighted average GUPPI boundary with symmetric
|
|
816
865
|
merging-firm margins.
|
|
817
866
|
|
|
867
|
+
Parameters
|
|
868
|
+
----------
|
|
869
|
+
_delta_star
|
|
870
|
+
corollary to GUPPI bound (:math:`\\overline{g} / (m^* \\cdot \\overline{r})`)
|
|
871
|
+
_r_val
|
|
872
|
+
recapture ratio
|
|
873
|
+
agg_method
|
|
874
|
+
Whether "arithmetic", "geometric", or "distance".
|
|
875
|
+
weighting
|
|
876
|
+
Whether "own-share" or "cross-product-share" (or None for simple, unweighted average).
|
|
877
|
+
recapture_spec
|
|
878
|
+
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
879
|
+
value for both merging firms ("proportional").
|
|
880
|
+
prec
|
|
881
|
+
Number of decimal places for rounding returned shares and area.
|
|
882
|
+
|
|
883
|
+
Returns
|
|
884
|
+
-------
|
|
885
|
+
Array of share-pairs, area under boundary.
|
|
886
|
+
|
|
818
887
|
Notes
|
|
819
888
|
-----
|
|
820
889
|
An analytical expression for the share-weighted arithmetic mean boundary
|
|
821
890
|
is derived and plotted from y-intercept to the ray of symmetry as follows::
|
|
822
891
|
|
|
823
892
|
from sympy import plot as symplot, solve, symbols
|
|
824
|
-
s_1, s_2
|
|
893
|
+
s_1, s_2 = symbols("s_1 s_2", positive=True)
|
|
825
894
|
|
|
826
895
|
g_val, r_val, m_val = 0.06, 0.80, 0.30
|
|
827
|
-
|
|
896
|
+
delta_star = g_val / (r_val * m_val)
|
|
828
897
|
|
|
829
898
|
# recapture_spec == "inside-out"
|
|
830
899
|
oswag = solve(
|
|
@@ -834,7 +903,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
834
903
|
s_2
|
|
835
904
|
)[0]
|
|
836
905
|
symplot(
|
|
837
|
-
oswag
|
|
906
|
+
oswag,
|
|
838
907
|
(s_1, 0., d_hat / (1 + d_hat)),
|
|
839
908
|
ylabel=s_2
|
|
840
909
|
)
|
|
@@ -846,7 +915,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
846
915
|
s_2
|
|
847
916
|
)[1]
|
|
848
917
|
symplot(
|
|
849
|
-
cpwag
|
|
918
|
+
cpwag,
|
|
850
919
|
(s_1, 0., d_hat / (1 + d_hat)),
|
|
851
920
|
ylabel=s_2
|
|
852
921
|
)
|
|
@@ -859,7 +928,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
859
928
|
s_2
|
|
860
929
|
)[0]
|
|
861
930
|
symplot(
|
|
862
|
-
oswag
|
|
931
|
+
oswag,
|
|
863
932
|
(s_1, 0., d_hat / (1 + d_hat)),
|
|
864
933
|
ylabel=s_2
|
|
865
934
|
)
|
|
@@ -871,38 +940,14 @@ def shrratio_boundary_wtd_avg(
|
|
|
871
940
|
s_2
|
|
872
941
|
)[1]
|
|
873
942
|
symplot(
|
|
874
|
-
cpswag
|
|
943
|
+
cpswag,
|
|
875
944
|
(s_1, 0.0, d_hat / (1 + d_hat)),
|
|
876
945
|
ylabel=s_2
|
|
877
946
|
)
|
|
878
947
|
|
|
879
|
-
Parameters
|
|
880
|
-
----------
|
|
881
|
-
_delta_star
|
|
882
|
-
corollary to GUPPI bound (:math:`\\overline{g} / (m^* \\cdot \\overline{r})`)
|
|
883
|
-
_r_val
|
|
884
|
-
recapture ratio
|
|
885
|
-
avg_method
|
|
886
|
-
Whether "arithmetic", "geometric", or "distance".
|
|
887
|
-
wgtng_policy
|
|
888
|
-
Whether "own-share" or "cross-product-share".
|
|
889
|
-
recapture_spec
|
|
890
|
-
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
891
|
-
value for both merging firms ("proportional").
|
|
892
|
-
gbd_dps
|
|
893
|
-
Number of decimal places for rounding returned shares and area.
|
|
894
|
-
|
|
895
|
-
Returns
|
|
896
|
-
-------
|
|
897
|
-
Array of share-pairs, area under boundary.
|
|
898
948
|
|
|
899
949
|
"""
|
|
900
950
|
|
|
901
|
-
if _delta_star > 1:
|
|
902
|
-
raise ValueError(
|
|
903
|
-
"Margin-adjusted benchmark share ratio, `_delta_star` cannot exceed 1."
|
|
904
|
-
)
|
|
905
|
-
|
|
906
951
|
_delta_star = mpf(f"{_delta_star}")
|
|
907
952
|
_s_mid = _delta_star / (1 + _delta_star)
|
|
908
953
|
|
|
@@ -912,8 +957,8 @@ def shrratio_boundary_wtd_avg(
|
|
|
912
957
|
_s_2_oddval, _s_2_oddsum, _s_2_evnsum = True, 0, 0
|
|
913
958
|
|
|
914
959
|
# parameters for iteration
|
|
915
|
-
_gbd_step_sz = mp.power(10, -
|
|
916
|
-
_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)
|
|
917
962
|
for _s_1 in mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz):
|
|
918
963
|
# The wtd. avg. GUPPI is not always convex to the origin, so we
|
|
919
964
|
# increment _s_2 after each iteration in which our algorithm
|
|
@@ -921,7 +966,7 @@ def shrratio_boundary_wtd_avg(
|
|
|
921
966
|
_s_2 = _s_2_pre * (1 + _theta)
|
|
922
967
|
|
|
923
968
|
if (_s_1 + _s_2) > mpf("0.99875"):
|
|
924
|
-
#
|
|
969
|
+
# Loss of accuracy at 3-9s and up
|
|
925
970
|
break
|
|
926
971
|
|
|
927
972
|
while True:
|
|
@@ -934,13 +979,13 @@ def shrratio_boundary_wtd_avg(
|
|
|
934
979
|
|
|
935
980
|
_r = (
|
|
936
981
|
mp.fdiv(
|
|
937
|
-
_s_1 if
|
|
982
|
+
_s_1 if weighting == "cross-product-share" else _s_2, _s_1 + _s_2
|
|
938
983
|
)
|
|
939
|
-
if
|
|
984
|
+
if weighting
|
|
940
985
|
else 0.5
|
|
941
986
|
)
|
|
942
987
|
|
|
943
|
-
match
|
|
988
|
+
match agg_method:
|
|
944
989
|
case "geometric":
|
|
945
990
|
_delta_test = mp.expm1(lerp(mp.log1p(_de_1), mp.log1p(_de_2), _r))
|
|
946
991
|
case "distance":
|
|
@@ -948,10 +993,11 @@ def shrratio_boundary_wtd_avg(
|
|
|
948
993
|
case _:
|
|
949
994
|
_delta_test = lerp(_de_1, _de_2, _r)
|
|
950
995
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
996
|
+
_test_flag, _incr_decr = (
|
|
997
|
+
(_delta_test > _delta_star, -1)
|
|
998
|
+
if weighting == "cross-product-share"
|
|
999
|
+
else (_delta_test < _delta_star, 1)
|
|
1000
|
+
)
|
|
955
1001
|
|
|
956
1002
|
if _test_flag:
|
|
957
1003
|
_s_2 += _incr_decr * _gbd_step_sz
|
|
@@ -970,35 +1016,45 @@ def shrratio_boundary_wtd_avg(
|
|
|
970
1016
|
_s_2_pre = _s_2
|
|
971
1017
|
_s_1_pre = _s_1
|
|
972
1018
|
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1019
|
+
if _s_2_oddval:
|
|
1020
|
+
_s_2_evnsum -= _s_2_pre
|
|
1021
|
+
else:
|
|
1022
|
+
_s_2_oddsum -= _s_1_pre
|
|
1023
|
+
|
|
1024
|
+
_s_intcpt = _shrratio_boundary_intcpt(
|
|
1025
|
+
_s_1_pre,
|
|
1026
|
+
_delta_star,
|
|
1027
|
+
_r_val,
|
|
1028
|
+
recapture_spec=recapture_spec,
|
|
1029
|
+
agg_method=agg_method,
|
|
1030
|
+
weighting=weighting,
|
|
980
1031
|
)
|
|
981
1032
|
|
|
982
|
-
|
|
983
|
-
|
|
1033
|
+
if weighting == "own-share":
|
|
1034
|
+
_gbd_prtlarea = (
|
|
1035
|
+
_gbd_step_sz * (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_2_pre) / 3
|
|
1036
|
+
)
|
|
1037
|
+
# Area under boundary
|
|
1038
|
+
_gbdry_area_total = float(
|
|
1039
|
+
2 * (_s_1_pre + _gbd_prtlarea)
|
|
1040
|
+
- (mp.power(_s_mid, "2") + mp.power(_s_1_pre, "2"))
|
|
1041
|
+
)
|
|
984
1042
|
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
_s_intcpt
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
_s_intcpt = _delta_star * mp.sqrt("2")
|
|
992
|
-
case _:
|
|
993
|
-
_s_intcpt = _s_2_pre
|
|
1043
|
+
else:
|
|
1044
|
+
_gbd_prtlarea = (
|
|
1045
|
+
_gbd_step_sz * (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_intcpt) / 3
|
|
1046
|
+
)
|
|
1047
|
+
# Area under boundary
|
|
1048
|
+
_gbdry_area_total = float(2 * _gbd_prtlarea - mp.power(_s_mid, "2"))
|
|
994
1049
|
|
|
995
1050
|
_gbdry_points = np.row_stack((_gbdry_points, (mpf("0.0"), _s_intcpt))).astype(
|
|
996
1051
|
np.float64
|
|
997
1052
|
)
|
|
1053
|
+
|
|
998
1054
|
# Points defining boundary to point-of-symmetry
|
|
999
1055
|
return GuidelinesBoundary(
|
|
1000
1056
|
np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
|
|
1001
|
-
round(float(_gbdry_area_total),
|
|
1057
|
+
round(float(_gbdry_area_total), prec),
|
|
1002
1058
|
)
|
|
1003
1059
|
|
|
1004
1060
|
|
|
@@ -1008,7 +1064,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1008
1064
|
/,
|
|
1009
1065
|
*,
|
|
1010
1066
|
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
1011
|
-
|
|
1067
|
+
prec: int = 5,
|
|
1012
1068
|
) -> GuidelinesBoundary:
|
|
1013
1069
|
"""
|
|
1014
1070
|
Share combinations for the simple average GUPPI boundary with symmetric
|
|
@@ -1056,7 +1112,7 @@ def shrratio_boundary_xact_avg(
|
|
|
1056
1112
|
recapture_spec
|
|
1057
1113
|
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
1058
1114
|
value for both merging firms ("proportional").
|
|
1059
|
-
|
|
1115
|
+
prec
|
|
1060
1116
|
Number of decimal places for rounding returned shares.
|
|
1061
1117
|
|
|
1062
1118
|
Returns
|
|
@@ -1065,18 +1121,9 @@ def shrratio_boundary_xact_avg(
|
|
|
1065
1121
|
|
|
1066
1122
|
"""
|
|
1067
1123
|
|
|
1068
|
-
if _delta_star > 1:
|
|
1069
|
-
raise ValueError(
|
|
1070
|
-
"Invalid combination specified; "
|
|
1071
|
-
"Margin-adjusted benchmark share ratio cannot exceed 1."
|
|
1072
|
-
)
|
|
1073
|
-
|
|
1074
|
-
if recapture_spec not in (_recspecs := ("inside-out", "proportional")):
|
|
1075
|
-
raise ValueError(f"Recapture spec must be one of {_recspecs:!}")
|
|
1076
|
-
|
|
1077
1124
|
_delta_star = mpf(f"{_delta_star}")
|
|
1078
1125
|
_s_mid = _delta_star / (1 + _delta_star)
|
|
1079
|
-
_gbd_step_sz = mp.power(10, -
|
|
1126
|
+
_gbd_step_sz = mp.power(10, -prec)
|
|
1080
1127
|
|
|
1081
1128
|
_gbdry_points_start = np.array([(_s_mid, _s_mid)])
|
|
1082
1129
|
_s_1 = np.array(mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz), np.float64)
|
|
@@ -1113,10 +1160,10 @@ def shrratio_boundary_xact_avg(
|
|
|
1113
1160
|
_nr_t2_s1 = _nr_sqrt_s1sq + _nr_sqrt_s1 + _nr_sqrt_nos1
|
|
1114
1161
|
|
|
1115
1162
|
if not np.isclose( # type: ignore
|
|
1116
|
-
np.einsum("i->", _nr_t2_mdr.astype(np.float64)),
|
|
1117
|
-
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)),
|
|
1118
1165
|
rtol=0,
|
|
1119
|
-
atol=0.5 *
|
|
1166
|
+
atol=0.5 * prec,
|
|
1120
1167
|
):
|
|
1121
1168
|
raise RuntimeError(
|
|
1122
1169
|
"Calculation of sq. root term in exact average GUPPI"
|
|
@@ -1166,290 +1213,37 @@ def shrratio_boundary_xact_avg(
|
|
|
1166
1213
|
_s_1_pts, _s_2_pts = np.split(_gbdry_points, 2, axis=1)
|
|
1167
1214
|
return GuidelinesBoundary(
|
|
1168
1215
|
np.column_stack((np.array(_s_1_pts), np.array(_s_2_pts))),
|
|
1169
|
-
round(float(_gbdry_area_simpson),
|
|
1170
|
-
)
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
def shrratio_boundary_avg(
|
|
1174
|
-
_delta_star: float = 0.075,
|
|
1175
|
-
_r_val: float = 0.80,
|
|
1176
|
-
/,
|
|
1177
|
-
*,
|
|
1178
|
-
avg_method: Literal["arithmetic", "geometric", "distance"] = "arithmetic",
|
|
1179
|
-
recapture_spec: Literal["inside-out", "proportional"] = "inside-out",
|
|
1180
|
-
gbd_dps: int = 5,
|
|
1181
|
-
) -> GuidelinesBoundary:
|
|
1182
|
-
"""
|
|
1183
|
-
Share combinations along the average GUPPI boundary, with
|
|
1184
|
-
symmetric merging-firm margins.
|
|
1185
|
-
|
|
1186
|
-
Reimplements the unweighted average and distance estimations from function,
|
|
1187
|
-
`shrratio_boundary_wtd_avg`. This reimplementation
|
|
1188
|
-
is primarifly useful for testing the output of `shrratio_boundary_wtd_avg`
|
|
1189
|
-
as it tests considerably slower.
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
Parameters
|
|
1193
|
-
----------
|
|
1194
|
-
_delta_star
|
|
1195
|
-
Margin-adjusted benchmark share ratio.
|
|
1196
|
-
_r_val
|
|
1197
|
-
Recapture ratio.
|
|
1198
|
-
avg_method
|
|
1199
|
-
Whether "arithmetic", "geometric", or "distance".
|
|
1200
|
-
recapture_spec
|
|
1201
|
-
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
1202
|
-
value for both merging firms ("proportional").
|
|
1203
|
-
gbd_dps
|
|
1204
|
-
Number of decimal places for rounding returned shares.
|
|
1205
|
-
|
|
1206
|
-
Returns
|
|
1207
|
-
-------
|
|
1208
|
-
Array of share-pairs, area under boundary.
|
|
1209
|
-
|
|
1210
|
-
"""
|
|
1211
|
-
|
|
1212
|
-
if _delta_star > 1:
|
|
1213
|
-
raise ValueError(
|
|
1214
|
-
"Invalid combination specified; "
|
|
1215
|
-
"Margin-adjusted benchmark share ratio cannot exceed 1."
|
|
1216
|
-
)
|
|
1217
|
-
|
|
1218
|
-
if avg_method not in (_avgmthds := ("arithmetic", "geometric", "distance")):
|
|
1219
|
-
raise ValueError(
|
|
1220
|
-
f"Averarging method, {f'"{avg_method}"'} is invalid. "
|
|
1221
|
-
f"Must be one of, {_avgmthds!r}."
|
|
1222
|
-
)
|
|
1223
|
-
|
|
1224
|
-
if recapture_spec not in (_recspecs := ("inside-out", "proportional")):
|
|
1225
|
-
raise ValueError(
|
|
1226
|
-
f"Recapture spec, {f'"{recapture_spec}"'} is invalid. "
|
|
1227
|
-
f"Must be one of {_recspecs!r}."
|
|
1228
|
-
)
|
|
1229
|
-
|
|
1230
|
-
_delta_star = mpf(f"{_delta_star}")
|
|
1231
|
-
_s_mid = _delta_star / (1 + _delta_star)
|
|
1232
|
-
|
|
1233
|
-
# initial conditions
|
|
1234
|
-
_s_2 = _s_mid
|
|
1235
|
-
_s_2_oddval = True
|
|
1236
|
-
_s_2_oddsum = 0
|
|
1237
|
-
_s_2_evnsum = 0
|
|
1238
|
-
_gbdry_points = [(_s_mid, _s_mid)]
|
|
1239
|
-
|
|
1240
|
-
# parameters for iteration
|
|
1241
|
-
_gbd_step_sz = mp.power(10, -gbd_dps)
|
|
1242
|
-
for _s_1 in mp.arange(_s_mid, 0, -_gbd_step_sz):
|
|
1243
|
-
_s_1 -= _gbd_step_sz
|
|
1244
|
-
while True:
|
|
1245
|
-
_delta_12 = _s_2 / (1 - _s_1)
|
|
1246
|
-
_delta_21 = (
|
|
1247
|
-
_s_1 / (1 - _s_2)
|
|
1248
|
-
if recapture_spec == "proportional"
|
|
1249
|
-
else _s_1 / (1 - lerp(_s_1, _s_2, _r_val))
|
|
1250
|
-
)
|
|
1251
|
-
|
|
1252
|
-
match avg_method:
|
|
1253
|
-
case "geometric":
|
|
1254
|
-
_delta_test = mp.sqrt(_delta_12 * _delta_21)
|
|
1255
|
-
case "distance":
|
|
1256
|
-
# _delta_test = mp.sqrt(mp.fdiv((_delta_12**2 + _delta_21**2), "2"))
|
|
1257
|
-
_delta_test = mp.sqrt(
|
|
1258
|
-
mp.fdiv(
|
|
1259
|
-
mp.fsum(
|
|
1260
|
-
mp.power(f"{_g}", "2") for _g in (_delta_12, _delta_21)
|
|
1261
|
-
),
|
|
1262
|
-
"2",
|
|
1263
|
-
)
|
|
1264
|
-
)
|
|
1265
|
-
case _:
|
|
1266
|
-
_delta_test = mp.fdiv(_delta_12 + _delta_21, "2")
|
|
1267
|
-
|
|
1268
|
-
if _delta_test < _delta_star:
|
|
1269
|
-
_s_2 += _gbd_step_sz
|
|
1270
|
-
else:
|
|
1271
|
-
break
|
|
1272
|
-
|
|
1273
|
-
_gbdry_points.append((_s_1, _s_2))
|
|
1274
|
-
|
|
1275
|
-
_s_2_oddsum += _s_2 if _s_2_oddval else 0
|
|
1276
|
-
_s_2_evnsum += _s_2 if not _s_2_oddval else 0
|
|
1277
|
-
_s_2_oddval = not _s_2_oddval
|
|
1278
|
-
|
|
1279
|
-
# Starting at _s_id - _gbd_step_sz means _s_1 is not always
|
|
1280
|
-
# an even multiple of _gbd_step_sz
|
|
1281
|
-
_s_intcpt = _s_2
|
|
1282
|
-
|
|
1283
|
-
_gbd_prtlarea = 2 * _gbd_step_sz * (
|
|
1284
|
-
mp.fmul(4 / 3, _s_2_oddsum)
|
|
1285
|
-
+ mp.fmul(2 / 3, _s_2_evnsum)
|
|
1286
|
-
+ mp.fmul(1 / 3, _s_mid + _s_intcpt)
|
|
1287
|
-
) - mp.power(_s_mid, 2)
|
|
1288
|
-
|
|
1289
|
-
_gbdry_points = np.array(_gbdry_points, np.float64)
|
|
1290
|
-
return GuidelinesBoundary(
|
|
1291
|
-
np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
|
|
1292
|
-
round(float(_gbd_prtlarea), gbd_dps),
|
|
1216
|
+
round(float(_gbdry_area_simpson), prec),
|
|
1293
1217
|
)
|
|
1294
1218
|
|
|
1295
1219
|
|
|
1296
|
-
def
|
|
1297
|
-
|
|
1298
|
-
|
|
1220
|
+
def _shrratio_boundary_intcpt(
|
|
1221
|
+
_s_2_pre: float,
|
|
1222
|
+
_delta_star: mpf,
|
|
1223
|
+
_r_val: mpf,
|
|
1299
1224
|
/,
|
|
1300
1225
|
*,
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
"""
|
|
1307
|
-
Share combinations for the GUPPI boundaries using various aggregators with
|
|
1308
|
-
symmetric merging-firm margins.
|
|
1309
|
-
|
|
1310
|
-
Reimplements the arithmetic-averages and distance estimations from function,
|
|
1311
|
-
`shrratio_boundary_wtd_avg`but uses the Minkowski-distance function,
|
|
1312
|
-
`scipy.spatial.distance.minkowski` for all aggregators. This reimplementation
|
|
1313
|
-
is primarifly useful for testing the output of `shrratio_boundary_wtd_avg`
|
|
1314
|
-
as it tests considerably slower.
|
|
1315
|
-
|
|
1316
|
-
Parameters
|
|
1317
|
-
----------
|
|
1318
|
-
_delta_star
|
|
1319
|
-
corollary to GUPPI bound (:math:`\\overline{g} / (m^* \\cdot \\overline{r})`)
|
|
1320
|
-
_r_val
|
|
1321
|
-
recapture ratio
|
|
1322
|
-
avg_method
|
|
1323
|
-
Whether "arithmetic", "geometric", or "distance".
|
|
1324
|
-
wgtng_policy
|
|
1325
|
-
Whether "own-share" or "cross-product-share".
|
|
1326
|
-
recapture_spec
|
|
1327
|
-
Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
|
|
1328
|
-
value for both merging firms ("proportional").
|
|
1329
|
-
gbd_dps
|
|
1330
|
-
Number of decimal places for rounding returned shares and area.
|
|
1331
|
-
|
|
1332
|
-
Returns
|
|
1333
|
-
-------
|
|
1334
|
-
Array of share-pairs, area under boundary.
|
|
1335
|
-
|
|
1336
|
-
"""
|
|
1337
|
-
|
|
1338
|
-
if _delta_star > 1:
|
|
1339
|
-
raise ValueError(
|
|
1340
|
-
"Margin-adjusted benchmark share ratio, `_delta_star` cannot exceed 1."
|
|
1341
|
-
)
|
|
1342
|
-
|
|
1343
|
-
_delta_star = mpf(f"{_delta_star}")
|
|
1344
|
-
_s_mid = _delta_star / (1 + _delta_star)
|
|
1345
|
-
|
|
1346
|
-
# initial conditions
|
|
1347
|
-
_gbdry_points = [(_s_mid, _s_mid)]
|
|
1348
|
-
_s_1_pre, _s_2_pre = _s_mid, _s_mid
|
|
1349
|
-
_s_2_oddval, _s_2_oddsum, _s_2_evnsum = True, 0, 0
|
|
1350
|
-
|
|
1351
|
-
# parameters for iteration
|
|
1352
|
-
_weights_base = (mpf("0.5"),) * 2
|
|
1353
|
-
_gbd_step_sz = mp.power(10, -gbd_dps)
|
|
1354
|
-
_theta = _gbd_step_sz * (10 if wgtng_policy == "cross-product-share" else 1)
|
|
1355
|
-
for _s_1 in mp.arange(_s_mid - _gbd_step_sz, 0, -_gbd_step_sz):
|
|
1356
|
-
# The wtd. avg. GUPPI is not always convex to the origin, so we
|
|
1357
|
-
# increment _s_2 after each iteration in which our algorithm
|
|
1358
|
-
# finds (s1, s2) on the boundary
|
|
1359
|
-
_s_2 = _s_2_pre * (1 + _theta)
|
|
1360
|
-
|
|
1361
|
-
if (_s_1 + _s_2) > mpf("0.99875"):
|
|
1362
|
-
# 1: # We lose accuracy at 3-9s and up
|
|
1363
|
-
break
|
|
1364
|
-
|
|
1365
|
-
while True:
|
|
1366
|
-
_de_1 = _s_2 / (1 - _s_1)
|
|
1367
|
-
_de_2 = (
|
|
1368
|
-
_s_1 / (1 - lerp(_s_1, _s_2, _r_val))
|
|
1369
|
-
if recapture_spec == "inside-out"
|
|
1370
|
-
else _s_1 / (1 - _s_2)
|
|
1371
|
-
)
|
|
1372
|
-
|
|
1373
|
-
_weights_i = (
|
|
1374
|
-
(
|
|
1375
|
-
_w1 := mp.fdiv(
|
|
1376
|
-
_s_2 if wgtng_policy == "cross-product-share" else _s_1,
|
|
1377
|
-
_s_1 + _s_2,
|
|
1378
|
-
),
|
|
1379
|
-
1 - _w1,
|
|
1380
|
-
)
|
|
1381
|
-
if wgtng_policy
|
|
1382
|
-
else _weights_base
|
|
1383
|
-
)
|
|
1384
|
-
|
|
1385
|
-
match avg_method:
|
|
1386
|
-
case "arithmetic":
|
|
1387
|
-
_delta_test = distance_function(
|
|
1388
|
-
(_de_1, _de_2), (0.0, 0.0), p=1, w=_weights_i
|
|
1389
|
-
)
|
|
1390
|
-
case "distance":
|
|
1391
|
-
_delta_test = distance_function(
|
|
1392
|
-
(_de_1, _de_2), (0.0, 0.0), p=2, w=_weights_i
|
|
1393
|
-
)
|
|
1394
|
-
|
|
1395
|
-
if wgtng_policy == "cross-product-share":
|
|
1396
|
-
_test_flag, _incr_decr = (_delta_test > _delta_star, -1)
|
|
1397
|
-
else:
|
|
1398
|
-
_test_flag, _incr_decr = (_delta_test < _delta_star, 1)
|
|
1399
|
-
|
|
1400
|
-
if _test_flag:
|
|
1401
|
-
_s_2 += _incr_decr * _gbd_step_sz
|
|
1402
|
-
else:
|
|
1403
|
-
break
|
|
1404
|
-
|
|
1405
|
-
# Build-up boundary points
|
|
1406
|
-
_gbdry_points.append((_s_1, _s_2))
|
|
1407
|
-
|
|
1408
|
-
# Build up area terms
|
|
1409
|
-
_s_2_oddsum += _s_2 if _s_2_oddval else 0
|
|
1410
|
-
_s_2_evnsum += _s_2 if not _s_2_oddval else 0
|
|
1411
|
-
_s_2_oddval = not _s_2_oddval
|
|
1412
|
-
|
|
1413
|
-
# Hold share points
|
|
1414
|
-
_s_2_pre = _s_2
|
|
1415
|
-
_s_1_pre = _s_1
|
|
1416
|
-
|
|
1417
|
-
_gbd_prtlarea = _gbd_step_sz * (
|
|
1418
|
-
(4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _delta_star) / 3
|
|
1419
|
-
if wgtng_policy == "cross-product-share"
|
|
1420
|
-
else (
|
|
1421
|
-
(4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_2_pre) / 3
|
|
1422
|
-
+ _s_1_pre * (1 + _s_2_pre) / 2
|
|
1423
|
-
)
|
|
1424
|
-
)
|
|
1425
|
-
|
|
1426
|
-
# Area under boundary
|
|
1427
|
-
_gbdry_area_total = 2 * _gbd_prtlarea - mp.power(_s_mid, 2)
|
|
1428
|
-
|
|
1429
|
-
match wgtng_policy:
|
|
1226
|
+
recapture_spec: Literal["inside-out", "proportional"],
|
|
1227
|
+
agg_method: Literal["arithmetic", "geometric", "distance"],
|
|
1228
|
+
weighting: Literal["cross-product-share", "own-share"] | None,
|
|
1229
|
+
) -> float:
|
|
1230
|
+
match weighting:
|
|
1430
1231
|
case "cross-product-share":
|
|
1431
|
-
_s_intcpt = _delta_star
|
|
1432
|
-
case "own-
|
|
1232
|
+
_s_intcpt: float = _delta_star
|
|
1233
|
+
case "own-share":
|
|
1433
1234
|
_s_intcpt = mpf("1.0")
|
|
1434
|
-
case None if
|
|
1235
|
+
case None if agg_method == "distance":
|
|
1435
1236
|
_s_intcpt = _delta_star * mp.sqrt("2")
|
|
1436
|
-
case None if
|
|
1237
|
+
case None if agg_method == "arithmetic" and recapture_spec == "inside-out":
|
|
1437
1238
|
_s_intcpt = mp.fdiv(
|
|
1438
1239
|
mp.fsub(
|
|
1439
1240
|
2 * _delta_star * _r_val + 1, mp.fabs(2 * _delta_star * _r_val - 1)
|
|
1440
1241
|
),
|
|
1441
1242
|
2 * mpf(f"{_r_val}"),
|
|
1442
1243
|
)
|
|
1443
|
-
case None if
|
|
1244
|
+
case None if agg_method == "arithmetic":
|
|
1444
1245
|
_s_intcpt = mp.fsub(_delta_star + 1 / 2, mp.fabs(_delta_star - 1 / 2))
|
|
1445
1246
|
case _:
|
|
1446
1247
|
_s_intcpt = _s_2_pre
|
|
1447
1248
|
|
|
1448
|
-
|
|
1449
|
-
np.float64
|
|
1450
|
-
)
|
|
1451
|
-
# Points defining boundary to point-of-symmetry
|
|
1452
|
-
return GuidelinesBoundary(
|
|
1453
|
-
np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
|
|
1454
|
-
round(float(_gbdry_area_total), gbd_dps),
|
|
1455
|
-
)
|
|
1249
|
+
return _s_intcpt
|