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.
- mergeron/__init__.py +28 -3
- mergeron/core/__init__.py +2 -67
- mergeron/core/damodaran_margin_data.py +66 -52
- mergeron/core/excel_helper.py +32 -37
- mergeron/core/ftc_merger_investigations_data.py +66 -35
- mergeron/core/guidelines_boundaries.py +256 -1042
- mergeron/core/guidelines_boundary_functions.py +981 -0
- mergeron/core/{guidelines_boundaries_specialized_functions.py → guidelines_boundary_functions_extra.py} +53 -16
- mergeron/core/proportions_tests.py +2 -4
- mergeron/core/pseudorandom_numbers.py +6 -11
- mergeron/data/__init__.py +3 -0
- mergeron/data/damodaran_margin_data.xls +0 -0
- mergeron/data/damodaran_margin_data_dict.msgpack +0 -0
- mergeron/{jinja_LaTex_templates/setup_tikz_tables.tex.jinja2 → data/jinja2_LaTeX_templates/setup_tikz_tables.tex} +45 -50
- mergeron/demo/__init__.py +3 -0
- mergeron/demo/visualize_empirical_margin_distribution.py +88 -0
- mergeron/ext/__init__.py +2 -4
- mergeron/ext/tol_colors.py +3 -3
- mergeron/gen/__init__.py +53 -55
- mergeron/gen/_data_generation_functions.py +28 -93
- mergeron/gen/data_generation.py +20 -24
- mergeron/gen/{investigations_stats.py → enforcement_stats.py} +59 -57
- mergeron/gen/market_sample.py +6 -10
- mergeron/gen/upp_tests.py +29 -26
- mergeron-2024.739079.9.dist-info/METADATA +109 -0
- mergeron-2024.739079.9.dist-info/RECORD +36 -0
- mergeron/core/InCommon RSA Server CA cert chain.pem +0 -68
- mergeron-2024.738972.0.dist-info/METADATA +0 -108
- mergeron-2024.738972.0.dist-info/RECORD +0 -31
- /mergeron/{core → data}/ftc_invdata.msgpack +0 -0
- /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/clrrate_cis_summary_table_template.tex.jinja2 +0 -0
- /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/ftcinvdata_byhhianddelta_table_template.tex.jinja2 +0 -0
- /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/ftcinvdata_summary_table_template.tex.jinja2 +0 -0
- /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/ftcinvdata_summarypaired_table_template.tex.jinja2 +0 -0
- /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/mergeron.cls +0 -0
- /mergeron/{jinja_LaTex_templates → data/jinja2_LaTeX_templates}/mergeron_table_collection_template.tex.jinja2 +0 -0
- {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
|
|
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
|
|
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
|
|
23
|
+
from . import INVResolution
|
|
24
24
|
|
|
25
|
-
__version__ =
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
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.
|
|
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].
|
|
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].
|
|
390
|
-
_data_array_dict_sub[_t].
|
|
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.
|
|
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.
|
|
412
|
+
def invres_cnts_bydelta(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
|
|
411
413
|
_ndim_in = 2
|
|
412
|
-
return np.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
615
|
-
_stats_row_tot: NDArray[np.
|
|
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(),
|
|
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
|
+
)
|
mergeron/gen/market_sample.py
CHANGED
|
@@ -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
|
|
14
|
-
from ..core import
|
|
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__ =
|
|
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:
|
|
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
|
-
|
|
77
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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 =
|
|
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
|
|
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.
|
|
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 =
|
|
280
|
+
_hhi_zone_post_ranged = esl.hhi_zone_post_ranger(_hhi_post)
|
|
284
281
|
except ValueError as _err:
|
|
285
|
-
|
|
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
|
|
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.
|
|
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 =
|
|
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
|
-
|
|
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,
|
|
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.
|
|
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,,
|