mergeron 2024.738949.0__tar.gz → 2024.738949.5__tar.gz

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.

Files changed (42) hide show
  1. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/PKG-INFO +1 -1
  2. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/pyproject.toml +1 -1
  3. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/core/excel_helper.py +6 -7
  4. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/core/ftc_merger_investigations_data.py +5 -6
  5. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/core/guidelines_boundaries.py +315 -100
  6. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/concentration_as_diversion.py +60 -41
  7. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/gen/_data_generation_functions_nonpublic.py +3 -5
  8. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/gen/data_generation.py +3 -4
  9. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/gen/investigations_stats.py +5 -8
  10. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/gen/upp_tests.py +6 -7
  11. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/README.rst +0 -0
  12. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/License.txt +0 -0
  13. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/__init__.py +0 -0
  14. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/core/InCommon RSA Server CA cert chain.pem +0 -0
  15. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/core/__init__.py +0 -0
  16. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/core/damodaran_margin_data.py +6 -6
  17. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/core/proportions_tests.py +6 -6
  18. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/core/pseudorandom_numbers.py +6 -6
  19. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/__init__.py +0 -0
  20. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/enforcement_boundaries_for_mergers_with_asymmetric_shares.py +0 -0
  21. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/enforcement_boundaries_for_symmetric_firm_mergers.py +0 -0
  22. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/example_parameterizations.py +0 -0
  23. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/guidelines_enforcement_patterns.py +0 -0
  24. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/investigations_stats_obs_tables.py +0 -0
  25. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/investigations_stats_sim_tables.py +0 -0
  26. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/plotSafeHarbs_symbolically.py +0 -0
  27. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/sound_guppi_safeharbor.py +0 -0
  28. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/summarize_ftc_investigations_data.py +0 -0
  29. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/testIntrinsicClearanceRates.py +0 -0
  30. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/visualize_empirical_margin_distribution.py +0 -0
  31. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/examples/visualize_guidelines_tests.py +0 -0
  32. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/ext/__init__.py +0 -0
  33. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/ext/tol_colors.py +0 -0
  34. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/gen/__init__.py +0 -0
  35. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/jinja_LaTex_templates/clrrate_cis_summary_table_template.tex.jinja2 +0 -0
  36. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/jinja_LaTex_templates/ftcinvdata_byhhianddelta_table_template.tex.jinja2 +0 -0
  37. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/jinja_LaTex_templates/ftcinvdata_summary_table_template.tex.jinja2 +0 -0
  38. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/jinja_LaTex_templates/ftcinvdata_summarypaired_table_template.tex.jinja2 +0 -0
  39. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/jinja_LaTex_templates/mergeron.cls +0 -0
  40. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/jinja_LaTex_templates/mergeron_table_collection_template.tex.jinja2 +0 -0
  41. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/jinja_LaTex_templates/setup_tikz_tables.tex.jinja2 +0 -0
  42. {mergeron-2024.738949.0 → mergeron-2024.738949.5}/src/mergeron/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mergeron
3
- Version: 2024.738949.0
3
+ Version: 2024.738949.5
4
4
  Summary: Analysis of standards defined in Horizontal Merger Guidelines
5
5
  License: MIT
6
6
  Keywords: merger policy analysis,merger guidelines,merger screening,policy presumptions,concentration standards,upward pricing pressure,GUPPI
@@ -1,7 +1,7 @@
1
1
  [tool.poetry]
2
2
  name = "mergeron"
3
3
  # See ./get_version_str.py
4
- version = "2024.738949.0"
4
+ version = "2024.738949.5"
5
5
  description = "Analysis of standards defined in Horizontal Merger Guidelines"
6
6
  keywords = [
7
7
  "merger policy analysis",
@@ -8,14 +8,9 @@ Includes a flexible system of defining cell formats.
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
- from importlib.metadata import version
12
-
13
- from .. import _PKG_NAME # noqa: TID252
14
-
15
- __version__ = version(_PKG_NAME)
16
-
17
11
  import enum
18
12
  from collections.abc import Mapping, Sequence
13
+ from importlib.metadata import version
19
14
  from types import MappingProxyType
20
15
  from typing import Any
21
16
 
@@ -23,6 +18,10 @@ import numpy as np
23
18
  import numpy.typing as npt
24
19
  import xlsxwriter # type: ignore
25
20
 
21
+ from .. import _PKG_NAME # noqa: TID252
22
+
23
+ __version__ = version(_PKG_NAME)
24
+
26
25
 
27
26
  @enum.unique
28
27
  class CFmtParent(dict[str, Any], enum.ReprEnum):
@@ -233,7 +232,7 @@ def xl_fmt(
233
232
  if isinstance(_cell_fmt, tuple):
234
233
  ensure_cell_format_spec_tuple(_cell_fmt)
235
234
  for _cf in _cell_fmt:
236
- _cell_fmt_dict |= _cf.value
235
+ _cell_fmt_dict = _cell_fmt_dict | _cf.value
237
236
  elif isinstance(_cell_fmt, CFmt):
238
237
  _cell_fmt_dict = _cell_fmt.value
239
238
  else:
@@ -8,13 +8,8 @@ We drop reported row and column totals from source data for reducing stored data
8
8
 
9
9
  """
10
10
 
11
- from importlib.metadata import version
12
-
13
- from .. import _PKG_NAME, DATA_DIR # noqa: TID252
14
-
15
- __version__ = version(_PKG_NAME)
16
-
17
11
  from collections.abc import Mapping, Sequence
12
+ from importlib.metadata import version
18
13
  from operator import itemgetter
19
14
  from pathlib import Path
20
15
  from types import MappingProxyType
@@ -30,6 +25,10 @@ from bs4 import BeautifulSoup
30
25
  from numpy.testing import assert_array_equal
31
26
  from numpy.typing import NDArray
32
27
 
28
+ from .. import _PKG_NAME, DATA_DIR # noqa: TID252
29
+
30
+ __version__ = version(_PKG_NAME)
31
+
33
32
  m.patch()
34
33
 
35
34
  FTCDATA_DIR = DATA_DIR / "FTCData"
@@ -4,14 +4,10 @@ with a canvas on which to draw boundaries for Guidelines standards.
4
4
 
5
5
  """
6
6
 
7
- from importlib.metadata import version
8
-
9
- from .. import _PKG_NAME # noqa: TID252
10
-
11
- __version__ = version(_PKG_NAME)
12
-
13
7
  import decimal
8
+ from collections.abc import Callable
14
9
  from dataclasses import dataclass
10
+ from importlib.metadata import version
15
11
  from typing import Any, Literal, TypeAlias
16
12
 
17
13
  import numpy as np
@@ -19,6 +15,12 @@ from attrs import define, field
19
15
  from mpmath import mp, mpf # type: ignore
20
16
  from numpy.typing import NDArray
21
17
  from scipy.spatial.distance import minkowski as distance_function
18
+ from sympy import lambdify, simplify, solve, symbols
19
+
20
+ from .. import _PKG_NAME # noqa: TID252
21
+
22
+ __version__ = version(_PKG_NAME)
23
+
22
24
 
23
25
  mp.prec = 80
24
26
  mp.trap_complex = True
@@ -32,6 +34,13 @@ class GuidelinesBoundary:
32
34
  area: float
33
35
 
34
36
 
37
+ @dataclass(slots=True, frozen=True)
38
+ class GuidelinesBoundaryCallable:
39
+ boundary_function: Callable[[NDArray[np.float64]], NDArray[np.float64]]
40
+ area: float
41
+ s_naught: float = 0
42
+
43
+
35
44
  @define(slots=True, frozen=True)
36
45
  class HMGThresholds:
37
46
  delta: float
@@ -278,7 +287,12 @@ def gbd_from_dsf(
278
287
 
279
288
 
280
289
  def critical_shrratio(
281
- _gbd: float = 0.06, /, *, m_star: float = 1.00, r_bar: float = 0.80
290
+ _gbd: float = 0.06,
291
+ /,
292
+ *,
293
+ m_star: float = 1.00,
294
+ r_bar: float = 0.80,
295
+ frac: float = 1e-16,
282
296
  ) -> mpf:
283
297
  """
284
298
  Corollary to GUPPI bound.
@@ -298,7 +312,7 @@ def critical_shrratio(
298
312
  for given margin and recapture rate.
299
313
 
300
314
  """
301
- return mpf(f"{_gbd}") / mp.fmul(f"{m_star}", f"{r_bar}")
315
+ return round_cust(mpf(f"{_gbd}") / mp.fmul(f"{m_star}", f"{r_bar}"), frac=frac)
302
316
 
303
317
 
304
318
  def shr_from_gbd(
@@ -371,18 +385,18 @@ def boundary_plot(*, mktshares_plot_flag: bool = True) -> tuple[Any, ...]:
371
385
  r"\setsansfont{Fira Sans Light}",
372
386
  R"\setmonofont[Scale=MatchLowercase,]{Fira Mono}",
373
387
  R"\defaultfontfeatures[\rmfamily]{",
374
- R" Ligatures={TeX, Common},",
375
- R" Numbers={Proportional, Lining},",
376
- R" }",
388
+ R" Ligatures={TeX, Common},",
389
+ R" Numbers={Proportional, Lining},",
390
+ R" }",
377
391
  R"\defaultfontfeatures[\sffamily]{",
378
- R" Ligatures={TeX, Common},",
379
- R" Numbers={Monospaced, Lining},",
380
- R" LetterSpace=0.50,",
381
- R" }",
392
+ R" Ligatures={TeX, Common},",
393
+ R" Numbers={Monospaced, Lining},",
394
+ R" LetterSpace=0.50,",
395
+ R" }",
382
396
  R"\usepackage[",
383
- R" activate={true, nocompatibility},",
384
- R" tracking=true,",
385
- R" ]{microtype}",
397
+ R" activate={true, nocompatibility},",
398
+ R" tracking=true,",
399
+ R" ]{microtype}",
386
400
  ]),
387
401
  })
388
402
 
@@ -589,19 +603,16 @@ def delta_hhi_boundary(
589
603
  _s1_zero = 1 / 2 * (1 - mp.sqrt(1 - 2 * _dh_val))
590
604
  _s1_one = 1 - _s1_zero
591
605
 
592
- _s_mid = mp.sqrt(_dh_val / 2)
593
-
594
606
  _dh_step_sz = mp.power(10, -6)
595
- _s_1 = np.array(mp.arange(_s_mid, _s1_zero, -_dh_step_sz))
607
+ _s_1 = np.array(mp.arange(_s1_zero, _s1_one + _dh_step_sz, _dh_step_sz))
596
608
  _s_2 = _dh_val / (2 * _s_1)
597
609
 
598
610
  # Boundary points
599
- _dh_half = np.row_stack((
600
- np.column_stack((_s_1, _s_2)),
601
- np.array([(_s1_zero, _s1_one)]),
611
+ _dh_bdry_pts = np.row_stack((
602
612
  np.array([(mpf("0.0"), mpf("1.0"))]),
613
+ np.column_stack((_s_1, _s_2)),
614
+ np.array([(mpf("1.0"), mpf("0.0"))]),
603
615
  ))
604
- _dh_bdry_pts = np.row_stack((np.flip(_dh_half, 0), np.flip(_dh_half[1:], 1)))
605
616
 
606
617
  _s_1_pts, _s_2_pts = np.split(_dh_bdry_pts, 2, axis=1)
607
618
  return GuidelinesBoundary(
@@ -613,6 +624,42 @@ def delta_hhi_boundary(
613
624
  )
614
625
 
615
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
660
+ )
661
+
662
+
616
663
  def combined_share_boundary(
617
664
  _s_intcpt: float = 0.0625, /, *, bdry_dps: int = 10
618
665
  ) -> GuidelinesBoundary:
@@ -801,6 +848,130 @@ def shrratio_boundary_min(
801
848
  )
802
849
 
803
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
972
+ )
973
+
974
+
804
975
  def shrratio_boundary_wtd_avg(
805
976
  _delta_star: float = 0.075,
806
977
  _r_val: float = 0.80,
@@ -815,16 +986,36 @@ def shrratio_boundary_wtd_avg(
815
986
  Share combinations for the share-weighted average GUPPI boundary with symmetric
816
987
  merging-firm margins.
817
988
 
989
+ Parameters
990
+ ----------
991
+ _delta_star
992
+ corollary to GUPPI bound (:math:`\\overline{g} / (m^* \\cdot \\overline{r})`)
993
+ _r_val
994
+ recapture ratio
995
+ avg_method
996
+ Whether "arithmetic", "geometric", or "distance".
997
+ wgtng_policy
998
+ Whether "own-share" or "cross-product-share" (or None for simple, unweighted average).
999
+ recapture_spec
1000
+ Whether recapture-ratio is MNL-consistent ("inside-out") or has fixed
1001
+ value for both merging firms ("proportional").
1002
+ gbd_dps
1003
+ Number of decimal places for rounding returned shares and area.
1004
+
1005
+ Returns
1006
+ -------
1007
+ Array of share-pairs, area under boundary.
1008
+
818
1009
  Notes
819
1010
  -----
820
1011
  An analytical expression for the share-weighted arithmetic mean boundary
821
1012
  is derived and plotted from y-intercept to the ray of symmetry as follows::
822
1013
 
823
1014
  from sympy import plot as symplot, solve, symbols
824
- s_1, s_2, delta_star = symbols("s_1 s_2 \\delta^*")
1015
+ s_1, s_2 = symbols("s_1 s_2", positive=True)
825
1016
 
826
1017
  g_val, r_val, m_val = 0.06, 0.80, 0.30
827
- d_hat = g_val / (r_val * m_val)
1018
+ delta_star = g_val / (r_val * m_val)
828
1019
 
829
1020
  # recapture_spec == "inside-out"
830
1021
  oswag = solve(
@@ -834,7 +1025,7 @@ def shrratio_boundary_wtd_avg(
834
1025
  s_2
835
1026
  )[0]
836
1027
  symplot(
837
- oswag.subs({delta_star: d_hat}),
1028
+ oswag,
838
1029
  (s_1, 0., d_hat / (1 + d_hat)),
839
1030
  ylabel=s_2
840
1031
  )
@@ -846,7 +1037,7 @@ def shrratio_boundary_wtd_avg(
846
1037
  s_2
847
1038
  )[1]
848
1039
  symplot(
849
- cpwag.subs({delta_star: d_hat}),
1040
+ cpwag,
850
1041
  (s_1, 0., d_hat / (1 + d_hat)),
851
1042
  ylabel=s_2
852
1043
  )
@@ -859,7 +1050,7 @@ def shrratio_boundary_wtd_avg(
859
1050
  s_2
860
1051
  )[0]
861
1052
  symplot(
862
- oswag.subs({delta_star: d_hat}),
1053
+ oswag,
863
1054
  (s_1, 0., d_hat / (1 + d_hat)),
864
1055
  ylabel=s_2
865
1056
  )
@@ -871,30 +1062,11 @@ def shrratio_boundary_wtd_avg(
871
1062
  s_2
872
1063
  )[1]
873
1064
  symplot(
874
- cpswag.subs({delta_star: d_hat}),
1065
+ cpswag,
875
1066
  (s_1, 0.0, d_hat / (1 + d_hat)),
876
1067
  ylabel=s_2
877
1068
  )
878
1069
 
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
1070
 
899
1071
  """
900
1072
 
@@ -921,7 +1093,7 @@ def shrratio_boundary_wtd_avg(
921
1093
  _s_2 = _s_2_pre * (1 + _theta)
922
1094
 
923
1095
  if (_s_1 + _s_2) > mpf("0.99875"):
924
- # 1: # We lose accuracy at 3-9s and up
1096
+ # Loss of accuracy at 3-9s and up
925
1097
  break
926
1098
 
927
1099
  while True:
@@ -948,10 +1120,11 @@ def shrratio_boundary_wtd_avg(
948
1120
  case _:
949
1121
  _delta_test = lerp(_de_1, _de_2, _r)
950
1122
 
951
- if wgtng_policy == "cross-product-share":
952
- _test_flag, _incr_decr = (_delta_test > _delta_star, -1)
953
- else:
954
- _test_flag, _incr_decr = (_delta_test < _delta_star, 1)
1123
+ _test_flag, _incr_decr = (
1124
+ (_delta_test > _delta_star, -1)
1125
+ if wgtng_policy == "cross-product-share"
1126
+ else (_delta_test < _delta_star, 1)
1127
+ )
955
1128
 
956
1129
  if _test_flag:
957
1130
  _s_2 += _incr_decr * _gbd_step_sz
@@ -970,31 +1143,41 @@ def shrratio_boundary_wtd_avg(
970
1143
  _s_2_pre = _s_2
971
1144
  _s_1_pre = _s_1
972
1145
 
973
- _gbd_prtlarea = _gbd_step_sz * (
974
- (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _delta_star) / 3
975
- if wgtng_policy == "cross-product-share"
976
- else (
977
- (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_2_pre) / 3
978
- + _s_1_pre * (1 + _s_2_pre) / 2
979
- )
1146
+ if _s_2_oddval:
1147
+ _s_2_evnsum -= _s_2_pre
1148
+ else:
1149
+ _s_2_oddsum -= _s_1_pre
1150
+
1151
+ _s_intcpt = _shrratio_boundary_intcpt(
1152
+ _s_1_pre,
1153
+ _delta_star,
1154
+ _r_val,
1155
+ recapture_spec=recapture_spec,
1156
+ avg_method=avg_method,
1157
+ wgtng_policy=wgtng_policy,
980
1158
  )
981
1159
 
982
- # Area under boundary
983
- _gbdry_area_total = 2 * _gbd_prtlarea - mp.power(_s_mid, 2)
1160
+ if wgtng_policy == "own-share":
1161
+ _gbd_prtlarea = (
1162
+ _gbd_step_sz * (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_2_pre) / 3
1163
+ )
1164
+ # Area under boundary
1165
+ _gbdry_area_total = float(
1166
+ 2 * (_s_1_pre + _gbd_prtlarea)
1167
+ - (mp.power(_s_mid, "2") + mp.power(_s_1_pre, "2"))
1168
+ )
984
1169
 
985
- match wgtng_policy:
986
- case "cross-product-share":
987
- _s_intcpt = _delta_star
988
- case "own-product-share":
989
- _s_intcpt = mpf("1.0")
990
- case None if avg_method == "distance":
991
- _s_intcpt = _delta_star * mp.sqrt("2")
992
- case _:
993
- _s_intcpt = _s_2_pre
1170
+ else:
1171
+ _gbd_prtlarea = (
1172
+ _gbd_step_sz * (4 * _s_2_oddsum + 2 * _s_2_evnsum + _s_mid + _s_intcpt) / 3
1173
+ )
1174
+ # Area under boundary
1175
+ _gbdry_area_total = float(2 * _gbd_prtlarea - mp.power(_s_mid, "2"))
994
1176
 
995
1177
  _gbdry_points = np.row_stack((_gbdry_points, (mpf("0.0"), _s_intcpt))).astype(
996
1178
  np.float64
997
1179
  )
1180
+
998
1181
  # Points defining boundary to point-of-symmetry
999
1182
  return GuidelinesBoundary(
1000
1183
  np.row_stack((np.flip(_gbdry_points, 0), np.flip(_gbdry_points[1:], 1))),
@@ -1281,10 +1464,10 @@ def shrratio_boundary_avg(
1281
1464
  _s_intcpt = _s_2
1282
1465
 
1283
1466
  _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)
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)
1288
1471
 
1289
1472
  _gbdry_points = np.array(_gbdry_points, np.float64)
1290
1473
  return GuidelinesBoundary(
@@ -1310,8 +1493,8 @@ def shrratio_boundary_distance(
1310
1493
  Reimplements the arithmetic-averages and distance estimations from function,
1311
1494
  `shrratio_boundary_wtd_avg`but uses the Minkowski-distance function,
1312
1495
  `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.
1496
+ is useful for testing the output of `shrratio_boundary_wtd_avg`
1497
+ but runs considerably slower.
1315
1498
 
1316
1499
  Parameters
1317
1500
  ----------
@@ -1392,10 +1575,11 @@ def shrratio_boundary_distance(
1392
1575
  (_de_1, _de_2), (0.0, 0.0), p=2, w=_weights_i
1393
1576
  )
1394
1577
 
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)
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
+ )
1399
1583
 
1400
1584
  if _test_flag:
1401
1585
  _s_2 += _incr_decr * _gbd_step_sz
@@ -1414,22 +1598,60 @@ def shrratio_boundary_distance(
1414
1598
  _s_2_pre = _s_2
1415
1599
  _s_1_pre = _s_1
1416
1600
 
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
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
1423
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),
1424
1638
  )
1425
1639
 
1426
- # Area under boundary
1427
- _gbdry_area_total = 2 * _gbd_prtlarea - mp.power(_s_mid, 2)
1428
1640
 
1641
+ def _shrratio_boundary_intcpt(
1642
+ _s_2_pre: float,
1643
+ _delta_star: mpf,
1644
+ _r_val: mpf,
1645
+ /,
1646
+ *,
1647
+ recapture_spec: Literal["inside-out", "proportional"],
1648
+ avg_method: Literal["arithmetic", "geometric", "distance"],
1649
+ wgtng_policy: Literal["cross-product-share", "own-share"] | None,
1650
+ ) -> float:
1429
1651
  match wgtng_policy:
1430
1652
  case "cross-product-share":
1431
1653
  _s_intcpt = _delta_star
1432
- case "own-product-share":
1654
+ case "own-share":
1433
1655
  _s_intcpt = mpf("1.0")
1434
1656
  case None if avg_method == "distance":
1435
1657
  _s_intcpt = _delta_star * mp.sqrt("2")
@@ -1445,11 +1667,4 @@ def shrratio_boundary_distance(
1445
1667
  case _:
1446
1668
  _s_intcpt = _s_2_pre
1447
1669
 
1448
- _gbdry_points = np.row_stack((_gbdry_points, (mpf("0.0"), _s_intcpt))).astype(
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
- )
1670
+ return _s_intcpt
@@ -27,14 +27,15 @@ from pathlib import Path
27
27
  from typing import Any, Literal
28
28
 
29
29
  import matplotlib.axes as mpa
30
- from joblib import Parallel, cpu_count, delayed
31
- from numpy import pi
32
- from xlsxwriter import Workbook
33
-
34
30
  import mergeron.core.excel_helper as xlh
35
31
  import mergeron.core.guidelines_boundaries as gbl
36
32
  import mergeron.ext.tol_colors as ptcolor
33
+ import mergeron.gen.investigations_stats as isl
34
+ from jinja2 import FileSystemLoader
35
+ from joblib import Parallel, cpu_count, delayed
37
36
  from mergeron import DATA_DIR
37
+ from numpy import pi
38
+ from xlsxwriter import Workbook
38
39
 
39
40
  PROG_PATH = Path(__file__)
40
41
 
@@ -79,6 +80,13 @@ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
79
80
  "func_str": R"s_M",
80
81
  "func": gbl.combined_share_boundary,
81
82
  },
83
+ "SAG Average Div Ratio": {
84
+ "title_str": "Aggregated-diversion-ratio boundary, simple average",
85
+ "sheet_name": "SAG, average",
86
+ "func_str": R"(d_{12} + d_{21}) / 2",
87
+ "func": gbl.shrratio_boundary_wtd_avg,
88
+ "func_kwargs": {"wgtng_policy": None, "recapture_spec": RECAPTURE_SPEC},
89
+ },
82
90
  "SAG Div Ratio Distance": {
83
91
  "title_str": "Aggregated-diversion-ratio boundary, distance",
84
92
  "sheet_name": "SAG, distance",
@@ -90,13 +98,6 @@ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
90
98
  "avg_method": "distance",
91
99
  },
92
100
  },
93
- "SAG Average Div Ratio": {
94
- "title_str": "Aggregated-diversion-ratio boundary, simple average",
95
- "sheet_name": "SAG, average",
96
- "func_str": R"(d_{12} + d_{21}) / 2",
97
- "func": gbl.shrratio_boundary_xact_avg,
98
- "func_kwargs": {"recapture_spec": RECAPTURE_SPEC},
99
- },
100
101
  "CPSWAG Premerger HHI-contribution": {
101
102
  "title_str": "Premerger HHI-contribution boundary",
102
103
  "sheet_name": "CPSWAG, HHI-contrib-pre",
@@ -133,7 +134,7 @@ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
133
134
  }
134
135
 
135
136
 
136
- def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
137
+ def tabulate_boundary_stats(_gpubyr: gbl.HMGPubYear, /) -> None:
137
138
  """
138
139
  Parameters
139
140
  ----------
@@ -142,15 +143,17 @@ def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
142
143
  are drawn
143
144
 
144
145
  """
146
+ _invres_rate_table_content = isl.StatsContainer()
147
+
145
148
  gso = gbl.GuidelinesThresholds(_gpubyr)
146
149
  _dhhi_val, _r_val, _g_val = (
147
150
  getattr(gso.presumption, _f) for _f in ("delta", "rec", "guppi")
148
151
  )
149
152
 
150
153
  _dhhi_seq = (
151
- (0.01, 0.02, 0.03125, 0.05, _dhhi_val)
154
+ (0.005, 0.01, 0.02, gso.imputed_presumption.delta, 0.08)
152
155
  if _gpubyr == 2010
153
- else (0.005, 0.01, 0.02, 0.03125, _dhhi_val)
156
+ else (0.005, 0.01, 0.02, gso.imputed_presumption.delta, 0.08)
154
157
  )
155
158
 
156
159
  _bdry_approx_data_dict = {
@@ -166,7 +169,7 @@ def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
166
169
  ),
167
170
  )
168
171
  for _k in BDRY_SPECS_DICT
169
- if not _k.endswith("Distance")
172
+ # if not _k.endswith("Distance")
170
173
  }
171
174
  }
172
175
  _bdry_approx_data_dict |= {
@@ -176,32 +179,46 @@ def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
176
179
  }
177
180
 
178
181
  _bdry_data = Parallel(n_jobs=-1)(
179
- delayed(_dhhi_stats)(_dhhi_val, _r_val, _g_val) for _dhhi_val in _dhhi_seq
182
+ delayed(_dhhi_stats)(_dhhi_val, _r_val) for _dhhi_val in _dhhi_seq
180
183
  )
181
184
  _bdry_approx_data_dict |= dict(_bdry_data)
182
185
 
183
- print(" & ".join(_k for _k in _bdry_approx_data_dict), R" \\")
186
+ _data_str = ""
187
+ _data_str = "{} \\\\ \n".format(
188
+ " & ".join(
189
+ _k.replace("Criterion", R"{\text{} \\ Criterion}") # \phantom{Criterion}
190
+ for _k in _bdry_approx_data_dict
191
+ )
192
+ )
184
193
  for _sk in _bdry_approx_data_dict["Criterion"]:
185
- print(
186
- " & ".join(
187
- _bdry_approx_data_dict[_k][_sk] for _k in _bdry_approx_data_dict
188
- ),
189
- R"\\",
194
+ _data_str += "{} \\\\ \n".format(
195
+ " & ".join(_bdry_approx_data_dict[_k][_sk] for _k in _bdry_approx_data_dict)
190
196
  )
197
+ print(_data_str)
198
+
199
+ _invres_rate_table_content.data_str = _data_str
200
+
201
+ _j2_env = isl.latex_jinja_env
202
+ _j2_env.loader = FileSystemLoader(str(PROG_PATH.parent / "templates"))
203
+ _j2_templ = _j2_env.get_template(
204
+ "concentration_as_diversion_intrinsic_enforcement_rates.tex.jinja2"
205
+ )
206
+ PROG_PATH.parents[1].joinpath(
207
+ f"{PROG_PATH.stem}_intrinsic_enforcement_rates_{_gpubyr}.tex"
208
+ ).write_text(_j2_templ.render(tmpl_data=_invres_rate_table_content))
191
209
 
192
210
 
193
- def _dhhi_stats(
194
- _dhhi_val: float, _r_val: float, _g_val: float
195
- ) -> tuple[str, dict[str, str]]:
211
+ def _dhhi_stats(_dhhi_val: float, _r_val: float) -> tuple[str, dict[str, str]]:
196
212
  _dhhi_val = round(_dhhi_val, 5)
197
213
 
198
- _r_val = round(_r_val, 4)
199
- _s_mid = sqrt(_dhhi_val / 2)
214
+ _divr_val = gbl.gbd_from_dsf(_dhhi_val, r_bar=_r_val)
215
+ _delta_val = gbl.critical_shrratio(_divr_val, r_bar=_r_val)
216
+ # _s_mid = sqrt(_dhhi_val / 2)
200
217
 
201
- _delta_val = _s_mid / (1 - _s_mid)
202
- if _dhhi_val * 1e4 in (50, 100, 200):
203
- _delta_val = gbl.round_cust(_r_val * _delta_val) / _r_val
204
- _divr_val = _r_val * _delta_val
218
+ # _delta_val = _s_mid / (1 - _s_mid)
219
+ # if _dhhi_val * 1e4 in (50, 100, 200):
220
+ # _delta_val = gbl.critical_shrratio()(_r_val * _delta_val) / _r_val
221
+ # _divr_val = _r_val * _delta_val
205
222
 
206
223
  print(
207
224
  "Processing data for ΔHHI = {0:.{1}f} points;".format(
@@ -238,15 +255,16 @@ def _bdry_stats_col(
238
255
  return _bdry_spec, f"{_hhi_m_pre_prob:6.5f}"
239
256
  case _ if "Div Ratio" in _bdry_spec:
240
257
  _gbd_func = BDRY_SPECS_DICT[_bdry_spec]["func"]
241
- _, _within_bdry_area = _gbd_func(
258
+ _within_bdry_area = _gbd_func(
242
259
  _delta_val, _r_val, **BDRY_SPECS_DICT[_bdry_spec].get("func_kwargs", {})
243
- )
260
+ ).area
244
261
  _within_bdry_prob = 2 * _within_bdry_area
245
- _within_conc_bdry_prob = (
246
- _hhi_m_pre_prob
247
- if _bdry_spec.startswith("CPSWAG")
248
- else (_cs_prob if _bdry_spec.startswith("SAG") else _dhhi_prob)
249
- )
262
+ if _bdry_spec.startswith("CPSWAG"):
263
+ _within_conc_bdry_prob = _hhi_m_pre_prob
264
+ elif _bdry_spec.startswith("SAG"):
265
+ _within_conc_bdry_prob = _cs_prob
266
+ else:
267
+ _within_conc_bdry_prob = _dhhi_prob
250
268
 
251
269
  return _bdry_spec, R"{{ {:6.5f} \\ {:.2f}\% }}".format(
252
270
  _within_bdry_prob,
@@ -257,7 +275,7 @@ def _bdry_stats_col(
257
275
 
258
276
 
259
277
  def plot_and_save_boundary_coords(
260
- _gpubyr: Literal[1992, 2010, 2023],
278
+ _gpubyr: gbl.HMGPubYear,
261
279
  _xl_book: Workbook,
262
280
  /,
263
281
  layout: Literal["collected", "distributed"] = "collected",
@@ -599,8 +617,9 @@ def boundary_data_to_worksheet(
599
617
 
600
618
 
601
619
  if __name__ == "__main__":
602
- for gpubyr in [1992, 2010, 2023][2:]:
603
- # tabulate_boundary_stats(gpubyr)
620
+ gpubyrs: list[gbl.HMGPubYear] = [1992, 2010, 2023]
621
+ for gpubyr in gpubyrs[2:][:1]:
622
+ tabulate_boundary_stats(gpubyr)
604
623
 
605
624
  # Initiliaze workbook for saving boundary coordinates
606
625
  with Workbook(
@@ -5,17 +5,13 @@ Non-public functions called in data_generation.py
5
5
  from __future__ import annotations
6
6
 
7
7
  from importlib.metadata import version
8
-
9
- from .. import _PKG_NAME # noqa: TID252
10
-
11
- __version__ = version(_PKG_NAME)
12
-
13
8
  from typing import Literal
14
9
 
15
10
  import numpy as np
16
11
  from numpy.random import SeedSequence
17
12
  from numpy.typing import NDArray
18
13
 
14
+ from .. import _PKG_NAME # noqa: TID252
19
15
  from ..core.damodaran_margin_data import resample_mgn_data # noqa: TID252
20
16
  from ..core.pseudorandom_numbers import ( # noqa: TID252
21
17
  DIST_PARMS_DEFAULT,
@@ -37,6 +33,8 @@ from . import (
37
33
  SSZConstants,
38
34
  )
39
35
 
36
+ __version__ = version(_PKG_NAME)
37
+
40
38
 
41
39
  def _gen_share_data(
42
40
  _mkt_sample_spec: MarketSampleSpec,
@@ -7,15 +7,12 @@ from __future__ import annotations
7
7
 
8
8
  from importlib.metadata import version
9
9
 
10
- from .. import _PKG_NAME # noqa: TID252
11
-
12
- __version__ = version(_PKG_NAME)
13
-
14
10
  import attrs
15
11
  import numpy as np
16
12
  from numpy.random import SeedSequence
17
13
  from numpy.typing import NDArray
18
14
 
15
+ from .. import _PKG_NAME # noqa: TID252
19
16
  from . import (
20
17
  EMPTY_ARRAY_DEFAULT,
21
18
  TF,
@@ -35,6 +32,8 @@ from ._data_generation_functions_nonpublic import (
35
32
  _gen_share_data,
36
33
  )
37
34
 
35
+ __version__ = version(_PKG_NAME)
36
+
38
37
 
39
38
  def gen_market_sample(
40
39
  _mkt_sample_spec: MarketSampleSpec,
@@ -3,16 +3,10 @@ Routines to format and print summary data on merger enforcement patterns.
3
3
 
4
4
  """
5
5
 
6
- import subprocess
7
- from importlib.metadata import version
8
-
9
- from .. import _PKG_NAME, DATA_DIR # noqa: TID252
10
-
11
- __version__ = version(_PKG_NAME)
12
-
13
-
14
6
  import enum
7
+ import subprocess
15
8
  from collections.abc import Mapping, Sequence
9
+ from importlib.metadata import version
16
10
  from pathlib import Path
17
11
  from types import SimpleNamespace
18
12
 
@@ -22,10 +16,13 @@ from jinja2 import Environment, FileSystemLoader, Template, select_autoescape
22
16
  from numpy.typing import NDArray
23
17
  from scipy.interpolate import interp1d # type: ignore
24
18
 
19
+ from .. import _PKG_NAME, DATA_DIR # noqa: TID252
25
20
  from ..core import ftc_merger_investigations_data as fid # noqa: TID252
26
21
  from ..core.proportions_tests import propn_ci # noqa: TID252
27
22
  from . import TF, TI, INVResolution
28
23
 
24
+ __version__ = version(_PKG_NAME)
25
+
29
26
 
30
27
  @enum.unique
31
28
  class INDGRPConstants(enum.StrEnum):
@@ -4,16 +4,11 @@ from generated market data.
4
4
 
5
5
  """
6
6
 
7
- from importlib.metadata import version
8
- from pathlib import Path
9
-
10
- from .. import _PKG_NAME # noqa: TID252
11
-
12
- __version__ = version(_PKG_NAME)
13
-
14
7
  from collections.abc import Sequence
15
8
  from contextlib import suppress
16
9
  from dataclasses import fields
10
+ from importlib.metadata import version
11
+ from pathlib import Path
17
12
  from typing import Literal, TypeAlias, TypedDict
18
13
 
19
14
  import numpy as np
@@ -24,6 +19,7 @@ from joblib import Parallel, cpu_count, delayed # type: ignore
24
19
  from numpy.random import SeedSequence
25
20
  from numpy.typing import NDArray
26
21
 
22
+ from .. import _PKG_NAME # noqa: TID252
27
23
  from ..core import guidelines_boundaries as gbl # noqa: TID252
28
24
  from . import (
29
25
  EMPTY_ARRAY_DEFAULT,
@@ -40,6 +36,9 @@ from . import (
40
36
  from . import data_generation as dgl
41
37
  from . import investigations_stats as isl
42
38
 
39
+ __version__ = version(_PKG_NAME)
40
+
41
+
43
42
  ptb.parameters.MAX_NUMEXPR_THREADS = 8
44
43
  ptb.parameters.MAX_BLOSC_THREADS = 4
45
44
 
@@ -32,13 +32,8 @@ price-cost margins fall in the interval :math:`[0, 1]`.
32
32
 
33
33
  """
34
34
 
35
- from importlib.metadata import version
36
-
37
- from .. import _PKG_NAME, DATA_DIR # noqa: TID252
38
-
39
- __version__ = version(_PKG_NAME)
40
-
41
35
  from collections.abc import Mapping
36
+ from importlib.metadata import version
42
37
  from pathlib import Path
43
38
  from types import MappingProxyType
44
39
 
@@ -51,6 +46,11 @@ from requests_toolbelt.downloadutils import stream # type: ignore
51
46
  from scipy import stats # type: ignore
52
47
  from xlrd import open_workbook # type: ignore
53
48
 
49
+ from .. import _PKG_NAME, DATA_DIR # noqa: TID252
50
+
51
+ __version__ = version(_PKG_NAME)
52
+
53
+
54
54
  MGNDATA_ARCHIVE_PATH = DATA_DIR / "damodaran_margin_data_dict.msgpack"
55
55
 
56
56
 
@@ -7,14 +7,9 @@ Functions to estimate confidence intervals for
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
+ from collections.abc import Sequence
10
11
  from dataclasses import dataclass
11
12
  from importlib.metadata import version
12
-
13
- from .. import _PKG_NAME # noqa: TID252
14
-
15
- __version__ = version(_PKG_NAME)
16
-
17
- from collections.abc import Sequence
18
13
  from typing import Literal, TypeVar
19
14
 
20
15
  import numpy as np
@@ -22,6 +17,11 @@ from numpy.typing import NBitBase, NDArray
22
17
  from scipy.optimize import OptimizeResult, root # type: ignore
23
18
  from scipy.stats import beta, chi2, norm # type: ignore
24
19
 
20
+ from .. import _PKG_NAME # noqa: TID252
21
+
22
+ __version__ = version(_PKG_NAME)
23
+
24
+
25
25
  TI = TypeVar("TI", bound=NBitBase)
26
26
 
27
27
 
@@ -6,14 +6,9 @@ https://github.com/numpy/numpy/issues/16313.
6
6
 
7
7
  """
8
8
 
9
- from importlib.metadata import version
10
-
11
- from .. import _PKG_NAME # noqa: TID252
12
-
13
- __version__ = version(_PKG_NAME)
14
-
15
9
  import concurrent.futures
16
10
  from collections.abc import Sequence
11
+ from importlib.metadata import version
17
12
  from multiprocessing import cpu_count
18
13
  from typing import Literal, TypeVar
19
14
 
@@ -21,6 +16,11 @@ import numpy as np
21
16
  from numpy.random import PCG64DXSM, Generator, SeedSequence
22
17
  from numpy.typing import NBitBase, NDArray
23
18
 
19
+ from .. import _PKG_NAME # noqa: TID252
20
+
21
+ __version__ = version(_PKG_NAME)
22
+
23
+
24
24
  TF = TypeVar("TF", bound=NBitBase)
25
25
  TI = TypeVar("TI", bound=NBitBase)
26
26