mergeron 2025.739290.0__tar.gz → 2025.739290.1__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.
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/PKG-INFO +1 -1
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/pyproject.toml +1 -1
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/__init__.py +17 -1
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/core/guidelines_boundaries.py +69 -8
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/core/pseudorandom_numbers.py +1 -17
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/gen/data_generation.py +5 -11
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/README.rst +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/core/__init__.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/core/empirical_margin_distribution.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/core/ftc_merger_investigations_data.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/core/guidelines_boundary_functions.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/core/guidelines_boundary_functions_extra.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/data/__init__.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/data/damodaran_margin_data.xls +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/data/damodaran_margin_data_dict.msgpack +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/data/ftc_invdata.msgpack +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/demo/__init__.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/demo/visualize_empirical_margin_distribution.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/gen/__init__.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/gen/data_generation_functions.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/gen/enforcement_stats.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/gen/upp_tests.py +0 -0
- {mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: mergeron
|
|
3
|
-
Version: 2025.739290.
|
|
3
|
+
Version: 2025.739290.1
|
|
4
4
|
Summary: Analyze merger enforcement policy using Python
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: merger policy analysis,merger guidelines,merger screening,policy presumptions,concentration standards,upward pricing pressure,GUPPI
|
|
@@ -6,12 +6,13 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Literal
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
|
+
from numpy.random import SeedSequence
|
|
9
10
|
from numpy.typing import NDArray
|
|
10
11
|
from ruamel import yaml
|
|
11
12
|
|
|
12
13
|
_PKG_NAME: str = Path(__file__).parent.stem
|
|
13
14
|
|
|
14
|
-
VERSION = "2025.739290.
|
|
15
|
+
VERSION = "2025.739290.1"
|
|
15
16
|
|
|
16
17
|
__version__ = VERSION
|
|
17
18
|
|
|
@@ -66,6 +67,21 @@ type ArrayBIGINT = NDArray[np.int64]
|
|
|
66
67
|
),
|
|
67
68
|
)
|
|
68
69
|
|
|
70
|
+
# Add yaml representer, constructor for SeedSequence
|
|
71
|
+
this_yaml.representer.add_representer(
|
|
72
|
+
SeedSequence,
|
|
73
|
+
lambda _r, _d: _r.represent_mapping(
|
|
74
|
+
"!SeedSequence",
|
|
75
|
+
{
|
|
76
|
+
_a: getattr(_d, _a)
|
|
77
|
+
for _a in ("entropy", "spawn_key", "pool_size", "n_children_spawned")
|
|
78
|
+
},
|
|
79
|
+
),
|
|
80
|
+
)
|
|
81
|
+
this_yaml.constructor.add_constructor(
|
|
82
|
+
"!SeedSequence", lambda _c, _n, /: SeedSequence(**_c.construct_mapping(_n))
|
|
83
|
+
)
|
|
84
|
+
|
|
69
85
|
|
|
70
86
|
@enum.unique
|
|
71
87
|
class RECForm(enum.StrEnum):
|
{mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/core/guidelines_boundaries.py
RENAMED
|
@@ -13,6 +13,7 @@ from typing import Literal
|
|
|
13
13
|
import numpy as np
|
|
14
14
|
from attrs import Attribute, field, frozen, validators
|
|
15
15
|
from mpmath import mp, mpf # type: ignore
|
|
16
|
+
from ruamel import yaml
|
|
16
17
|
|
|
17
18
|
from .. import ( # noqa: TID252
|
|
18
19
|
DEFAULT_REC_RATIO,
|
|
@@ -21,6 +22,7 @@ from .. import ( # noqa: TID252
|
|
|
21
22
|
HMGPubYear,
|
|
22
23
|
RECForm,
|
|
23
24
|
UPPAggrSelector,
|
|
25
|
+
this_yaml,
|
|
24
26
|
)
|
|
25
27
|
from . import guidelines_boundary_functions as gbfn
|
|
26
28
|
|
|
@@ -42,6 +44,7 @@ class HMGThresholds:
|
|
|
42
44
|
ipr: float
|
|
43
45
|
|
|
44
46
|
|
|
47
|
+
@this_yaml.register_class
|
|
45
48
|
@frozen
|
|
46
49
|
class GuidelinesThresholds:
|
|
47
50
|
"""
|
|
@@ -147,7 +150,24 @@ class GuidelinesThresholds:
|
|
|
147
150
|
),
|
|
148
151
|
)
|
|
149
152
|
|
|
153
|
+
@classmethod
|
|
154
|
+
def to_yaml(
|
|
155
|
+
cls, _r: yaml.representer.SafeRepresenter, _d: GuidelinesThresholds
|
|
156
|
+
) -> yaml.MappingNode:
|
|
157
|
+
_ret: yaml.MappingNode = _r.represent_mapping(
|
|
158
|
+
f"!{cls.__name__}",
|
|
159
|
+
{_a.name: getattr(_d, _a.name) for _a in _d.__attrs_attrs__},
|
|
160
|
+
)
|
|
161
|
+
return _ret
|
|
162
|
+
|
|
163
|
+
@classmethod
|
|
164
|
+
def from_yaml(
|
|
165
|
+
cls, _c: yaml.constructor.SafeConstructor, _n: yaml.MappingNode
|
|
166
|
+
) -> GuidelinesThresholds:
|
|
167
|
+
return cls(**_c.construct_mapping(_n))
|
|
150
168
|
|
|
169
|
+
|
|
170
|
+
@this_yaml.register_class
|
|
151
171
|
@frozen
|
|
152
172
|
class ConcentrationBoundary:
|
|
153
173
|
"""Concentration parameters, boundary coordinates, and area under concentration boundary."""
|
|
@@ -184,12 +204,12 @@ class ConcentrationBoundary:
|
|
|
184
204
|
kw_only=False, default=5, validator=validators.instance_of(int)
|
|
185
205
|
)
|
|
186
206
|
|
|
187
|
-
coordinates: ArrayDouble = field(init=False, kw_only=True)
|
|
188
|
-
"""Market-share pairs as Cartesian coordinates of points on the concentration boundary."""
|
|
189
|
-
|
|
190
207
|
area: float = field(init=False, kw_only=True)
|
|
191
208
|
"""Area under the concentration boundary."""
|
|
192
209
|
|
|
210
|
+
coordinates: ArrayDouble = field(init=False, kw_only=True)
|
|
211
|
+
"""Market-share pairs as Cartesian coordinates of points on the concentration boundary."""
|
|
212
|
+
|
|
193
213
|
def __attrs_post_init__(self, /) -> None:
|
|
194
214
|
match self.measure_name:
|
|
195
215
|
case "ΔHHI":
|
|
@@ -202,10 +222,31 @@ class ConcentrationBoundary:
|
|
|
202
222
|
_conc_fn = gbfn.hhi_post_contrib_boundary
|
|
203
223
|
|
|
204
224
|
_boundary = _conc_fn(self.threshold, dps=self.precision)
|
|
205
|
-
object.__setattr__(self, "coordinates", _boundary.coordinates)
|
|
206
225
|
object.__setattr__(self, "area", _boundary.area)
|
|
226
|
+
object.__setattr__(self, "coordinates", _boundary.coordinates)
|
|
227
|
+
|
|
228
|
+
@classmethod
|
|
229
|
+
def to_yaml(
|
|
230
|
+
cls, _r: yaml.representer.SafeRepresenter, _d: ConcentrationBoundary
|
|
231
|
+
) -> yaml.MappingNode:
|
|
232
|
+
_ret: yaml.MappingNode = _r.represent_mapping(
|
|
233
|
+
f"!{cls.__name__}",
|
|
234
|
+
{
|
|
235
|
+
_a.name: getattr(_d, _a.name)
|
|
236
|
+
for _a in _d.__attrs_attrs__
|
|
237
|
+
if _a.name not in ("area", "coordinates")
|
|
238
|
+
},
|
|
239
|
+
)
|
|
240
|
+
return _ret
|
|
207
241
|
|
|
242
|
+
@classmethod
|
|
243
|
+
def from_yaml(
|
|
244
|
+
cls, _c: yaml.constructor.SafeConstructor, _n: yaml.MappingNode
|
|
245
|
+
) -> ConcentrationBoundary:
|
|
246
|
+
return cls(**_c.construct_mapping(_n))
|
|
208
247
|
|
|
248
|
+
|
|
249
|
+
@this_yaml.register_class
|
|
209
250
|
@frozen
|
|
210
251
|
class DiversionRatioBoundary:
|
|
211
252
|
"""
|
|
@@ -310,12 +351,12 @@ class DiversionRatioBoundary:
|
|
|
310
351
|
|
|
311
352
|
"""
|
|
312
353
|
|
|
313
|
-
coordinates: ArrayDouble = field(init=False, kw_only=True)
|
|
314
|
-
"""Market-share pairs as Cartesian coordinates of points on the diversion ratio boundary."""
|
|
315
|
-
|
|
316
354
|
area: float = field(init=False, kw_only=True)
|
|
317
355
|
"""Area under the diversion ratio boundary."""
|
|
318
356
|
|
|
357
|
+
coordinates: ArrayDouble = field(init=False, kw_only=True)
|
|
358
|
+
"""Market-share pairs as Cartesian coordinates of points on the diversion ratio boundary."""
|
|
359
|
+
|
|
319
360
|
def __attrs_post_init__(self, /) -> None:
|
|
320
361
|
_share_ratio = critical_share_ratio(
|
|
321
362
|
self.diversion_ratio, r_bar=self.recapture_ratio
|
|
@@ -359,8 +400,28 @@ class DiversionRatioBoundary:
|
|
|
359
400
|
_upp_agg_kwargs |= {"agg_method": _aggregator, "weighting": _wgt_type}
|
|
360
401
|
|
|
361
402
|
_boundary = _upp_agg_fn(_share_ratio, self.recapture_ratio, **_upp_agg_kwargs)
|
|
362
|
-
object.__setattr__(self, "coordinates", _boundary.coordinates)
|
|
363
403
|
object.__setattr__(self, "area", _boundary.area)
|
|
404
|
+
object.__setattr__(self, "coordinates", _boundary.coordinates)
|
|
405
|
+
|
|
406
|
+
@classmethod
|
|
407
|
+
def to_yaml(
|
|
408
|
+
cls, _r: yaml.representer.SafeRepresenter, _d: DiversionRatioBoundary
|
|
409
|
+
) -> yaml.MappingNode:
|
|
410
|
+
_ret: yaml.MappingNode = _r.represent_mapping(
|
|
411
|
+
f"!{cls.__name__}",
|
|
412
|
+
{
|
|
413
|
+
_a.name: getattr(_d, _a.name)
|
|
414
|
+
for _a in _d.__attrs_attrs__
|
|
415
|
+
if _a.name not in ("area", "coordinates")
|
|
416
|
+
},
|
|
417
|
+
)
|
|
418
|
+
return _ret
|
|
419
|
+
|
|
420
|
+
@classmethod
|
|
421
|
+
def from_yaml(
|
|
422
|
+
cls, _c: yaml.constructor.SafeConstructor, _n: yaml.MappingNode
|
|
423
|
+
) -> DiversionRatioBoundary:
|
|
424
|
+
return cls(**_c.construct_mapping(_n))
|
|
364
425
|
|
|
365
426
|
|
|
366
427
|
def guppi_from_delta(
|
|
@@ -16,7 +16,7 @@ import numpy as np
|
|
|
16
16
|
from attrs import Attribute, Converter, define, field
|
|
17
17
|
from numpy.random import PCG64DXSM, Generator, SeedSequence
|
|
18
18
|
|
|
19
|
-
from .. import NTHREADS, VERSION, ArrayDouble, ArrayFloat
|
|
19
|
+
from .. import NTHREADS, VERSION, ArrayDouble, ArrayFloat # noqa: TID252
|
|
20
20
|
|
|
21
21
|
__version__ = VERSION
|
|
22
22
|
|
|
@@ -24,22 +24,6 @@ DEFAULT_DIST_PARMS: ArrayFloat = np.array([0.0, 1.0], float)
|
|
|
24
24
|
DEFAULT_BETA_DIST_PARMS: ArrayFloat = np.array([1.0, 1.0], float)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
# Add yaml representer, constructor for SeedSequence
|
|
28
|
-
this_yaml.representer.add_representer(
|
|
29
|
-
SeedSequence,
|
|
30
|
-
lambda _r, _d: _r.represent_mapping(
|
|
31
|
-
"!SeedSequence",
|
|
32
|
-
{
|
|
33
|
-
_a: getattr(_d, _a)
|
|
34
|
-
for _a in ("entropy", "spawn_key", "pool_size", "n_children_spawned")
|
|
35
|
-
},
|
|
36
|
-
),
|
|
37
|
-
)
|
|
38
|
-
this_yaml.constructor.add_constructor(
|
|
39
|
-
"!SeedSequence", lambda _c, _n, /: SeedSequence(**_c.construct_mapping(_n))
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
27
|
def prng(_s: SeedSequence | None = None, /) -> np.random.Generator:
|
|
44
28
|
"""Adopt the PCG64DXSM bit-generator, the future default in numpy.default_rng().
|
|
45
29
|
|
|
@@ -34,7 +34,7 @@ from .data_generation_functions import (
|
|
|
34
34
|
gen_margin_price_data,
|
|
35
35
|
gen_share_data,
|
|
36
36
|
)
|
|
37
|
-
from .upp_tests import
|
|
37
|
+
from .upp_tests import compute_upp_test_counts
|
|
38
38
|
|
|
39
39
|
__version__ = VERSION
|
|
40
40
|
|
|
@@ -51,12 +51,6 @@ class SamplingFunctionKWArgs(TypedDict, total=False):
|
|
|
51
51
|
nthreads: int
|
|
52
52
|
"""number of parallel threads to use"""
|
|
53
53
|
|
|
54
|
-
save_data_to_file: SaveData
|
|
55
|
-
"""optionally save data to HDF5 file"""
|
|
56
|
-
|
|
57
|
-
saved_array_name_suffix: str
|
|
58
|
-
"""optionally specify a suffix for the HDF5 array names"""
|
|
59
|
-
|
|
60
54
|
|
|
61
55
|
def _seed_data_conv(_v: SeedSequenceData | None, _i: MarketSample) -> SeedSequenceData:
|
|
62
56
|
if isinstance(_v, SeedSequenceData):
|
|
@@ -104,9 +98,9 @@ class MarketSample:
|
|
|
104
98
|
and _v.firm2_pcm_constraint == FM2Constraint.MNL
|
|
105
99
|
):
|
|
106
100
|
raise ValueError(
|
|
107
|
-
f'Specification of "
|
|
108
|
-
|
|
109
|
-
f
|
|
101
|
+
f'Specification of "PCMSpec.firm2_pcm_constraint", as {FM2Constraint.MNL!r} '
|
|
102
|
+
f'requires that "ShareSpec.recapture_form" be {RECForm.INOUT!r} '
|
|
103
|
+
f"or {RECForm.OUTIN!r}, not {RECForm.FIXED!r} as presently specified"
|
|
110
104
|
)
|
|
111
105
|
|
|
112
106
|
price_spec: PriceSpec = field(
|
|
@@ -484,7 +478,7 @@ class MarketSample:
|
|
|
484
478
|
{
|
|
485
479
|
_a.name: getattr(_d, _a.name)
|
|
486
480
|
for _a in _d.__attrs_attrs__
|
|
487
|
-
if _a.
|
|
481
|
+
if _a.name not in ("data", "enf_counts")
|
|
488
482
|
},
|
|
489
483
|
)
|
|
490
484
|
return _ret
|
|
File without changes
|
|
File without changes
|
{mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/core/empirical_margin_distribution.py
RENAMED
|
File without changes
|
|
File without changes
|
{mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/core/guidelines_boundary_functions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/data/damodaran_margin_data.xls
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mergeron-2025.739290.0 → mergeron-2025.739290.1}/src/mergeron/gen/data_generation_functions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|