mergeron 2024.738936.2__py3-none-any.whl → 2024.738940.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 +4 -2
- mergeron/core/guidelines_standards.py +137 -83
- mergeron/examples/concentration_as_diversion.py +30 -30
- mergeron/examples/investigations_stats_sim_tables.py +22 -29
- mergeron/examples/safeharbor_boundaries_for_mergers_with_asymmetric_shares.py +13 -13
- mergeron/examples/safeharbor_boundaries_for_symmetric_firm_mergers.py +3 -3
- mergeron/examples/sound_guppi_safeharbor.py +31 -28
- mergeron/examples/testIntrinsicClearanceRates.py +12 -12
- mergeron/examples/visualize_guidelines_tests.py +34 -29
- mergeron/gen/__init__.py +463 -0
- mergeron/gen/_data_generation_functions_nonpublic.py +626 -0
- mergeron/gen/data_generation.py +45 -989
- mergeron/gen/guidelines_tests.py +122 -99
- mergeron/gen/investigations_stats.py +10 -12
- mergeron/jinja_LaTex_templates/clrrate_cis_summary_table_template.tex.jinja2 +1 -1
- mergeron/jinja_LaTex_templates/ftcinvdata_summarypaired_table_template.tex.jinja2 +1 -1
- {mergeron-2024.738936.2.dist-info → mergeron-2024.738940.0.dist-info}/METADATA +1 -1
- {mergeron-2024.738936.2.dist-info → mergeron-2024.738940.0.dist-info}/RECORD +19 -18
- {mergeron-2024.738936.2.dist-info → mergeron-2024.738940.0.dist-info}/WHEEL +0 -0
mergeron/gen/__init__.py
CHANGED
|
@@ -1,5 +1,468 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Defines constants and containers for industry data generation and testing
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
1
8
|
from importlib.metadata import version
|
|
2
9
|
|
|
3
10
|
from .. import _PKG_NAME # noqa: TID252
|
|
4
11
|
|
|
5
12
|
__version__ = version(_PKG_NAME)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
import enum
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from typing import ClassVar, Protocol, TypeVar
|
|
18
|
+
|
|
19
|
+
import attrs
|
|
20
|
+
import numpy as np
|
|
21
|
+
from numpy.typing import NBitBase, NDArray
|
|
22
|
+
|
|
23
|
+
from ..core.pseudorandom_numbers import DIST_PARMS_DEFAULT # noqa: TID252
|
|
24
|
+
|
|
25
|
+
EMPTY_ARRAY_DEFAULT = np.zeros(2)
|
|
26
|
+
FCOUNT_WTS_DEFAULT = ((_nr := np.arange(1, 6)[::-1]) / _nr.sum()).astype(np.float64)
|
|
27
|
+
|
|
28
|
+
TF = TypeVar("TF", bound=NBitBase)
|
|
29
|
+
TI = TypeVar("TI", bound=NBitBase)
|
|
30
|
+
|
|
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
|
+
@enum.unique
|
|
41
|
+
class PRIConstants(tuple[bool, str | None], enum.ReprEnum):
|
|
42
|
+
"""Price specification.
|
|
43
|
+
|
|
44
|
+
Whether prices are symmetric and, if not, the direction of correlation, if any.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
SYM = (True, None)
|
|
48
|
+
ZERO = (False, None)
|
|
49
|
+
NEG = (False, "negative share-correlation")
|
|
50
|
+
POS = (False, "positive share-correlation")
|
|
51
|
+
CSY = (False, "market-wide cost-symmetry")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@enum.unique
|
|
55
|
+
class SHRConstants(enum.StrEnum):
|
|
56
|
+
"""Market share distributions."""
|
|
57
|
+
|
|
58
|
+
UNI = "Uniform"
|
|
59
|
+
"""Uniform distribution over the 3-simplex"""
|
|
60
|
+
|
|
61
|
+
DIR_FLAT = "Flat Dirichlet"
|
|
62
|
+
"""Shape parameter for all merging-firm-shares is unity (1)"""
|
|
63
|
+
|
|
64
|
+
DIR_FLAT_CONSTR = "Flat Dirichlet - Constrained"
|
|
65
|
+
"""Impose minimum probablility weight on each firm-count
|
|
66
|
+
|
|
67
|
+
Only firm-counts with probability weight of no less than 3%
|
|
68
|
+
are included for data generation.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
DIR_ASYM = "Asymmetric Dirichlet"
|
|
72
|
+
"""Share distribution for merging-firm shares has a higher peak share
|
|
73
|
+
|
|
74
|
+
Shape parameter for merging-firm-share is 2.5, and 1.0 for all others.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
DIR_COND = "Conditional Dirichlet"
|
|
78
|
+
"""Shape parameters for non-merging firms is proportional
|
|
79
|
+
|
|
80
|
+
Shape parameters for merging-firm-share are 2.0 each; and
|
|
81
|
+
are equiproportional and add to 2.0 for all non-merging-firm-shares.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@enum.unique
|
|
86
|
+
class RECConstants(enum.StrEnum):
|
|
87
|
+
"""Recapture rate - derivation methods."""
|
|
88
|
+
|
|
89
|
+
INOUT = "inside-out"
|
|
90
|
+
OUTIN = "outside-in"
|
|
91
|
+
FIXED = "proportional"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@attrs.define(slots=True, frozen=True)
|
|
95
|
+
class ShareSpec:
|
|
96
|
+
"""Market share specification
|
|
97
|
+
|
|
98
|
+
Notes
|
|
99
|
+
-----
|
|
100
|
+
If recapture is determined "outside-in", market shares cannot have
|
|
101
|
+
Uniform distribution.
|
|
102
|
+
|
|
103
|
+
If sample with varying firm counts is required, market shares must
|
|
104
|
+
be specified as having a supported Dirichlet distribution.
|
|
105
|
+
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
recapture_spec: RECConstants
|
|
109
|
+
"""see RECConstants"""
|
|
110
|
+
|
|
111
|
+
dist_type: SHRConstants
|
|
112
|
+
"""see SHRConstants"""
|
|
113
|
+
|
|
114
|
+
dist_parms: NDArray[np.float64] | None
|
|
115
|
+
"""Parameters for tailoring market-share distribution
|
|
116
|
+
|
|
117
|
+
For Uniform distribution, bounds of the distribution; defaults to `(0, 1)`;
|
|
118
|
+
for Beta distribution, shape parameters, defaults to `(1, 1)`;
|
|
119
|
+
for Bounded-Beta distribution, vector of (min, max, mean, std. deviation), non-optional;
|
|
120
|
+
for Dirichlet-type distributions, a vector of shape parameters of length
|
|
121
|
+
no less than the length of firm-count weights below; defaults depend on
|
|
122
|
+
type of Dirichlet-distribution specified.
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
firm_counts_weights: NDArray[np.float64 | np.int64] | None
|
|
126
|
+
"""relative or absolute frequencies of firm counts
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
Given frequencies are exogenous to generated market data sample;
|
|
130
|
+
defaults to FCOUNT_WTS_DEFAULT, which specifies firm-counts of 2 to 6
|
|
131
|
+
with weights in descending order from 5 to 1."""
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@enum.unique
|
|
135
|
+
class PCMConstants(enum.StrEnum):
|
|
136
|
+
"""Margin distributions."""
|
|
137
|
+
|
|
138
|
+
UNI = "Uniform"
|
|
139
|
+
BETA = "Beta"
|
|
140
|
+
BETA_BND = "Bounded Beta"
|
|
141
|
+
EMPR = "Damodaran margin data"
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@enum.unique
|
|
145
|
+
class FM2Constants(enum.StrEnum):
|
|
146
|
+
"""Firm 2 margins - derivation methods."""
|
|
147
|
+
|
|
148
|
+
IID = "i.i.d"
|
|
149
|
+
MNL = "MNL-dep"
|
|
150
|
+
SYM = "symmetric"
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@attrs.define(slots=True, frozen=True)
|
|
154
|
+
class PCMSpec:
|
|
155
|
+
"""Price-cost margin (PCM) specification
|
|
156
|
+
|
|
157
|
+
If price-cost margins are specified as having Beta distribution,
|
|
158
|
+
`dist_parms` is specified as a pair of positive, non-zero shape parameters of
|
|
159
|
+
the standard Beta distribution. Specifying shape parameters :code:`np.array([1, 1])`
|
|
160
|
+
is known equivalent to specifying uniform distribution over
|
|
161
|
+
the interval :math:`[0, 1]`. If price-cost margins are specified as having
|
|
162
|
+
Bounded-Beta distribution, `dist_parms` is specified as
|
|
163
|
+
the tuple, (`mean`, `std deviation`, `min`, `max`), where `min` and `max`
|
|
164
|
+
are lower- and upper-bounds respectively within the interval :math:`[0, 1]`.
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
dist_type: PCMConstants
|
|
170
|
+
"""See PCMConstants"""
|
|
171
|
+
|
|
172
|
+
firm2_pcm_constraint: FM2Constants
|
|
173
|
+
"""See FM2Constants"""
|
|
174
|
+
|
|
175
|
+
dist_parms: NDArray[np.float64] | None
|
|
176
|
+
"""Parameter specification for tailoring PCM distribution
|
|
177
|
+
|
|
178
|
+
For Uniform distribution, bounds of the distribution; defaults to `(0, 1)`;
|
|
179
|
+
for Beta distribution, shape parameters, defaults to `(1, 1)`;
|
|
180
|
+
for Bounded-Beta distribution, vector of (min, max, mean, std. deviation), non-optional;
|
|
181
|
+
for empirical distribution based on Damodaran margin data, optional, ignored
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@enum.unique
|
|
186
|
+
class SSZConstants(float, enum.ReprEnum):
|
|
187
|
+
"""
|
|
188
|
+
Scale factors to offset sample size reduction.
|
|
189
|
+
|
|
190
|
+
Sample size reduction occurs when imposing a HSR filing test
|
|
191
|
+
or equilibrium condition under MNL demand.
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
HSR_NTH = 1.666667
|
|
195
|
+
"""
|
|
196
|
+
For HSR filing requirement.
|
|
197
|
+
|
|
198
|
+
When filing requirement is assumed met if maximum merging-firm shares exceeds
|
|
199
|
+
ten (10) times the n-th firm's share and minimum merging-firm share is
|
|
200
|
+
no less than n-th firm's share. To assure that the number of draws available
|
|
201
|
+
after applying the given restriction, the initial number of draws is larger than
|
|
202
|
+
the sample size by the given scale factor.
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
HSR_TEN = 1.234567
|
|
206
|
+
"""
|
|
207
|
+
For alternative HSR filing requirement,
|
|
208
|
+
|
|
209
|
+
When filing requirement is assumed met if merging-firm shares exceed 10:1 ratio
|
|
210
|
+
to each other.
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
MNL_DEP = 1.25
|
|
214
|
+
"""
|
|
215
|
+
For restricted PCM's.
|
|
216
|
+
|
|
217
|
+
When merging firm's PCMs are constrained for consistency with f.o.c.s from
|
|
218
|
+
profit maximization under Nash-Bertrand oligopoly with MNL demand.
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
ONE = 1.00
|
|
222
|
+
"""When initial set of draws is not restricted in any way."""
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# Validators for selected attributes of MarketSampleSpec
|
|
226
|
+
def _sample_size_validator(
|
|
227
|
+
_object: MarketSampleSpec, _attribute: attrs.Attribute, _value: int, /
|
|
228
|
+
) -> None:
|
|
229
|
+
if _value < 10**6 or (_value % 10**5 != 0):
|
|
230
|
+
raise ValueError(
|
|
231
|
+
f"Sample size must be a multiple of {10** 4:,d} and not less than {10** 6:,d}."
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _recapture_rate_validator(
|
|
236
|
+
_object: MarketSampleSpec, _attribute: attrs.Attribute, _value: float | None, /
|
|
237
|
+
) -> None:
|
|
238
|
+
# if _value < 10**6 or (np.log10(_value) % 1 != 0):
|
|
239
|
+
if _value and not (0 < _value <= 1):
|
|
240
|
+
raise ValueError("Recapture rate must lie in the interval, [0, 1).")
|
|
241
|
+
|
|
242
|
+
if _value and _object.share_spec.recapture_spec == RECConstants.OUTIN:
|
|
243
|
+
raise ValueError(
|
|
244
|
+
"Market share specification requires estimation of recapture rate from "
|
|
245
|
+
"generated data. Either delete recapture rate specification or set it to None."
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _share_spec_validator(
|
|
250
|
+
_instance: MarketSampleSpec, _attribute: attrs.Attribute, _value: ShareSpec, /
|
|
251
|
+
) -> None:
|
|
252
|
+
_r_bar = _instance.recapture_rate
|
|
253
|
+
if _value.dist_type == SHRConstants.UNI:
|
|
254
|
+
if _value.recapture_spec == RECConstants.OUTIN:
|
|
255
|
+
raise ValueError(
|
|
256
|
+
f"Invalid recapture specification, {_value.recapture_spec!r} "
|
|
257
|
+
"for market share specification with Uniform distribution. "
|
|
258
|
+
"Redefine the market-sample specification, modifying the ."
|
|
259
|
+
"market-share specification or the recapture specification."
|
|
260
|
+
)
|
|
261
|
+
elif _value.firm_counts_weights is not None:
|
|
262
|
+
raise ValueError(
|
|
263
|
+
"Generated data for markets with specified firm-counts or "
|
|
264
|
+
"varying firm counts are not feasible with market shares "
|
|
265
|
+
"with Uniform distribution. Consider revising the "
|
|
266
|
+
r"distribution type to {SHRConstants.DIR_FLAT}, which gives "
|
|
267
|
+
"uniformly distributed draws on the :math:`n+1` simplex "
|
|
268
|
+
"for firm-count, :math:`n`."
|
|
269
|
+
)
|
|
270
|
+
# Outside-in calibration only valid for Dir-distributed shares
|
|
271
|
+
elif _value.recapture_spec != RECConstants.OUTIN and (
|
|
272
|
+
_r_bar is None or not isinstance(_r_bar, float)
|
|
273
|
+
):
|
|
274
|
+
raise ValueError(
|
|
275
|
+
f"Recapture specification, {_value.recapture_spec!r} requires that "
|
|
276
|
+
"the market sample specification inclues a recapture rate."
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _pcm_spec_validator(
|
|
281
|
+
_instance: MarketSampleSpec, _attribute: attrs.Attribute, _value: PCMSpec, /
|
|
282
|
+
) -> None:
|
|
283
|
+
if (
|
|
284
|
+
_instance.share_spec.recapture_spec == RECConstants.FIXED
|
|
285
|
+
and _value.firm2_pcm_constraint == FM2Constants.MNL
|
|
286
|
+
):
|
|
287
|
+
raise ValueError(
|
|
288
|
+
"{} {} {}".format(
|
|
289
|
+
f'Specification of "recapture_spec", "{_instance.share_spec.recapture_spec}"',
|
|
290
|
+
"requires Firm 2 margin must have property, ",
|
|
291
|
+
f'"{FM2Constants.IID}" or "{FM2Constants.SYM}".',
|
|
292
|
+
)
|
|
293
|
+
)
|
|
294
|
+
elif _value.dist_type.name.startswith("BETA"):
|
|
295
|
+
if _value.dist_parms is None:
|
|
296
|
+
pass
|
|
297
|
+
elif np.array_equal(_value.dist_parms, DIST_PARMS_DEFAULT):
|
|
298
|
+
raise ValueError(
|
|
299
|
+
f"The distribution parameters, {DIST_PARMS_DEFAULT!r} "
|
|
300
|
+
"are not valid with margin distribution, {_dist_type_pcm!r}"
|
|
301
|
+
)
|
|
302
|
+
elif (
|
|
303
|
+
_value.dist_type == PCMConstants.BETA
|
|
304
|
+
and len(_value.dist_parms) != len(("max", "min"))
|
|
305
|
+
) or (
|
|
306
|
+
_value.dist_type == PCMConstants.BETA_BND
|
|
307
|
+
and len(_value.dist_parms) != len(("mu", "sigma", "max", "min"))
|
|
308
|
+
):
|
|
309
|
+
raise ValueError(
|
|
310
|
+
f"Given number, {len(_value.dist_parms)} of parameters "
|
|
311
|
+
f'for PCM with distribution, "{_value.dist_type}" is incorrect.'
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
@attrs.define(slots=True, frozen=True)
|
|
316
|
+
class MarketSampleSpec:
|
|
317
|
+
"""Parameter specification for market data generation."""
|
|
318
|
+
|
|
319
|
+
sample_size: int = attrs.field(
|
|
320
|
+
default=10**6,
|
|
321
|
+
validator=(attrs.validators.instance_of(int), _sample_size_validator),
|
|
322
|
+
)
|
|
323
|
+
"""sample size generated"""
|
|
324
|
+
|
|
325
|
+
recapture_rate: float | None = attrs.field(
|
|
326
|
+
default=None, validator=attrs.validators.instance_of(float | None)
|
|
327
|
+
)
|
|
328
|
+
"""market recapture rate
|
|
329
|
+
|
|
330
|
+
Is None if market share specification requires generation of
|
|
331
|
+
outside good choice probabilities (RECConstants.OUTIN).
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
pr_sym_spec: PRIConstants = attrs.field( # type: ignore
|
|
335
|
+
kw_only=True,
|
|
336
|
+
default=PRIConstants.SYM,
|
|
337
|
+
validator=attrs.validators.instance_of(PRIConstants), # type: ignore
|
|
338
|
+
)
|
|
339
|
+
"""Price specification, see PRIConstants"""
|
|
340
|
+
|
|
341
|
+
share_spec: ShareSpec = attrs.field(
|
|
342
|
+
kw_only=True,
|
|
343
|
+
default=ShareSpec(RECConstants.INOUT, SHRConstants.UNI, None, None),
|
|
344
|
+
validator=[attrs.validators.instance_of(ShareSpec), _share_spec_validator],
|
|
345
|
+
)
|
|
346
|
+
"""See definition of ShareSpec"""
|
|
347
|
+
|
|
348
|
+
pcm_spec: PCMSpec = attrs.field(
|
|
349
|
+
kw_only=True,
|
|
350
|
+
default=PCMSpec(PCMConstants.UNI, FM2Constants.IID, None),
|
|
351
|
+
validator=[attrs.validators.instance_of(PCMSpec), _pcm_spec_validator],
|
|
352
|
+
)
|
|
353
|
+
"""See definition of PCMSpec"""
|
|
354
|
+
|
|
355
|
+
hsr_filing_test_type: SSZConstants = attrs.field( # type: ignore
|
|
356
|
+
kw_only=True,
|
|
357
|
+
default=SSZConstants.ONE,
|
|
358
|
+
validator=attrs.validators.instance_of(SSZConstants), # type: ignore
|
|
359
|
+
)
|
|
360
|
+
"""Method for modeling HSR filing threholds, see SSZConstants"""
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@dataclass(slots=True, frozen=True)
|
|
364
|
+
class MarketDataSample:
|
|
365
|
+
"""Container for generated markets data sample."""
|
|
366
|
+
|
|
367
|
+
frmshr_array: NDArray[np.floating]
|
|
368
|
+
"""Merging-firm shares (with two merging firms)"""
|
|
369
|
+
|
|
370
|
+
pcm_array: NDArray[np.floating]
|
|
371
|
+
"""Merging-firms' prices (normalized to 1, in default specification)"""
|
|
372
|
+
|
|
373
|
+
price_array: NDArray[np.floating]
|
|
374
|
+
"""Merging-firms' price-cost margins (PCM)"""
|
|
375
|
+
|
|
376
|
+
fcounts: NDArray[np.integer]
|
|
377
|
+
"""Number of firms in market"""
|
|
378
|
+
|
|
379
|
+
ratio_choice_prob_to_mktshr: NDArray[np.floating]
|
|
380
|
+
"""
|
|
381
|
+
One (1) minus probability that the outside good is chosen
|
|
382
|
+
|
|
383
|
+
Converts market shares to choice probabilities by multiplication.
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
nth_firm_share: NDArray[np.floating]
|
|
387
|
+
"""Market-share of n-th firm
|
|
388
|
+
|
|
389
|
+
Relevant for testing for draws the do or
|
|
390
|
+
do not meet HSR filing thresholds.
|
|
391
|
+
"""
|
|
392
|
+
|
|
393
|
+
divr_array: NDArray[np.floating]
|
|
394
|
+
"""Diversion ratio between the merging firms"""
|
|
395
|
+
|
|
396
|
+
hhi_post: NDArray[np.floating]
|
|
397
|
+
"""Post-merger change in Herfindahl-Hirschmann Index (HHI)"""
|
|
398
|
+
|
|
399
|
+
hhi_delta: NDArray[np.floating]
|
|
400
|
+
"""Change in HHI from combination of merging firms"""
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
@dataclass(slots=True, frozen=True)
|
|
404
|
+
class ShareDataSample:
|
|
405
|
+
"""Container for generated market shares.
|
|
406
|
+
|
|
407
|
+
Includes related measures of market structure
|
|
408
|
+
and aggregate purchase probability.
|
|
409
|
+
"""
|
|
410
|
+
|
|
411
|
+
mktshr_array: NDArray[np.float64]
|
|
412
|
+
"""All-firm shares (with two merging firms)"""
|
|
413
|
+
|
|
414
|
+
fcounts: NDArray[np.int64]
|
|
415
|
+
"""All-firm-count for each draw"""
|
|
416
|
+
|
|
417
|
+
nth_firm_share: NDArray[np.float64]
|
|
418
|
+
"""Market-share of n-th firm"""
|
|
419
|
+
|
|
420
|
+
aggregate_purchase_prob: NDArray[np.float64]
|
|
421
|
+
"""Converts market shares to choice probabilities by multiplication."""
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
@dataclass(slots=True, frozen=True)
|
|
425
|
+
class PriceDataSample:
|
|
426
|
+
"""Container for generated price array, and related."""
|
|
427
|
+
|
|
428
|
+
price_array: NDArray[np.floating]
|
|
429
|
+
"""Merging-firms' prices"""
|
|
430
|
+
|
|
431
|
+
hsr_filing_test: NDArray[np.bool_]
|
|
432
|
+
"""Flags draws as meeting HSR filing thresholds or not"""
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
@dataclass(slots=True, frozen=True)
|
|
436
|
+
class MarginDataSample:
|
|
437
|
+
"""Container for generated margin array and related MNL test array."""
|
|
438
|
+
|
|
439
|
+
pcm_array: NDArray[np.float64]
|
|
440
|
+
"""Merging-firms' PCMs"""
|
|
441
|
+
|
|
442
|
+
mnl_test_array: NDArray[np.bool_]
|
|
443
|
+
"""Flags infeasible observations as False and rest as True
|
|
444
|
+
|
|
445
|
+
Applying restrictions from Bertrand-Nash oligopoly
|
|
446
|
+
with MNL demand results in draws of Firm 2 PCM falling
|
|
447
|
+
outside the feabile interval,:math:`[0, 1]`, depending
|
|
448
|
+
on the configuration of merging firm shares. Such draws
|
|
449
|
+
are are flagged as infeasible (False)in :code:`mnl_test_array` while
|
|
450
|
+
draws with PCM values within the feasible range are
|
|
451
|
+
flagged as True. Used from filtering-out draws with
|
|
452
|
+
infeasible PCM.
|
|
453
|
+
"""
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
@dataclass(slots=True, frozen=True)
|
|
457
|
+
class UPPTestsRaw:
|
|
458
|
+
guppi_test_simple: NDArray[np.bool_]
|
|
459
|
+
guppi_test_compound: NDArray[np.bool_]
|
|
460
|
+
cmcr_test: NDArray[np.bool_]
|
|
461
|
+
ipr_test: NDArray[np.bool_]
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
@dataclass(slots=True, frozen=True)
|
|
465
|
+
class UPPTestsCounts:
|
|
466
|
+
by_firm_count: NDArray[np.int64]
|
|
467
|
+
by_delta: NDArray[np.int64]
|
|
468
|
+
by_conczone: NDArray[np.int64]
|