mergeron 2024.738972.0__py3-none-any.whl → 2024.739079.9__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.

Files changed (37) hide show
  1. mergeron/__init__.py +28 -3
  2. mergeron/core/__init__.py +2 -67
  3. mergeron/core/damodaran_margin_data.py +66 -52
  4. mergeron/core/excel_helper.py +32 -37
  5. mergeron/core/ftc_merger_investigations_data.py +66 -35
  6. mergeron/core/guidelines_boundaries.py +256 -1042
  7. mergeron/core/guidelines_boundary_functions.py +981 -0
  8. mergeron/core/{guidelines_boundaries_specialized_functions.py → guidelines_boundary_functions_extra.py} +53 -16
  9. mergeron/core/proportions_tests.py +2 -4
  10. mergeron/core/pseudorandom_numbers.py +6 -11
  11. mergeron/data/__init__.py +3 -0
  12. mergeron/data/damodaran_margin_data.xls +0 -0
  13. mergeron/data/damodaran_margin_data_dict.msgpack +0 -0
  14. mergeron/{jinja_LaTex_templates/setup_tikz_tables.tex.jinja2 → data/jinja2_LaTeX_templates/setup_tikz_tables.tex} +45 -50
  15. mergeron/demo/__init__.py +3 -0
  16. mergeron/demo/visualize_empirical_margin_distribution.py +88 -0
  17. mergeron/ext/__init__.py +2 -4
  18. mergeron/ext/tol_colors.py +3 -3
  19. mergeron/gen/__init__.py +53 -55
  20. mergeron/gen/_data_generation_functions.py +28 -93
  21. mergeron/gen/data_generation.py +20 -24
  22. mergeron/gen/{investigations_stats.py → enforcement_stats.py} +59 -57
  23. mergeron/gen/market_sample.py +6 -10
  24. mergeron/gen/upp_tests.py +29 -26
  25. mergeron-2024.739079.9.dist-info/METADATA +109 -0
  26. mergeron-2024.739079.9.dist-info/RECORD +36 -0
  27. mergeron/core/InCommon RSA Server CA cert chain.pem +0 -68
  28. mergeron-2024.738972.0.dist-info/METADATA +0 -108
  29. mergeron-2024.738972.0.dist-info/RECORD +0 -31
  30. /mergeron/{core → data}/ftc_invdata.msgpack +0 -0
  31. /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/clrrate_cis_summary_table_template.tex.jinja2 +0 -0
  32. /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/ftcinvdata_byhhianddelta_table_template.tex.jinja2 +0 -0
  33. /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/ftcinvdata_summary_table_template.tex.jinja2 +0 -0
  34. /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/ftcinvdata_summarypaired_table_template.tex.jinja2 +0 -0
  35. /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/mergeron.cls +0 -0
  36. /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/mergeron_table_collection_template.tex.jinja2 +0 -0
  37. {mergeron-2024.738972.0.dist-info → mergeron-2024.739079.9.dist-info}/WHEEL +0 -0
@@ -1,5 +1,5 @@
1
1
  """
2
- Methods to format and print summary data on merger enforcement patterns.
2
+ Methods to format and print summary statistics on merger enforcement patterns.
3
3
 
4
4
  """
5
5
 
@@ -7,7 +7,7 @@ import enum
7
7
  import shutil
8
8
  import subprocess
9
9
  from collections.abc import Mapping, Sequence
10
- from importlib.metadata import version
10
+ from importlib import resources
11
11
  from pathlib import Path
12
12
  from types import SimpleNamespace
13
13
 
@@ -17,12 +17,12 @@ from jinja2 import Environment, FileSystemLoader, Template, select_autoescape
17
17
  from numpy.typing import NDArray
18
18
  from scipy.interpolate import interp1d # type: ignore
19
19
 
20
- from .. import _PKG_NAME, DATA_DIR # noqa: TID252
20
+ from .. import _PKG_NAME, DATA_DIR, VERSION # noqa: TID252
21
21
  from ..core import ftc_merger_investigations_data as fid # noqa: TID252
22
22
  from ..core.proportions_tests import propn_ci # noqa: TID252
23
- from . import TF, TI, INVResolution
23
+ from . import INVResolution
24
24
 
25
- __version__ = version(_PKG_NAME)
25
+ __version__ = VERSION
26
26
 
27
27
 
28
28
  @enum.unique
@@ -108,38 +108,42 @@ class StatsContainer(SimpleNamespace):
108
108
 
109
109
  # Define the latex jinja environment
110
110
  # http://eosrei.net/articles/2015/11/latex-templates-python-and-jinja2-generate-pdfs
111
- latex_jinja_env = Environment(
112
- block_start_string=R"((*",
113
- block_end_string="*))",
114
- variable_start_string=R"\JINVAR{",
115
- variable_end_string="}",
116
- comment_start_string=R"((#", # r'#{',
117
- comment_end_string=R"#))", # '}',
118
- line_statement_prefix="##",
119
- line_comment_prefix="%#",
120
- trim_blocks=True,
121
- lstrip_blocks=True,
122
- autoescape=select_autoescape(disabled_extensions=("tex.jinja2",)),
123
- loader=FileSystemLoader(Path(__file__).parents[1] / "jinja_LaTex_templates"),
124
- )
111
+ with resources.as_file(
112
+ resources.files(f"{_PKG_NAME}.data.jinja2_LaTeX_templates")
113
+ ) as _tmpl_folder:
114
+ latex_jinja_env = Environment(
115
+ block_start_string=R"((*",
116
+ block_end_string="*))",
117
+ variable_start_string=R"\JINVAR{",
118
+ variable_end_string="}",
119
+ comment_start_string=R"((#", # r'#{',
120
+ comment_end_string=R"#))", # '}',
121
+ line_statement_prefix="##",
122
+ line_comment_prefix="%#",
123
+ trim_blocks=True,
124
+ lstrip_blocks=True,
125
+ autoescape=select_autoescape(disabled_extensions=("tex.jinja2",)),
126
+ loader=FileSystemLoader(_tmpl_folder),
127
+ )
125
128
 
126
129
  # Place files related to rendering latex in output data directory
127
130
  if not (_out_path := DATA_DIR.joinpath(f"{_PKG_NAME}.cls")).is_file():
128
- shutil.copyfile(
129
- Path(__file__).parents[1].joinpath("jinja_LaTex_templates", "mergeron.cls"),
130
- _out_path,
131
- )
131
+ with resources.as_file(
132
+ resources.files(f"{_PKG_NAME}.data.jinja2_LaTeX_templates").joinpath(
133
+ "{_PKG_NAME}.cls"
134
+ )
135
+ ) as _in_path:
136
+ shutil.copy2(_in_path, _out_path)
132
137
 
133
138
 
134
139
  if not (_DOTTEX := DATA_DIR / Rf"{_PKG_NAME}_TikZTableSettings.tex").is_file():
135
140
  # Write to dottex
136
- with _DOTTEX.open("w", encoding="UTF-8") as _table_helper_dottex:
137
- _table_helper_dottex.write(
138
- latex_jinja_env.get_template("setup_tikz_tables.tex.jinja2").render(
139
- tmpl_data=StatsContainer()
140
- )
141
+ with resources.as_file(
142
+ resources.files(f"{_PKG_NAME}.data.jinja2_LaTeX_templates").joinpath(
143
+ "setup_tikz_tables.tex"
141
144
  )
142
- print("\n", file=_table_helper_dottex)
145
+ ) as _tex_path:
146
+ shutil.copy2(_tex_path, _DOTTEX)
143
147
 
144
148
 
145
149
  # Parameters and functions to interpolate selected HHI and ΔHHI values
@@ -172,7 +176,7 @@ HMG_PRESUMPTION_ZONE_DICT = {
172
176
  }
173
177
 
174
178
  ZONE_VALS = np.unique(
175
- np.row_stack([
179
+ np.vstack([
176
180
  tuple(HMG_PRESUMPTION_ZONE_DICT[_k].values())
177
181
  for _k in HMG_PRESUMPTION_ZONE_DICT
178
182
  ]),
@@ -375,7 +379,7 @@ def table_no_lku(
375
379
  /,
376
380
  ) -> str:
377
381
  if _table_ind_group not in (
378
- _igl := [_data_array_dict_sub[_v].ind_grp for _v in _data_array_dict_sub]
382
+ _igl := [_data_array_dict_sub[_v].industry_group for _v in _data_array_dict_sub]
379
383
  ):
380
384
  raise ValueError(
381
385
  f"Invalid value for industry group, {f'"{_table_ind_group}"'}."
@@ -386,19 +390,17 @@ def table_no_lku(
386
390
  _t
387
391
  for _t in _data_array_dict_sub
388
392
  if all((
389
- _data_array_dict_sub[_t].ind_grp == _table_ind_group,
390
- _data_array_dict_sub[_t].evid_cond == _table_evid_cond,
393
+ _data_array_dict_sub[_t].industry_group == _table_ind_group,
394
+ _data_array_dict_sub[_t].additional_evidence == _table_evid_cond,
391
395
  ))
392
396
  )
393
397
 
394
398
  return _tno
395
399
 
396
400
 
397
- def invres_cnts_byfirmcount(
398
- _cnts_array: NDArray[np.integer[TI]], /
399
- ) -> NDArray[np.int64]:
401
+ def invres_cnts_byfirmcount(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
400
402
  _ndim_in = 1
401
- return np.row_stack([
403
+ return np.vstack([
402
404
  np.concatenate([
403
405
  (f,),
404
406
  np.einsum("ij->j", _cnts_array[_cnts_array[:, 0] == f][:, _ndim_in:]),
@@ -407,9 +409,9 @@ def invres_cnts_byfirmcount(
407
409
  ])
408
410
 
409
411
 
410
- def invres_cnts_bydelta(_cnts_array: NDArray[np.integer[TI]], /) -> NDArray[np.int64]:
412
+ def invres_cnts_bydelta(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
411
413
  _ndim_in = 2
412
- return np.row_stack([
414
+ return np.vstack([
413
415
  np.concatenate([
414
416
  (f,),
415
417
  np.einsum("ij->j", _cnts_array[_cnts_array[:, 1] == f][:, _ndim_in:]),
@@ -418,9 +420,7 @@ def invres_cnts_bydelta(_cnts_array: NDArray[np.integer[TI]], /) -> NDArray[np.i
418
420
  ])
419
421
 
420
422
 
421
- def invres_cnts_byconczone(
422
- _cnts_array: NDArray[np.integer[TI]], /
423
- ) -> NDArray[np.int64]:
423
+ def invres_cnts_byconczone(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
424
424
  # Prepare to tag clearance stats by presumption zone
425
425
  _hhi_zone_post_ranged = hhi_zone_post_ranger(_cnts_array[:, 0] / 1e4)
426
426
  _hhi_delta_ranged = hhi_delta_ranger(_cnts_array[:, 1] / 1e4)
@@ -453,7 +453,7 @@ def invres_cnts_byconczone(
453
453
 
454
454
  _conc_test = _level_test & _delta_test
455
455
 
456
- _cnts_byhhipostanddelta = np.row_stack((
456
+ _cnts_byhhipostanddelta = np.vstack((
457
457
  _cnts_byhhipostanddelta,
458
458
  np.array(
459
459
  (
@@ -475,7 +475,7 @@ def invres_cnts_byconczone(
475
475
  ])
476
476
  ).prod(axis=1) == 1
477
477
 
478
- _cnts_byconczone = np.row_stack((
478
+ _cnts_byconczone = np.vstack((
479
479
  _cnts_byconczone,
480
480
  np.concatenate(
481
481
  (
@@ -492,7 +492,7 @@ def invres_cnts_byconczone(
492
492
 
493
493
 
494
494
  def latex_tbl_invres_stats_1dim(
495
- _inparr: NDArray[np.floating[TF] | np.integer[TI]],
495
+ _inparr: NDArray[np.float64 | np.int64],
496
496
  _totals_row: int | None = None,
497
497
  /,
498
498
  *,
@@ -527,7 +527,7 @@ def latex_tbl_invres_stats_1dim(
527
527
  if sort_order == SortSelector.REV:
528
528
  _inparr = _inparr[::-1]
529
529
 
530
- _inparr = np.row_stack((_inparr, _in_totals_row))
530
+ _inparr = np.vstack((_inparr, _in_totals_row))
531
531
 
532
532
  _stats_hdr_list, _stats_dat_list = [], []
533
533
  for _stats_row in _inparr:
@@ -544,7 +544,7 @@ def latex_tbl_invres_stats_1dim(
544
544
 
545
545
 
546
546
  def latex_tbl_invres_stats_byzone(
547
- _inparr: NDArray[np.floating[TF] | np.integer[TI]],
547
+ _inparr: NDArray[np.float64 | np.int64],
548
548
  _totals_row: int | None = None,
549
549
  /,
550
550
  *,
@@ -559,7 +559,7 @@ def latex_tbl_invres_stats_byzone(
559
559
  _zone_str_keys = _zone_str_keys[:-1][::-1] + [_zone_str_keys[-1]]
560
560
 
561
561
  if _totals_row is None:
562
- _inparr = np.row_stack((
562
+ _inparr = np.vstack((
563
563
  _inparr,
564
564
  np.concatenate((
565
565
  [fid.TTL_KEY, -1, -1],
@@ -611,8 +611,8 @@ def latex_tbl_invres_stats_byzone(
611
611
 
612
612
 
613
613
  def _stats_formatted_row(
614
- _stats_row_cnt: NDArray[np.integer[TI]],
615
- _stats_row_tot: NDArray[np.integer[TI]],
614
+ _stats_row_cnt: NDArray[np.int64],
615
+ _stats_row_tot: NDArray[np.int64],
616
616
  _return_type_sel: StatsReturnSelector,
617
617
  /,
618
618
  ) -> list[list[str]]:
@@ -691,19 +691,21 @@ def render_table_pdf(
691
691
  )
692
692
  print("\n", file=_table_coll_file)
693
693
 
694
- _run_rc = subprocess.run(
695
- f"latexmk -f -quiet -synctex=0 -interaction=nonstopmode -file-line-error -pdflua {_table_coll_path}".split(), # noqa: S603
694
+ _run_rc = subprocess.run( # noqa: S603
695
+ f"latexmk -f -quiet -synctex=0 -interaction=nonstopmode -file-line-error -pdflua {_table_coll_path}".split(),
696
696
  check=True,
697
697
  cwd=DATA_DIR,
698
698
  )
699
699
  if _run_rc:
700
- subprocess.run(
701
- "latexmk -quiet -c".split(), # noqa: S603
702
- check=True,
703
- cwd=DATA_DIR,
704
- )
700
+ subprocess.run("latexmk -quiet -c".split(), check=True, cwd=DATA_DIR) # noqa: S603
705
701
  del _run_rc
706
702
 
707
703
  print(
708
704
  f"Tables rendered to path, {f"{Path(DATA_DIR / _table_coll_path).with_suffix(".pdf")}"}"
709
705
  )
706
+
707
+
708
+ if __name__ == "__main__":
709
+ print(
710
+ "This module provides methods to format and print summary statistics on merger enforcement patterns.."
711
+ )
@@ -5,18 +5,16 @@ Methods to generate data for analyzing merger enforcement policy.
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
- from importlib.metadata import version
9
-
10
8
  from attrs import define
11
9
  from numpy.random import SeedSequence
12
10
 
13
- from .. import _PKG_NAME # noqa: TID252
14
- from ..core import guidelines_boundaries as gbl # noqa: TID252
11
+ from .. import VERSION # noqa: TID252
12
+ from ..core.guidelines_boundaries import HMGThresholds # noqa: TID252
15
13
  from . import MarketSpec, UPPTestRegime
16
14
  from .data_generation import gen_market_sample
17
15
  from .upp_tests import SaveData, invres_cnts, save_data_to_hdf5, sim_invres_cnts_ll
18
16
 
19
- __version__ = version(_PKG_NAME)
17
+ __version__ = VERSION
20
18
 
21
19
 
22
20
  @define(slots=False)
@@ -50,7 +48,7 @@ class MarketSample(MarketSpec):
50
48
 
51
49
  def estimate_invres_counts(
52
50
  self,
53
- _invres_parm_vec: gbl.HMGThresholds,
51
+ _invres_parm_vec: HMGThresholds,
54
52
  _upp_test_regime: UPPTestRegime,
55
53
  /,
56
54
  *,
@@ -73,7 +71,5 @@ class MarketSample(MarketSpec):
73
71
  self.invres_counts = invres_cnts(
74
72
  self.data, _invres_parm_vec, _upp_test_regime
75
73
  )
76
- if save_data_to_file:
77
- save_data_to_hdf5(
78
- self.invres_counts, save_data_to_file=save_data_to_file
79
- )
74
+ if save_data_to_file:
75
+ save_data_to_hdf5(self.invres_counts, save_data_to_file=save_data_to_file)
mergeron/gen/upp_tests.py CHANGED
@@ -1,24 +1,22 @@
1
1
  """
2
- Methods to estimate intrinsic clearnace rates and intrinsic enforcement rates
2
+ Methods to compute intrinsic clearance rates and intrinsic enforcement rates
3
3
  from generated market data.
4
4
 
5
5
  """
6
6
 
7
7
  from collections.abc import Sequence
8
8
  from contextlib import suppress
9
- from importlib.metadata import version
10
9
  from pathlib import Path
11
10
  from typing import Literal, TypeAlias, TypedDict
12
11
 
13
12
  import numpy as np
14
13
  import tables as ptb # type: ignore
14
+ from icecream import ic # type: ignore
15
15
  from joblib import Parallel, cpu_count, delayed # type: ignore
16
16
  from numpy.random import SeedSequence
17
17
  from numpy.typing import NDArray
18
18
 
19
- from mergeron.core.pseudorandom_numbers import TF, TI
20
-
21
- from .. import _PKG_NAME, RECConstants, UPPAggrSelector # noqa: TID252
19
+ from .. import VERSION, RECConstants, UPPAggrSelector # noqa: TID252
22
20
  from ..core import guidelines_boundaries as gbl # noqa: TID252
23
21
  from . import (
24
22
  EMPTY_ARRAY_DEFAULT,
@@ -31,10 +29,9 @@ from . import (
31
29
  UPPTestsRaw,
32
30
  )
33
31
  from . import data_generation as dgl
34
- from . import investigations_stats as isl
35
-
36
- __version__ = version(_PKG_NAME)
32
+ from . import enforcement_stats as esl
37
33
 
34
+ __version__ = VERSION
38
35
 
39
36
  ptb.parameters.MAX_NUMEXPR_THREADS = 8
40
37
  ptb.parameters.MAX_BLOSC_THREADS = 4
@@ -45,11 +42,11 @@ SaveData: TypeAlias = Literal[False] | tuple[Literal[True], ptb.File, ptb.Group]
45
42
  class INVRESCntsArgs(TypedDict, total=False):
46
43
  "Keyword arguments of function, :code:`sim_invres_cnts`"
47
44
 
48
- saved_array_name_suffix: str
49
- save_data_to_file: SaveData
50
45
  sample_size: int
51
46
  seed_seq_list: list[SeedSequence] | None
52
47
  nthreads: int
48
+ save_data_to_file: SaveData
49
+ saved_array_name_suffix: str
53
50
 
54
51
 
55
52
  def sim_invres_cnts_ll(
@@ -58,11 +55,11 @@ def sim_invres_cnts_ll(
58
55
  _sim_test_regime: UPPTestRegime,
59
56
  /,
60
57
  *,
61
- saved_array_name_suffix: str = "",
62
- save_data_to_file: SaveData = False,
63
58
  sample_size: int = 10**6,
64
59
  seed_seq_list: list[SeedSequence] | None = None,
65
60
  nthreads: int = 16,
61
+ save_data_to_file: SaveData = False,
62
+ saved_array_name_suffix: str = "",
66
63
  ) -> UPPTestsCounts:
67
64
  """A function to parallelize data-generation and testing
68
65
 
@@ -171,11 +168,11 @@ def sim_invres_cnts(
171
168
  _sim_test_regime: UPPTestRegime,
172
169
  /,
173
170
  *,
174
- saved_array_name_suffix: str = "",
175
- save_data_to_file: SaveData = False,
176
171
  sample_size: int = 10**6,
177
172
  seed_seq_list: list[SeedSequence] | None = None,
178
173
  nthreads: int = 16,
174
+ save_data_to_file: SaveData = False,
175
+ saved_array_name_suffix: str = "",
179
176
  ) -> UPPTestsCounts:
180
177
  # Generate market data
181
178
  _market_data_sample = dgl.gen_market_sample(
@@ -235,7 +232,7 @@ def invres_cnts(
235
232
  for _firm_cnt in 2 + np.arange(_max_firm_count):
236
233
  _firm_count_test = _fcounts == _firm_cnt
237
234
 
238
- _invres_cnts_sim_byfirmcount_array = np.row_stack((
235
+ _invres_cnts_sim_byfirmcount_array = np.vstack((
239
236
  _invres_cnts_sim_byfirmcount_array,
240
237
  np.array([
241
238
  _firm_cnt,
@@ -257,12 +254,12 @@ def invres_cnts(
257
254
  _invres_cnts_sim_byfirmcount_array[0] = 2
258
255
 
259
256
  # Clearance/enfrocement counts --- by delta
260
- _hhi_delta_ranged = isl.hhi_delta_ranger(_hhi_delta)
257
+ _hhi_delta_ranged = esl.hhi_delta_ranger(_hhi_delta)
261
258
  _invres_cnts_sim_bydelta_array = -1 * np.ones(_stats_rowlen, np.int64)
262
- for _hhi_delta_lim in isl.HHI_DELTA_KNOTS[:-1]:
259
+ for _hhi_delta_lim in esl.HHI_DELTA_KNOTS[:-1]:
263
260
  _hhi_delta_test = _hhi_delta_ranged == _hhi_delta_lim
264
261
 
265
- _invres_cnts_sim_bydelta_array = np.row_stack((
262
+ _invres_cnts_sim_bydelta_array = np.vstack((
266
263
  _invres_cnts_sim_bydelta_array,
267
264
  np.array([
268
265
  _hhi_delta_lim,
@@ -280,13 +277,13 @@ def invres_cnts(
280
277
 
281
278
  # Clearance/enfrocement counts --- by zone
282
279
  try:
283
- _hhi_zone_post_ranged = isl.hhi_zone_post_ranger(_hhi_post)
280
+ _hhi_zone_post_ranged = esl.hhi_zone_post_ranger(_hhi_post)
284
281
  except ValueError as _err:
285
- print(_hhi_post)
282
+ ic(_hhi_post)
286
283
  raise _err
287
284
 
288
285
  _stats_byconczone_sim = -1 * np.ones(_stats_rowlen + 1, np.int64)
289
- for _hhi_zone_post_knot in isl.HHI_POST_ZONE_KNOTS[:-1]:
286
+ for _hhi_zone_post_knot in esl.HHI_POST_ZONE_KNOTS[:-1]:
290
287
  _level_test = _hhi_zone_post_ranged == _hhi_zone_post_knot
291
288
 
292
289
  for _hhi_zone_delta_knot in [0, 100, 200]:
@@ -298,7 +295,7 @@ def invres_cnts(
298
295
 
299
296
  _conc_test = _level_test & _delta_test
300
297
 
301
- _stats_byconczone_sim = np.row_stack((
298
+ _stats_byconczone_sim = np.vstack((
302
299
  _stats_byconczone_sim,
303
300
  np.array([
304
301
  _hhi_zone_post_knot,
@@ -313,7 +310,7 @@ def invres_cnts(
313
310
  ]),
314
311
  ))
315
312
 
316
- _invres_cnts_sim_byconczone_array = isl.invres_cnts_byconczone(
313
+ _invres_cnts_sim_byconczone_array = esl.invres_cnts_byconczone(
317
314
  _stats_byconczone_sim[1:]
318
315
  )
319
316
  del _stats_byconczone_sim
@@ -472,11 +469,11 @@ def initialize_hd5(
472
469
  _h5_path.unlink()
473
470
  _h5_file = ptb.open_file(_h5_path, mode="w", title=_h5_title)
474
471
  _save_data_to_file: tuple[Literal[True], ptb.File, str] = (True, _h5_file, "/")
475
- _next_subgroup_name = "invres_{}_{}_{}_{}".format(
472
+ _next_subgroup_name_root = "invres_{}_{}_{}_{}".format(
476
473
  _hmg_pub_year,
477
474
  *(getattr(_test_regime, _f.name).name for _f in _test_regime.__attrs_attrs__),
478
475
  )
479
- return _save_data_to_file, _next_subgroup_name
476
+ return _save_data_to_file, _next_subgroup_name_root
480
477
 
481
478
 
482
479
  def save_data_to_hdf5(
@@ -504,7 +501,7 @@ def save_data_to_hdf5(
504
501
 
505
502
 
506
503
  def save_array_to_hdf5(
507
- _array_obj: NDArray[np.floating[TF] | np.integer[TI] | np.bool_],
504
+ _array_obj: NDArray[np.float64 | np.int64 | np.bool_],
508
505
  _array_name: str,
509
506
  _h5_group: ptb.Group,
510
507
  _h5_file: ptb.File,
@@ -525,3 +522,9 @@ def save_array_to_hdf5(
525
522
  filters=ptb.Filters(complevel=3, complib="blosc:lz4hc", fletcher32=True),
526
523
  )
527
524
  _h5_array[:] = _array_obj
525
+
526
+
527
+ if __name__ == "__main__":
528
+ print(
529
+ "This module defines classes with methods for generating UPP test arrays and UPP test-counts arrays on given data."
530
+ )
@@ -0,0 +1,109 @@
1
+ Metadata-Version: 2.1
2
+ Name: mergeron
3
+ Version: 2024.739079.9
4
+ Summary: Merger Policy Analysis using Python
5
+ License: MIT
6
+ Keywords: merger policy analysis,merger guidelines,merger screening,policy presumptions,concentration standards,upward pricing pressure,GUPPI
7
+ Author: Murthy Kambhampaty
8
+ Author-email: smk@capeconomics.com
9
+ Requires-Python: >=3.12,<4.0
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: Implementation :: CPython
21
+ Requires-Dist: aenum (>=3.1.15,<4.0.0)
22
+ Requires-Dist: attrs (>=23.2)
23
+ Requires-Dist: bs4 (>=0.0.1)
24
+ Requires-Dist: certifi (>=2023.11.17)
25
+ Requires-Dist: google-re2 (>=1.1)
26
+ Requires-Dist: icecream (>=2.1.0)
27
+ Requires-Dist: jinja2 (>=3.1)
28
+ Requires-Dist: joblib (>=1.3)
29
+ Requires-Dist: lxml (>=5.0)
30
+ Requires-Dist: matplotlib (>=3.8)
31
+ Requires-Dist: mpmath (>=1.3)
32
+ Requires-Dist: msgpack (>=1.0)
33
+ Requires-Dist: msgpack-numpy (>=0.4)
34
+ Requires-Dist: numpy (>=1.26,<2.0)
35
+ Requires-Dist: openpyxl (>=3.1.2)
36
+ Requires-Dist: pendulum (>=3.0.0)
37
+ Requires-Dist: requests (>=2.31)
38
+ Requires-Dist: requests-toolbelt (>=1.0.0)
39
+ Requires-Dist: scipy (>=1.12)
40
+ Requires-Dist: sympy (>=1.12)
41
+ Requires-Dist: tables (>=3.8)
42
+ Requires-Dist: types-beautifulsoup4 (>=4.11.2)
43
+ Requires-Dist: types-requests (>=2.31.0)
44
+ Requires-Dist: xlrd (>=2.0.1,<3.0.0)
45
+ Requires-Dist: xlsxwriter (>=3.1)
46
+ Description-Content-Type: text/x-rst
47
+
48
+ mergeron: Merger Policy Analysis using Python
49
+ =============================================
50
+
51
+ Download and analyze merger investigations data published by the U.S. Federal Trade Commission in various reports on extended merger investigations during 1996 to 2011. Model the sets of mergers conforming to various U.S. Horizontal Merger Guidelines standards. Analyze intrinsic clearance rates and intrinsic enforcement rates under Guidelines standards using generated data with specified distributions of market shares, price-cost margins, firm counts, and prices, optionally imposing restrictions impled by statutory filing thresholds and/or Bertrand-Nash oligopoly with MNL demand.
52
+
53
+ Intrinsic clearance and enforcement rates are distinguished from *observed* clearance and enforcement rates in that the former do not reflect the effects of screening and deterrence as do the latter.
54
+
55
+
56
+ Introduction
57
+ ------------
58
+
59
+ Classes for specifying concentration standards (`mergeron.core.guidelines_boundaries.ConcentrationBoundary`) and diversion-ratio standards (`mergeron.core.guidelines_boundaries.DiversionRatioBoundary`), with automatic generation of boundary (as an array of share-pairs) and area, are provided in `mergeron.core.guidelines_boundaries`. This module also includes a function for generating plots of concentation and diversion-ratio boundaries, and functions for mapping GUPPI standards to concentration (ΔHHI) standards, and vice-versa.
60
+
61
+ Methods for generating industry data under various distributions of shares, margins, and prices are included in, `mergeron.gen.data_generation`. Shares are drawn with uniform distribution with :math:`s_1 + s_2 \leqslant 1` and an unspecified number of firms. Alternatively, shares may be drawn from the Dirichlet distribution. When drawing shares from the Dirichlet distribution, the user can specify a fixed number for firms or provide a vector of weights specifying the frequency distribution over sequential firm counts, e.g., :code:`[133, 184, 134, 52, 32, 10, 12, 4, 3]` to specify shares drawn from Dirichlet distributions with 2 to 10 pre-merger firms distributed as in data for FTC merger investigations during 1996--2003 (See, for example, Table 4.1 of `FTC, Horizontal Merger Investigations Data, Fiscal Years 1996--2003 (Revised: August 31, 2004) <"https://www.ftc.gov/sites/default/files/documents/reports/horizontal-merger-investigation-data-fiscal-years-1996-2003/040831horizmergersdata96-03.pdf>`_). The user can specify recapture rates as, "proportional", "inside-out" --- i.e., consistent with merging-firms' in-market shares and a default recapture rate) --- or "outside-in" --- i.e., purchase probabilities are drawn at random for :math:`N+1` goods, from which are derived market shares and recapture rates for the :math:`N` goods in the putative market. Documentation on specifying the sampling strategy for market shares is at `mergeron.gen.ShareSpec`. Price-cost-margins may be specified as symmetric, i.i.d., or subject to equilibrium conditions for (profit-mazimization in) Bertrand-Nash oligopoly with MNL demand (see, `mergeron.gen.PCMSpec`). Prices may be specified as symmetric or asymmetric, and in the latter case, the direction of correlation between merging firm prices, if any, can also be specified (see, `mergeron.gen.PriceSpec`). Two alternative approaches for modeling statutory filing requirements (HSR filing thresholds) are implemented (see, `mergeron.gen.SSZConstants`). The full specification of a market sample is given in a `mergeron.gen.market_sample.MarketSample` object. Data are drawn by invoking `mergeron.gen.market_sample.MarketSample.generate_sample` which adds a `data` property of class, `mergeron.gen.MarketDataSample`. Enforcement or clearance counts are computed by invoking `mergeron.gen.market_sample.MarketSample.estimate_invres_counts`, which adds an `invres_counts` property of class `mergeron.gen.UPPTestsCounts`. For fast, parallel generation of enforcement or clearance counts over large market data samples that ordinarily would exceed available limits on machine memory, the user can invoke the method `estimate_invres_counts` on a `mergeron.gen.market_sample.MarketSample` object without first invoking `generate_sample`. Note, however, that this strategy discards the market sample in the interests of conserving memory and maintaining high performance.
62
+
63
+ Methods for printing enforcement statistics based on FTC investigations data and test data are printed to screen or rendered to LaTex files (for processing into publication-quality tables) using methods provided in `mergeron.gen.enforcement_stats`.
64
+
65
+ Programs demonstrating the analysis and reporting facilites provided by the sub-package, `mergeron.demo`.
66
+
67
+ This package exposes methods employed for generating random numbers with selected continuous distribution over specified parameters, and with CPU multithreading on machines with multiple virtual, logical, or physical CPU cores. To access these directly:
68
+
69
+ .. code-block:: python
70
+
71
+ import mergeron.core.pseudorandom_numbers as prng
72
+
73
+ Also included are methods for estimating confidence intervals for proportions and for contrasts (differences) in proportions. (Although coded from scratch using the source literature, the APIs implemented in the module included here are designed for consistency with the APIs in, `statsmodels.stats.proportion` from the package, `statsmodels` (https://pypi.org/project/statsmodels/).) To access these directly:
74
+
75
+ .. code-block:: python
76
+
77
+ import mergeron.core.proportions_tests as prci
78
+
79
+ A recent version of Paul Tol's python module, `tol_colors.py` is redistributed within this package. Other than re-formatting and type annotation, the `mergeron.ext.tol_colors` module is re-distributed as downloaded from, https://personal.sron.nl/~pault/data/tol_colors.py. The `tol_colors.py` module is distributed under the Standard 3-clause BSD license. To access the `mergeron.ext.tol_colors` module directly:
80
+
81
+ .. code-block:: python
82
+
83
+ import mergeron.ext.tol_colors as ptc
84
+
85
+ Documentation for this package is in the form of the API Reference. Documentation for individual functions and classes is accessible within a python shell. For example:
86
+
87
+ .. code-block:: python
88
+
89
+ import mergeron.core.market_sample as market_sample
90
+
91
+ help(market_sample.MarketSample)
92
+
93
+
94
+ .. image:: https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json
95
+ :alt: Poetry
96
+ :target: https://python-poetry.org/
97
+
98
+ .. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
99
+ :alt: Ruff
100
+ :target: https://github.com/astral-sh/ruff
101
+
102
+ .. image:: https://www.mypy-lang.org/static/mypy_badge.svg
103
+ :alt: Checked with mypy
104
+ :target: https://mypy-lang.org/
105
+
106
+ .. image:: https://img.shields.io/badge/License-MIT-yellow.svg
107
+ :alt: License: MIT
108
+ :target: https://opensource.org/licenses/MIT
109
+
@@ -0,0 +1,36 @@
1
+ mergeron/License.txt,sha256=7iX-y0EyjkbVJKJLS4ZKzuuE1wd0lryfsD_IytLG8lQ,1246
2
+ mergeron/__init__.py,sha256=to9InGF69DIyenwmER8bPN-LoZLc-W8D7kS-Qc_CFdg,1647
3
+ mergeron/core/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
4
+ mergeron/core/damodaran_margin_data.py,sha256=pjI1rSK_O1-3Oel5b9KXH6ctnInjX1Vii7fypt00gV8,8541
5
+ mergeron/core/excel_helper.py,sha256=WxLJoSuX0RMK4xGzGKZSIVULSk1tdSLepgHPmj7M3yc,7605
6
+ mergeron/core/ftc_merger_investigations_data.py,sha256=ZaV2DO7UZabV8eX0Ubq_ToIor7tIRzcvYC54ADliuTk,27931
7
+ mergeron/core/guidelines_boundaries.py,sha256=__OHme8aGtwOgRXKp56WdX7k4vssAVQ8Ub54XwpS7mg,15621
8
+ mergeron/core/guidelines_boundary_functions.py,sha256=rXjncqTn7NPgI2KY9Wuv3WNrsjmv74hpH9-mUI56NgQ,29714
9
+ mergeron/core/guidelines_boundary_functions_extra.py,sha256=TYq3M5onfAIAY-35Q_SaSVF0Upa9hCSKIQkY-KCGzwM,11393
10
+ mergeron/core/proportions_tests.py,sha256=akq0Xhdgtst4RAT42_E5cBD_kATq_V4bQeBznmzRSLg,15267
11
+ mergeron/core/pseudorandom_numbers.py,sha256=k3sDs_NJ2jXlkIWKQ6iiTB5n_QS0RoJ-sqzvFYkC7pY,9277
12
+ mergeron/data/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
13
+ mergeron/data/damodaran_margin_data.xls,sha256=Qggl1p5nkOMJI8YUXhkwXQRz-OhRSqBTzz57N0JQyYA,79360
14
+ mergeron/data/damodaran_margin_data_dict.msgpack,sha256=sr6s4L69kposEpzGI7jpPb4ULz0UpY-bEYfeNi6UlRA,57621
15
+ mergeron/data/ftc_invdata.msgpack,sha256=WBFHgi7Ld4R-h2zL2Zc3TOIlKqVrbVFMH1LoI4-T-M0,264664
16
+ mergeron/data/jinja2_LaTeX_templates/clrrate_cis_summary_table_template.tex.jinja2,sha256=ae4JiciU-pt8YAM8mRbsmt4W6ePuN1y1NPCWD95oXIo,4833
17
+ mergeron/data/jinja2_LaTeX_templates/ftcinvdata_byhhianddelta_table_template.tex.jinja2,sha256=ODEurkC0UHuWpjRUiQpeW85njSeUEUJYRdYg8gqoEq0,3642
18
+ mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summary_table_template.tex.jinja2,sha256=h8_DEE0iskT9tnga5lZtxcoevN7pY4iKF-maErt4UU4,2906
19
+ mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summarypaired_table_template.tex.jinja2,sha256=Ox0ctiyW_hoOPzoWskOpuygomuV6XWhLeLo40KGRy2U,5224
20
+ mergeron/data/jinja2_LaTeX_templates/mergeron.cls,sha256=AV2mk4-uERvAuMkE95Ka7el6LZsb0JZKP4ieiNCnfMU,4562
21
+ mergeron/data/jinja2_LaTeX_templates/mergeron_table_collection_template.tex.jinja2,sha256=nr6xUI0_2KHG4Sz9k1JFVQjs2h9qS9BGt1MeE6Tygs8,2429
22
+ mergeron/data/jinja2_LaTeX_templates/setup_tikz_tables.tex,sha256=1hw3RINDtBrh9ZEToMIiNFIu9rozcPwRly69-5O_0UQ,3207
23
+ mergeron/demo/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
24
+ mergeron/demo/visualize_empirical_margin_distribution.py,sha256=v1xFJumBX2Ooye82kSSgly-_GpFVkYSDqBwM__rcmZY,2363
25
+ mergeron/ext/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
26
+ mergeron/ext/tol_colors.py,sha256=eJUtikxlgR3WjBwpkLh-tvB9QBanSvDXt8kp8pmONXU,22277
27
+ mergeron/gen/__init__.py,sha256=mlZn8gud6bxP_XKSQY2c-u-C85A8U7VxUKLiXu2hMw0,16280
28
+ mergeron/gen/_data_generation_functions.py,sha256=7fP4mSVaN36FBhPKSf1y_TbxfRUe-I7fgqdBt74oaCA,21029
29
+ mergeron/gen/data_generation.py,sha256=gDvCZYJwGpQnokcygM7IRzHBpE5rYI2J5I8uu0_wQyE,8727
30
+ mergeron/gen/enforcement_stats.py,sha256=1Mrx2p2-tXN9RdUQgRyk25xPvwh42EtjUHQgHMdCbmQ,22952
31
+ mergeron/gen/market_sample.py,sha256=4AxzF8WYPsfZaWGMtm0LMkLrEPSgRUNXd_z_ddP9-vE,2303
32
+ mergeron/gen/upp_tests.py,sha256=U2smV53VBnORIQpn3KCSdneSyegrq4dq-zT_6Eg-PIE,17302
33
+ mergeron/py.typed,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
34
+ mergeron-2024.739079.9.dist-info/METADATA,sha256=ynMO8-jtC9cvQ6Zg7myjoGcf9yHwf6n9bV8No2vc910,8690
35
+ mergeron-2024.739079.9.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
+ mergeron-2024.739079.9.dist-info/RECORD,,