mergeron 2024.738940.0__py3-none-any.whl → 2024.738949.0__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/core/excel_helper.py +38 -25
- mergeron/core/ftc_merger_investigations_data.py +33 -30
- mergeron/core/{guidelines_standards.py → guidelines_boundaries.py} +35 -29
- mergeron/core/proportions_tests.py +12 -10
- mergeron/examples/concentration_as_diversion.py +30 -26
- mergeron/examples/{safeharbor_boundaries_for_mergers_with_asymmetric_shares.py → enforcement_boundaries_for_mergers_with_asymmetric_shares.py} +84 -90
- mergeron/examples/{safeharbor_boundaries_for_symmetric_firm_mergers.py → enforcement_boundaries_for_symmetric_firm_mergers.py} +3 -3
- mergeron/examples/guidelines_enforcement_patterns.py +18 -16
- mergeron/examples/investigations_stats_obs_tables.py +15 -14
- mergeron/examples/investigations_stats_sim_tables.py +49 -54
- mergeron/examples/plotSafeHarbs_symbolically.py +1 -1
- mergeron/examples/sound_guppi_safeharbor.py +59 -54
- mergeron/examples/summarize_ftc_investigations_data.py +4 -4
- mergeron/examples/visualize_empirical_margin_distribution.py +2 -2
- mergeron/examples/visualize_guidelines_tests.py +67 -65
- mergeron/gen/__init__.py +104 -42
- mergeron/gen/_data_generation_functions_nonpublic.py +6 -6
- mergeron/gen/data_generation.py +1 -4
- mergeron/gen/investigations_stats.py +21 -27
- mergeron/gen/{guidelines_tests.py → upp_tests.py} +98 -102
- {mergeron-2024.738940.0.dist-info → mergeron-2024.738949.0.dist-info}/METADATA +2 -5
- mergeron-2024.738949.0.dist-info/RECORD +42 -0
- {mergeron-2024.738940.0.dist-info → mergeron-2024.738949.0.dist-info}/WHEEL +1 -1
- mergeron-2024.738940.0.dist-info/RECORD +0 -42
|
@@ -11,45 +11,53 @@ with the larger GUPPI estimate.
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
13
|
import gc
|
|
14
|
-
from contextlib import suppress
|
|
15
14
|
from dataclasses import fields
|
|
16
15
|
from pathlib import Path
|
|
17
16
|
from typing import Final
|
|
18
17
|
|
|
19
18
|
import numpy as np
|
|
20
|
-
import tables as ptb # type: ignore
|
|
21
19
|
from matplotlib import cm, colors
|
|
22
20
|
from matplotlib.ticker import StrMethodFormatter
|
|
23
21
|
from numpy.typing import NDArray
|
|
24
22
|
|
|
25
|
-
import mergeron.core.
|
|
23
|
+
import mergeron.core.guidelines_boundaries as gbl
|
|
26
24
|
import mergeron.gen.data_generation as dgl
|
|
27
|
-
import mergeron.gen.
|
|
28
|
-
import mergeron.gen.investigations_stats as isl
|
|
25
|
+
import mergeron.gen.upp_tests as utl
|
|
29
26
|
from mergeron import DATA_DIR
|
|
30
27
|
from mergeron.core.pseudorandom_numbers import DIST_PARMS_DEFAULT
|
|
31
|
-
from mergeron.gen import
|
|
28
|
+
from mergeron.gen import (
|
|
29
|
+
INVResolution,
|
|
30
|
+
MarketDataSample,
|
|
31
|
+
MarketSampleSpec,
|
|
32
|
+
RECConstants,
|
|
33
|
+
ShareSpec,
|
|
34
|
+
SHRConstants,
|
|
35
|
+
UPPAggrSelector,
|
|
36
|
+
UPPTestRegime,
|
|
37
|
+
)
|
|
32
38
|
|
|
33
39
|
PROG_PATH = Path(__file__)
|
|
34
40
|
|
|
35
41
|
|
|
36
|
-
blosc_filters = ptb.Filters(
|
|
37
|
-
complevel=3, complib="blosc:lz4", bitshuffle=True, fletcher32=True
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
|
|
41
42
|
def gen_plot_data(
|
|
42
|
-
_market_data:
|
|
43
|
-
_std_vec:
|
|
43
|
+
_market_data: MarketDataSample,
|
|
44
|
+
_std_vec: gbl.HMGThresholds,
|
|
44
45
|
_pcm_firm2_star: float,
|
|
45
|
-
_test_regime:
|
|
46
|
+
_test_regime: UPPTestRegime,
|
|
46
47
|
/,
|
|
47
48
|
*,
|
|
48
|
-
|
|
49
|
+
save_data_to_file: utl.SaveData = False,
|
|
49
50
|
) -> tuple[NDArray[np.float64], NDArray[np.float64], NDArray[np.float64]]:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
if save_data_to_file:
|
|
52
|
+
_, _h5_file, _h5_hier = save_data_to_file
|
|
53
|
+
_h5_hier = _h5_file.create_group(
|
|
54
|
+
_h5_hier,
|
|
55
|
+
"plotData_mstar{}PCT".format(
|
|
56
|
+
f"{_pcm_firm2_star * 100:03.1f}".replace(".", "dot")
|
|
57
|
+
),
|
|
58
|
+
title=f"Firm 2 margin = {_pcm_firm2_star * 100:03.1f}%",
|
|
59
|
+
)
|
|
60
|
+
save_data_to_file = (True, _h5_file, _h5_hier)
|
|
53
61
|
|
|
54
62
|
_pcm_array = np.column_stack((
|
|
55
63
|
_m1 := _market_data.pcm_array[:, [0]],
|
|
@@ -57,12 +65,10 @@ def gen_plot_data(
|
|
|
57
65
|
))
|
|
58
66
|
del _m1
|
|
59
67
|
|
|
60
|
-
_upp_test_raw =
|
|
68
|
+
_upp_test_raw = utl.gen_upp_arrays(
|
|
61
69
|
_std_vec,
|
|
62
|
-
|
|
63
|
-
_pcm_array.
|
|
64
|
-
if _f.name == "pcm_array"
|
|
65
|
-
else getattr(_market_data, _f.name)
|
|
70
|
+
MarketDataSample(*[ # type: ignore
|
|
71
|
+
_pcm_array if _f.name == "pcm_array" else getattr(_market_data, _f.name)
|
|
66
72
|
for _f in fields(_market_data)
|
|
67
73
|
]),
|
|
68
74
|
_test_regime,
|
|
@@ -83,7 +89,7 @@ def gen_plot_data(
|
|
|
83
89
|
|
|
84
90
|
_pcm_plotter = _pcm_firm1_inv
|
|
85
91
|
|
|
86
|
-
if
|
|
92
|
+
if save_data_to_file:
|
|
87
93
|
print("Save data to tables")
|
|
88
94
|
for _array_name in (
|
|
89
95
|
"qtyshr_firm1_inv",
|
|
@@ -91,18 +97,14 @@ def gen_plot_data(
|
|
|
91
97
|
"pcm_firm1_inv",
|
|
92
98
|
"pcm_firm2_inv",
|
|
93
99
|
):
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
obj=locals().get(f"_{_array_name}"),
|
|
100
|
-
createparents=True,
|
|
101
|
-
title=f"{_array_name}",
|
|
102
|
-
)
|
|
100
|
+
_array_obj: NDArray[any] = locals().get(f"_{_array_name}") # type: ignore
|
|
101
|
+
if np.any(_array_obj):
|
|
102
|
+
utl.save_array_to_hdf5(
|
|
103
|
+
_array_obj, _array_name, save_data_to_file[-1], save_data_to_file[1]
|
|
104
|
+
)
|
|
103
105
|
|
|
104
106
|
_pcm_sorter = np.argsort(_pcm_plotter, axis=0)
|
|
105
|
-
if test_regime.resolution !=
|
|
107
|
+
if test_regime.resolution != INVResolution.CLRN:
|
|
106
108
|
_pcm_sorter = _pcm_sorter[::-1, :]
|
|
107
109
|
_qtyshr_firm1_plotter = _qtyshr_firm1_inv[_pcm_sorter]
|
|
108
110
|
_qtyshr_firm2_plotter = _qtyshr_firm2_inv[_pcm_sorter]
|
|
@@ -121,19 +123,19 @@ def gen_plot_data(
|
|
|
121
123
|
|
|
122
124
|
# Generate market data
|
|
123
125
|
def _main(
|
|
124
|
-
_hmg_pub_year:
|
|
125
|
-
_market_sample_spec:
|
|
126
|
-
_test_regime:
|
|
127
|
-
|
|
126
|
+
_hmg_pub_year: gbl.HMGPubYear,
|
|
127
|
+
_market_sample_spec: MarketSampleSpec,
|
|
128
|
+
_test_regime: UPPTestRegime,
|
|
129
|
+
save_data_to_file: utl.SaveData,
|
|
128
130
|
) -> None:
|
|
129
131
|
guidelins_std_vec = getattr(
|
|
130
|
-
|
|
131
|
-
"safeharbor"
|
|
132
|
-
if test_regime.resolution == isl.PolicySelector.ENFT
|
|
133
|
-
else "presumption",
|
|
132
|
+
gbl.GuidelinesThresholds(_hmg_pub_year),
|
|
133
|
+
"safeharbor" if test_regime.resolution == INVResolution.ENFT else "presumption",
|
|
134
134
|
)
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
_r_bar, _g_bar, _divr_bar = (
|
|
137
|
+
getattr(guidelins_std_vec, _f) for _f in ("rec", "guppi", "divr")
|
|
138
|
+
)
|
|
137
139
|
|
|
138
140
|
market_data = dgl.gen_market_sample(_market_sample_spec, seed_seq_list=None)
|
|
139
141
|
|
|
@@ -145,7 +147,7 @@ def _main(
|
|
|
145
147
|
)
|
|
146
148
|
_fig_norm = colors.Normalize(0.0, 1.0)
|
|
147
149
|
_cmap_kwargs = {"cmap": "cividis", "norm": _fig_norm}
|
|
148
|
-
_plt, _, _, _set_axis_def =
|
|
150
|
+
_plt, _, _, _set_axis_def = gbl.boundary_plot()
|
|
149
151
|
|
|
150
152
|
_fig_2dsg = _plt.figure(figsize=(8.5, 9.5), dpi=600)
|
|
151
153
|
|
|
@@ -204,7 +206,7 @@ def _main(
|
|
|
204
206
|
guidelins_std_vec,
|
|
205
207
|
_pcm_firm2_star,
|
|
206
208
|
_test_regime,
|
|
207
|
-
|
|
209
|
+
save_data_to_file=save_data_to_file,
|
|
208
210
|
)
|
|
209
211
|
|
|
210
212
|
_ax_now.scatter(
|
|
@@ -255,44 +257,44 @@ def _main(
|
|
|
255
257
|
if __name__ == "__main__":
|
|
256
258
|
# Get Guidelines parameter values
|
|
257
259
|
hmg_pub_year: Final = 2023
|
|
258
|
-
|
|
259
|
-
|
|
260
|
+
|
|
261
|
+
test_regime: UPPTestRegime = UPPTestRegime(
|
|
262
|
+
INVResolution.ENFT, UPPAggrSelector.MIN, UPPAggrSelector.MIN
|
|
260
263
|
)
|
|
264
|
+
|
|
261
265
|
r_bar = getattr(
|
|
262
|
-
|
|
263
|
-
"presumption"
|
|
264
|
-
if test_regime.resolution == isl.PolicySelector.ENFT
|
|
265
|
-
else "safeharbor",
|
|
266
|
+
gbl.GuidelinesThresholds(hmg_pub_year),
|
|
267
|
+
"presumption" if test_regime.resolution == INVResolution.ENFT else "safeharbor",
|
|
266
268
|
).rec
|
|
267
269
|
|
|
268
270
|
sample_sz = 10**7
|
|
269
271
|
|
|
270
|
-
market_sample_spec =
|
|
272
|
+
market_sample_spec = MarketSampleSpec(
|
|
271
273
|
sample_sz,
|
|
272
274
|
r_bar,
|
|
273
275
|
share_spec=ShareSpec(
|
|
274
|
-
|
|
276
|
+
RECConstants.INOUT, SHRConstants.UNI, DIST_PARMS_DEFAULT, None
|
|
275
277
|
),
|
|
276
278
|
)
|
|
277
279
|
|
|
278
|
-
save_data_to_file_flag =
|
|
280
|
+
save_data_to_file_flag = True
|
|
279
281
|
if save_data_to_file_flag:
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
h5datafile,
|
|
290
|
-
"Intrinsic clearance stats",
|
|
282
|
+
h5_path = DATA_DIR / PROG_PATH.with_suffix(".h5").name
|
|
283
|
+
(_, h5_file, h5_group), h5_subgroup_name = utl.initialize_hd5(
|
|
284
|
+
h5_path, hmg_pub_year, test_regime
|
|
285
|
+
) # type: ignore
|
|
286
|
+
|
|
287
|
+
h5_subgroup = h5_file.create_group(
|
|
288
|
+
h5_group,
|
|
289
|
+
h5_subgroup_name,
|
|
290
|
+
title=f"Market sample specifications: {market_sample_spec}",
|
|
291
291
|
)
|
|
292
|
+
save_data_to_file: utl.SaveData = (True, h5_file, h5_subgroup)
|
|
292
293
|
else:
|
|
293
294
|
save_data_to_file = False
|
|
294
295
|
|
|
295
296
|
_main(hmg_pub_year, market_sample_spec, test_regime, save_data_to_file)
|
|
296
297
|
|
|
297
298
|
if save_data_to_file_flag:
|
|
299
|
+
save_data_to_file[1].flush() # type: ignore
|
|
298
300
|
save_data_to_file[1].close() # type: ignore
|
mergeron/gen/__init__.py
CHANGED
|
@@ -16,8 +16,8 @@ import enum
|
|
|
16
16
|
from dataclasses import dataclass
|
|
17
17
|
from typing import ClassVar, Protocol, TypeVar
|
|
18
18
|
|
|
19
|
-
import attrs
|
|
20
19
|
import numpy as np
|
|
20
|
+
from attrs import Attribute, define, field, validators
|
|
21
21
|
from numpy.typing import NBitBase, NDArray
|
|
22
22
|
|
|
23
23
|
from ..core.pseudorandom_numbers import DIST_PARMS_DEFAULT # noqa: TID252
|
|
@@ -29,14 +29,6 @@ TF = TypeVar("TF", bound=NBitBase)
|
|
|
29
29
|
TI = TypeVar("TI", bound=NBitBase)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
# https://stackoverflow.com/questions/54668000
|
|
33
|
-
class DataclassInstance(Protocol):
|
|
34
|
-
"""For type-hinting dataclass objects"""
|
|
35
|
-
|
|
36
|
-
__dataclass_asdict__: ClassVar
|
|
37
|
-
__dataclass_fields__: ClassVar
|
|
38
|
-
|
|
39
|
-
|
|
40
32
|
@enum.unique
|
|
41
33
|
class PRIConstants(tuple[bool, str | None], enum.ReprEnum):
|
|
42
34
|
"""Price specification.
|
|
@@ -91,7 +83,7 @@ class RECConstants(enum.StrEnum):
|
|
|
91
83
|
FIXED = "proportional"
|
|
92
84
|
|
|
93
85
|
|
|
94
|
-
@
|
|
86
|
+
@define(slots=True, frozen=True)
|
|
95
87
|
class ShareSpec:
|
|
96
88
|
"""Market share specification
|
|
97
89
|
|
|
@@ -150,7 +142,7 @@ class FM2Constants(enum.StrEnum):
|
|
|
150
142
|
SYM = "symmetric"
|
|
151
143
|
|
|
152
144
|
|
|
153
|
-
@
|
|
145
|
+
@define(slots=True, frozen=True)
|
|
154
146
|
class PCMSpec:
|
|
155
147
|
"""Price-cost margin (PCM) specification
|
|
156
148
|
|
|
@@ -224,18 +216,17 @@ class SSZConstants(float, enum.ReprEnum):
|
|
|
224
216
|
|
|
225
217
|
# Validators for selected attributes of MarketSampleSpec
|
|
226
218
|
def _sample_size_validator(
|
|
227
|
-
_object: MarketSampleSpec, _attribute:
|
|
219
|
+
_object: MarketSampleSpec, _attribute: Attribute, _value: int, /
|
|
228
220
|
) -> None:
|
|
229
|
-
if _value < 10**6
|
|
221
|
+
if _value < 10**6:
|
|
230
222
|
raise ValueError(
|
|
231
|
-
f"Sample size must be
|
|
223
|
+
f"Sample size must be not less than {10**6:,d}. Got, {_value:,d}."
|
|
232
224
|
)
|
|
233
225
|
|
|
234
226
|
|
|
235
227
|
def _recapture_rate_validator(
|
|
236
|
-
_object: MarketSampleSpec, _attribute:
|
|
228
|
+
_object: MarketSampleSpec, _attribute: Attribute, _value: float | None, /
|
|
237
229
|
) -> None:
|
|
238
|
-
# if _value < 10**6 or (np.log10(_value) % 1 != 0):
|
|
239
230
|
if _value and not (0 < _value <= 1):
|
|
240
231
|
raise ValueError("Recapture rate must lie in the interval, [0, 1).")
|
|
241
232
|
|
|
@@ -247,7 +238,7 @@ def _recapture_rate_validator(
|
|
|
247
238
|
|
|
248
239
|
|
|
249
240
|
def _share_spec_validator(
|
|
250
|
-
_instance: MarketSampleSpec, _attribute:
|
|
241
|
+
_instance: MarketSampleSpec, _attribute: Attribute, _value: ShareSpec, /
|
|
251
242
|
) -> None:
|
|
252
243
|
_r_bar = _instance.recapture_rate
|
|
253
244
|
if _value.dist_type == SHRConstants.UNI:
|
|
@@ -278,7 +269,7 @@ def _share_spec_validator(
|
|
|
278
269
|
|
|
279
270
|
|
|
280
271
|
def _pcm_spec_validator(
|
|
281
|
-
_instance: MarketSampleSpec, _attribute:
|
|
272
|
+
_instance: MarketSampleSpec, _attribute: Attribute, _value: PCMSpec, /
|
|
282
273
|
) -> None:
|
|
283
274
|
if (
|
|
284
275
|
_instance.share_spec.recapture_spec == RECConstants.FIXED
|
|
@@ -312,18 +303,18 @@ def _pcm_spec_validator(
|
|
|
312
303
|
)
|
|
313
304
|
|
|
314
305
|
|
|
315
|
-
@
|
|
306
|
+
@define(slots=True, frozen=True)
|
|
316
307
|
class MarketSampleSpec:
|
|
317
308
|
"""Parameter specification for market data generation."""
|
|
318
309
|
|
|
319
|
-
sample_size: int =
|
|
320
|
-
default=10**6,
|
|
321
|
-
validator=(attrs.validators.instance_of(int), _sample_size_validator),
|
|
310
|
+
sample_size: int = field(
|
|
311
|
+
default=10**6, validator=(validators.instance_of(int), _sample_size_validator)
|
|
322
312
|
)
|
|
323
313
|
"""sample size generated"""
|
|
324
314
|
|
|
325
|
-
recapture_rate: float | None =
|
|
326
|
-
default=None,
|
|
315
|
+
recapture_rate: float | None = field(
|
|
316
|
+
default=None,
|
|
317
|
+
validator=(validators.instance_of(float | None), _recapture_rate_validator),
|
|
327
318
|
)
|
|
328
319
|
"""market recapture rate
|
|
329
320
|
|
|
@@ -331,72 +322,119 @@ class MarketSampleSpec:
|
|
|
331
322
|
outside good choice probabilities (RECConstants.OUTIN).
|
|
332
323
|
"""
|
|
333
324
|
|
|
334
|
-
pr_sym_spec: PRIConstants =
|
|
325
|
+
pr_sym_spec: PRIConstants = field( # type: ignore
|
|
335
326
|
kw_only=True,
|
|
336
327
|
default=PRIConstants.SYM,
|
|
337
|
-
validator=
|
|
328
|
+
validator=validators.instance_of(PRIConstants), # type: ignore
|
|
338
329
|
)
|
|
339
330
|
"""Price specification, see PRIConstants"""
|
|
340
331
|
|
|
341
|
-
share_spec: ShareSpec =
|
|
332
|
+
share_spec: ShareSpec = field(
|
|
342
333
|
kw_only=True,
|
|
343
334
|
default=ShareSpec(RECConstants.INOUT, SHRConstants.UNI, None, None),
|
|
344
|
-
validator=[
|
|
335
|
+
validator=[validators.instance_of(ShareSpec), _share_spec_validator],
|
|
345
336
|
)
|
|
346
337
|
"""See definition of ShareSpec"""
|
|
347
338
|
|
|
348
|
-
pcm_spec: PCMSpec =
|
|
339
|
+
pcm_spec: PCMSpec = field(
|
|
349
340
|
kw_only=True,
|
|
350
341
|
default=PCMSpec(PCMConstants.UNI, FM2Constants.IID, None),
|
|
351
|
-
validator=[
|
|
342
|
+
validator=[validators.instance_of(PCMSpec), _pcm_spec_validator],
|
|
352
343
|
)
|
|
353
344
|
"""See definition of PCMSpec"""
|
|
354
345
|
|
|
355
|
-
hsr_filing_test_type: SSZConstants =
|
|
346
|
+
hsr_filing_test_type: SSZConstants = field( # type: ignore
|
|
356
347
|
kw_only=True,
|
|
357
348
|
default=SSZConstants.ONE,
|
|
358
|
-
validator=
|
|
349
|
+
validator=validators.instance_of(SSZConstants), # type: ignore
|
|
359
350
|
)
|
|
360
351
|
"""Method for modeling HSR filing threholds, see SSZConstants"""
|
|
361
352
|
|
|
362
353
|
|
|
354
|
+
@enum.unique
|
|
355
|
+
class INVResolution(enum.StrEnum):
|
|
356
|
+
CLRN = "clearance"
|
|
357
|
+
ENFT = "enforcement"
|
|
358
|
+
BOTH = "both"
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
@enum.unique
|
|
362
|
+
class UPPAggrSelector(enum.StrEnum):
|
|
363
|
+
"""
|
|
364
|
+
Aggregator selection for GUPPI and diversion ratio
|
|
365
|
+
|
|
366
|
+
"""
|
|
367
|
+
|
|
368
|
+
AVG = "average"
|
|
369
|
+
CPA = "cross-product-share-weighted average"
|
|
370
|
+
CPD = "cross-product-share-weighted distance"
|
|
371
|
+
DIS = "symmetrically-weighted distance"
|
|
372
|
+
MAX = "max"
|
|
373
|
+
MIN = "min"
|
|
374
|
+
OSA = "own-share-weighted average"
|
|
375
|
+
OSD = "own-share-weighted distance"
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
@define(slots=True, frozen=True)
|
|
379
|
+
class UPPTestRegime:
|
|
380
|
+
resolution: INVResolution = field( # type: ignore
|
|
381
|
+
default=INVResolution.ENFT,
|
|
382
|
+
validator=validators.instance_of(INVResolution), # type: ignore
|
|
383
|
+
)
|
|
384
|
+
guppi_aggregator: UPPAggrSelector = field( # type: ignore
|
|
385
|
+
default=UPPAggrSelector.MAX,
|
|
386
|
+
validator=validators.instance_of(UPPAggrSelector), # type: ignore
|
|
387
|
+
)
|
|
388
|
+
divr_aggregator: UPPAggrSelector | None = field( # type: ignore
|
|
389
|
+
default=guppi_aggregator,
|
|
390
|
+
validator=validators.instance_of(UPPAggrSelector | None), # type: ignore
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
# https://stackoverflow.com/questions/54668000
|
|
395
|
+
class DataclassInstance(Protocol):
|
|
396
|
+
"""Generic dataclass-instance"""
|
|
397
|
+
|
|
398
|
+
__dataclass_fields__: ClassVar
|
|
399
|
+
|
|
400
|
+
|
|
363
401
|
@dataclass(slots=True, frozen=True)
|
|
364
402
|
class MarketDataSample:
|
|
365
403
|
"""Container for generated markets data sample."""
|
|
366
404
|
|
|
367
|
-
frmshr_array: NDArray[np.
|
|
405
|
+
frmshr_array: NDArray[np.float64]
|
|
368
406
|
"""Merging-firm shares (with two merging firms)"""
|
|
369
407
|
|
|
370
|
-
pcm_array: NDArray[np.
|
|
408
|
+
pcm_array: NDArray[np.float64]
|
|
371
409
|
"""Merging-firms' prices (normalized to 1, in default specification)"""
|
|
372
410
|
|
|
373
|
-
price_array: NDArray[np.
|
|
411
|
+
price_array: NDArray[np.float64]
|
|
374
412
|
"""Merging-firms' price-cost margins (PCM)"""
|
|
375
413
|
|
|
376
|
-
fcounts: NDArray[np.
|
|
414
|
+
fcounts: NDArray[np.int64]
|
|
377
415
|
"""Number of firms in market"""
|
|
378
416
|
|
|
379
|
-
|
|
417
|
+
aggregate_purchase_prob: NDArray[np.float64]
|
|
380
418
|
"""
|
|
381
419
|
One (1) minus probability that the outside good is chosen
|
|
382
420
|
|
|
383
421
|
Converts market shares to choice probabilities by multiplication.
|
|
384
422
|
"""
|
|
385
423
|
|
|
386
|
-
nth_firm_share: NDArray[np.
|
|
424
|
+
nth_firm_share: NDArray[np.float64]
|
|
387
425
|
"""Market-share of n-th firm
|
|
388
426
|
|
|
389
427
|
Relevant for testing for draws the do or
|
|
390
428
|
do not meet HSR filing thresholds.
|
|
391
429
|
"""
|
|
392
430
|
|
|
393
|
-
divr_array: NDArray[np.
|
|
431
|
+
divr_array: NDArray[np.float64]
|
|
394
432
|
"""Diversion ratio between the merging firms"""
|
|
395
433
|
|
|
396
|
-
hhi_post: NDArray[np.
|
|
434
|
+
hhi_post: NDArray[np.float64]
|
|
397
435
|
"""Post-merger change in Herfindahl-Hirschmann Index (HHI)"""
|
|
398
436
|
|
|
399
|
-
hhi_delta: NDArray[np.
|
|
437
|
+
hhi_delta: NDArray[np.float64]
|
|
400
438
|
"""Change in HHI from combination of merging firms"""
|
|
401
439
|
|
|
402
440
|
|
|
@@ -425,7 +463,7 @@ class ShareDataSample:
|
|
|
425
463
|
class PriceDataSample:
|
|
426
464
|
"""Container for generated price array, and related."""
|
|
427
465
|
|
|
428
|
-
price_array: NDArray[np.
|
|
466
|
+
price_array: NDArray[np.float64]
|
|
429
467
|
"""Merging-firms' prices"""
|
|
430
468
|
|
|
431
469
|
hsr_filing_test: NDArray[np.bool_]
|
|
@@ -455,14 +493,38 @@ class MarginDataSample:
|
|
|
455
493
|
|
|
456
494
|
@dataclass(slots=True, frozen=True)
|
|
457
495
|
class UPPTestsRaw:
|
|
496
|
+
"""arrays marking test failures and successes
|
|
497
|
+
|
|
498
|
+
A test success is a draw ("market") that meeets the
|
|
499
|
+
specified test criterion, and a test failure is
|
|
500
|
+
one that does not; test criteria are defined and
|
|
501
|
+
evaluated in:code:`guidelines_stats.gen_upp_arrays`.
|
|
502
|
+
"""
|
|
503
|
+
|
|
458
504
|
guppi_test_simple: NDArray[np.bool_]
|
|
505
|
+
"""True if GUPPI estimate meets criterion"""
|
|
506
|
+
|
|
459
507
|
guppi_test_compound: NDArray[np.bool_]
|
|
508
|
+
"""True if both GUPPI estimate and diversion ratio estimate
|
|
509
|
+
meet criterion
|
|
510
|
+
"""
|
|
511
|
+
|
|
460
512
|
cmcr_test: NDArray[np.bool_]
|
|
513
|
+
"""True if CMCR estimate meets criterion"""
|
|
514
|
+
|
|
461
515
|
ipr_test: NDArray[np.bool_]
|
|
516
|
+
"""True if IPR (partial price-simulation) estimate meets criterion"""
|
|
462
517
|
|
|
463
518
|
|
|
464
519
|
@dataclass(slots=True, frozen=True)
|
|
465
520
|
class UPPTestsCounts:
|
|
521
|
+
"""counts of markets resolved as specified
|
|
522
|
+
|
|
523
|
+
Resolution is specified in a UPPTestRegime object.
|
|
524
|
+
"""
|
|
525
|
+
|
|
466
526
|
by_firm_count: NDArray[np.int64]
|
|
467
527
|
by_delta: NDArray[np.int64]
|
|
468
528
|
by_conczone: NDArray[np.int64]
|
|
529
|
+
"""Zones are "unoncentrated", "moderately concentrated", and "highly concentrated"
|
|
530
|
+
"""
|
|
@@ -116,7 +116,7 @@ def _gen_share_data(
|
|
|
116
116
|
|
|
117
117
|
def _gen_market_shares_uniform(
|
|
118
118
|
_s_size: int = 10**6,
|
|
119
|
-
_dist_parms_mktshr: NDArray[np.floating[TF]] | None = DIST_PARMS_DEFAULT,
|
|
119
|
+
_dist_parms_mktshr: NDArray[np.floating[TF]] | None = DIST_PARMS_DEFAULT, # type: ignore
|
|
120
120
|
_mktshr_rng_seed_seq: SeedSequence | None = None,
|
|
121
121
|
_nthreads: int = 16,
|
|
122
122
|
/,
|
|
@@ -141,8 +141,8 @@ def _gen_market_shares_uniform(
|
|
|
141
141
|
"""
|
|
142
142
|
|
|
143
143
|
_frmshr_array = np.empty((_s_size, 2), dtype=np.float64)
|
|
144
|
-
_dist_parms_mktshr = (
|
|
145
|
-
DIST_PARMS_DEFAULT if _dist_parms_mktshr is None else _dist_parms_mktshr
|
|
144
|
+
_dist_parms_mktshr: NDArray[np.floating] = (
|
|
145
|
+
DIST_PARMS_DEFAULT if _dist_parms_mktshr is None else _dist_parms_mktshr
|
|
146
146
|
)
|
|
147
147
|
_mrng = MultithreadedRNG(
|
|
148
148
|
_frmshr_array,
|
|
@@ -220,9 +220,9 @@ def _gen_market_shares_dirichlet_multisample(
|
|
|
220
220
|
|
|
221
221
|
"""
|
|
222
222
|
|
|
223
|
-
_firm_count_wts: np.
|
|
223
|
+
_firm_count_wts: NDArray[np.floating] = (
|
|
224
224
|
FCOUNT_WTS_DEFAULT if _firm_count_wts is None else _firm_count_wts
|
|
225
|
-
)
|
|
225
|
+
)
|
|
226
226
|
|
|
227
227
|
_min_choice_wt = 0.03 if _dist_type_dir == SHRConstants.DIR_FLAT_CONSTR else 0.00
|
|
228
228
|
_fcount_keys, _choice_wts = zip(
|
|
@@ -441,7 +441,7 @@ def _gen_pr_data(
|
|
|
441
441
|
)
|
|
442
442
|
# del _pr_max_ratio
|
|
443
443
|
|
|
444
|
-
|
|
444
|
+
_price_array = _price_array.astype(np.float64)
|
|
445
445
|
_rev_array = _price_array * _frmshr_array
|
|
446
446
|
_nth_firm_rev = _nth_firm_price * _nth_firm_share
|
|
447
447
|
|
mergeron/gen/data_generation.py
CHANGED
|
@@ -118,10 +118,7 @@ def gen_market_sample(
|
|
|
118
118
|
|
|
119
119
|
# Generate merging-firm price data
|
|
120
120
|
_price_data = _gen_pr_data(
|
|
121
|
-
|
|
122
|
-
_mktshr_data.nth_firm_share,
|
|
123
|
-
_mkt_sample_spec_here,
|
|
124
|
-
_pr_rng_seed_seq,
|
|
121
|
+
_mktshr_array[:, :2], _nth_firm_share, _mkt_sample_spec_here, _pr_rng_seed_seq
|
|
125
122
|
)
|
|
126
123
|
|
|
127
124
|
_price_array, _hsr_filing_test = (
|