mergeron 2025.739290.0__tar.gz → 2025.739290.2__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.

Files changed (23) hide show
  1. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/PKG-INFO +1 -1
  2. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/pyproject.toml +1 -1
  3. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/__init__.py +17 -1
  4. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/core/ftc_merger_investigations_data.py +28 -5
  5. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/core/guidelines_boundaries.py +84 -8
  6. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/core/pseudorandom_numbers.py +1 -17
  7. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/gen/__init__.py +18 -1
  8. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/gen/data_generation.py +5 -11
  9. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/gen/data_generation_functions.py +18 -19
  10. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/README.rst +0 -0
  11. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/core/__init__.py +0 -0
  12. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/core/empirical_margin_distribution.py +0 -0
  13. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/core/guidelines_boundary_functions.py +0 -0
  14. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/core/guidelines_boundary_functions_extra.py +0 -0
  15. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/data/__init__.py +0 -0
  16. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/data/damodaran_margin_data.xls +0 -0
  17. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/data/damodaran_margin_data_dict.msgpack +0 -0
  18. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/data/ftc_invdata.msgpack +0 -0
  19. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/demo/__init__.py +0 -0
  20. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/demo/visualize_empirical_margin_distribution.py +0 -0
  21. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/gen/enforcement_stats.py +0 -0
  22. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/gen/upp_tests.py +0 -0
  23. {mergeron-2025.739290.0 → mergeron-2025.739290.2}/src/mergeron/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mergeron
3
- Version: 2025.739290.0
3
+ Version: 2025.739290.2
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
@@ -13,7 +13,7 @@ keywords = [
13
13
  "upward pricing pressure",
14
14
  "GUPPI",
15
15
  ]
16
- version = "2025.739290.0"
16
+ version = "2025.739290.2"
17
17
 
18
18
  # Classifiers list: https://pypi.org/classifiers/
19
19
  classifiers = [
@@ -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.0"
15
+ VERSION = "2025.739290.2"
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):
@@ -8,13 +8,16 @@ Reported row and column totals from source data are not stored.
8
8
 
9
9
  """
10
10
 
11
+ from __future__ import annotations
12
+
11
13
  import shutil
12
14
  from collections.abc import Mapping, Sequence
15
+ from dataclasses import dataclass
13
16
  from importlib import resources
14
17
  from operator import itemgetter
15
18
  from pathlib import Path
16
19
  from types import MappingProxyType
17
- from typing import Any, NamedTuple
20
+ from typing import Any
18
21
 
19
22
  import msgpack # type: ignore
20
23
  import msgpack_numpy as m # type: ignore
@@ -23,8 +26,9 @@ import re2 as re # type: ignore
23
26
  import urllib3
24
27
  from bs4 import BeautifulSoup
25
28
  from numpy.testing import assert_array_equal
29
+ from ruamel import yaml
26
30
 
27
- from .. import _PKG_NAME, DATA_DIR, VERSION, ArrayBIGINT # noqa: TID252
31
+ from .. import _PKG_NAME, DATA_DIR, EMPTY_ARRAYINT, VERSION, ArrayBIGINT # noqa: TID252
28
32
 
29
33
  __version__ = VERSION
30
34
 
@@ -89,11 +93,27 @@ CNT_FCOUNT_DICT = {
89
93
  }
90
94
 
91
95
 
92
- class INVTableData(NamedTuple):
96
+ @dataclass(slots=True, frozen=True)
97
+ class INVTableData:
93
98
  industry_group: str
94
99
  additional_evidence: str
95
100
  data_array: ArrayBIGINT
96
101
 
102
+ @classmethod
103
+ def to_yaml(
104
+ cls, _r: yaml.representer.SafeRepresenter, _d: INVTableData
105
+ ) -> yaml.MappingNode:
106
+ _ret: yaml.MappingNode = _r.represent_mapping(
107
+ f"!{cls.__name__}", {_a: getattr(_d, _a) for _a in _d.__dataclass_fields__}
108
+ )
109
+ return _ret
110
+
111
+ @classmethod
112
+ def from_yaml(
113
+ cls, _c: yaml.constructor.SafeConstructor, _n: yaml.MappingNode
114
+ ) -> INVTableData:
115
+ return cls(**_c.construct_mapping(_n))
116
+
97
117
 
98
118
  type INVData = Mapping[str, Mapping[str, Mapping[str, INVTableData]]]
99
119
  type _INVData_in = dict[str, dict[str, dict[str, INVTableData]]]
@@ -278,10 +298,13 @@ def _construct_new_period_data(
278
298
  _invdata_cuml_sub_table.data_array,
279
299
  )
280
300
 
281
- _invdata_base_sub_table = _invdata_base[_table_type].get(_table_no, None)
301
+ _invdata_base_sub_table = _invdata_base[_table_type].get(
302
+ _table_no, INVTableData("", "", EMPTY_ARRAYINT)
303
+ )
282
304
 
283
305
  (_invdata_base_ind_group, _invdata_base_evid_cond, _invdata_base_array) = (
284
- _invdata_base_sub_table or ("", "", None)
306
+ getattr(_invdata_base_sub_table, _a)
307
+ for _a in ("industry_group", "additional_evidence", "data_array")
285
308
  )
286
309
 
287
310
  # Some tables can't be constructed due to inconsistencies in the data
@@ -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
 
@@ -41,7 +43,23 @@ class HMGThresholds:
41
43
  cmcr: float
42
44
  ipr: float
43
45
 
46
+ @classmethod
47
+ def to_yaml(
48
+ cls, _r: yaml.representer.SafeRepresenter, _d: HMGThresholds
49
+ ) -> yaml.MappingNode:
50
+ _ret: yaml.MappingNode = _r.represent_mapping(
51
+ f"!{cls.__name__}", {_a: getattr(_d, _a) for _a in _d.__dataclass_fields__}
52
+ )
53
+ return _ret
54
+
55
+ @classmethod
56
+ def from_yaml(
57
+ cls, _c: yaml.constructor.SafeConstructor, _n: yaml.MappingNode
58
+ ) -> HMGThresholds:
59
+ return cls(**_c.construct_mapping(_n))
44
60
 
61
+
62
+ @this_yaml.register_class
45
63
  @frozen
46
64
  class GuidelinesThresholds:
47
65
  """
@@ -147,7 +165,24 @@ class GuidelinesThresholds:
147
165
  ),
148
166
  )
149
167
 
168
+ @classmethod
169
+ def to_yaml(
170
+ cls, _r: yaml.representer.SafeRepresenter, _d: GuidelinesThresholds
171
+ ) -> yaml.MappingNode:
172
+ _ret: yaml.MappingNode = _r.represent_mapping(
173
+ f"!{cls.__name__}",
174
+ {_a.name: getattr(_d, _a.name) for _a in _d.__attrs_attrs__},
175
+ )
176
+ return _ret
150
177
 
178
+ @classmethod
179
+ def from_yaml(
180
+ cls, _c: yaml.constructor.SafeConstructor, _n: yaml.MappingNode
181
+ ) -> GuidelinesThresholds:
182
+ return cls(**_c.construct_mapping(_n))
183
+
184
+
185
+ @this_yaml.register_class
151
186
  @frozen
152
187
  class ConcentrationBoundary:
153
188
  """Concentration parameters, boundary coordinates, and area under concentration boundary."""
@@ -184,12 +219,12 @@ class ConcentrationBoundary:
184
219
  kw_only=False, default=5, validator=validators.instance_of(int)
185
220
  )
186
221
 
187
- coordinates: ArrayDouble = field(init=False, kw_only=True)
188
- """Market-share pairs as Cartesian coordinates of points on the concentration boundary."""
189
-
190
222
  area: float = field(init=False, kw_only=True)
191
223
  """Area under the concentration boundary."""
192
224
 
225
+ coordinates: ArrayDouble = field(init=False, kw_only=True)
226
+ """Market-share pairs as Cartesian coordinates of points on the concentration boundary."""
227
+
193
228
  def __attrs_post_init__(self, /) -> None:
194
229
  match self.measure_name:
195
230
  case "ΔHHI":
@@ -202,10 +237,31 @@ class ConcentrationBoundary:
202
237
  _conc_fn = gbfn.hhi_post_contrib_boundary
203
238
 
204
239
  _boundary = _conc_fn(self.threshold, dps=self.precision)
205
- object.__setattr__(self, "coordinates", _boundary.coordinates)
206
240
  object.__setattr__(self, "area", _boundary.area)
241
+ object.__setattr__(self, "coordinates", _boundary.coordinates)
207
242
 
243
+ @classmethod
244
+ def to_yaml(
245
+ cls, _r: yaml.representer.SafeRepresenter, _d: ConcentrationBoundary
246
+ ) -> yaml.MappingNode:
247
+ _ret: yaml.MappingNode = _r.represent_mapping(
248
+ f"!{cls.__name__}",
249
+ {
250
+ _a.name: getattr(_d, _a.name)
251
+ for _a in _d.__attrs_attrs__
252
+ if _a.name not in ("area", "coordinates")
253
+ },
254
+ )
255
+ return _ret
256
+
257
+ @classmethod
258
+ def from_yaml(
259
+ cls, _c: yaml.constructor.SafeConstructor, _n: yaml.MappingNode
260
+ ) -> ConcentrationBoundary:
261
+ return cls(**_c.construct_mapping(_n))
208
262
 
263
+
264
+ @this_yaml.register_class
209
265
  @frozen
210
266
  class DiversionRatioBoundary:
211
267
  """
@@ -310,12 +366,12 @@ class DiversionRatioBoundary:
310
366
 
311
367
  """
312
368
 
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
369
  area: float = field(init=False, kw_only=True)
317
370
  """Area under the diversion ratio boundary."""
318
371
 
372
+ coordinates: ArrayDouble = field(init=False, kw_only=True)
373
+ """Market-share pairs as Cartesian coordinates of points on the diversion ratio boundary."""
374
+
319
375
  def __attrs_post_init__(self, /) -> None:
320
376
  _share_ratio = critical_share_ratio(
321
377
  self.diversion_ratio, r_bar=self.recapture_ratio
@@ -359,8 +415,28 @@ class DiversionRatioBoundary:
359
415
  _upp_agg_kwargs |= {"agg_method": _aggregator, "weighting": _wgt_type}
360
416
 
361
417
  _boundary = _upp_agg_fn(_share_ratio, self.recapture_ratio, **_upp_agg_kwargs)
362
- object.__setattr__(self, "coordinates", _boundary.coordinates)
363
418
  object.__setattr__(self, "area", _boundary.area)
419
+ object.__setattr__(self, "coordinates", _boundary.coordinates)
420
+
421
+ @classmethod
422
+ def to_yaml(
423
+ cls, _r: yaml.representer.SafeRepresenter, _d: DiversionRatioBoundary
424
+ ) -> yaml.MappingNode:
425
+ _ret: yaml.MappingNode = _r.represent_mapping(
426
+ f"!{cls.__name__}",
427
+ {
428
+ _a.name: getattr(_d, _a.name)
429
+ for _a in _d.__attrs_attrs__
430
+ if _a.name not in ("area", "coordinates")
431
+ },
432
+ )
433
+ return _ret
434
+
435
+ @classmethod
436
+ def from_yaml(
437
+ cls, _c: yaml.constructor.SafeConstructor, _n: yaml.MappingNode
438
+ ) -> DiversionRatioBoundary:
439
+ return cls(**_c.construct_mapping(_n))
364
440
 
365
441
 
366
442
  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, this_yaml # noqa: TID252
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
 
@@ -40,7 +40,7 @@ __version__ = VERSION
40
40
  DEFAULT_FCOUNT_WTS = np.asarray((_nr := np.arange(6, 0, -1)) / _nr.sum(), float)
41
41
 
42
42
 
43
- @dataclass
43
+ @dataclass(slots=True, frozen=True)
44
44
  class SeedSequenceData:
45
45
  share: SeedSequence
46
46
  pcm: SeedSequence
@@ -654,3 +654,20 @@ for _typ in (
654
654
  ),
655
655
  ),
656
656
  )
657
+
658
+ for _typ in (MarketSampleData, SeedSequenceData, UPPTestsCounts):
659
+ _, _ = (
660
+ this_yaml.representer.add_representer(
661
+ _typ,
662
+ lambda _r, _d: _r.rpresent_mapping(
663
+ f"!{_d.__class__.__name__}",
664
+ {_a: getattr(_d, _a) for _a in _d.__dataclass_fields__},
665
+ ),
666
+ ),
667
+ this_yaml.constructor.add_constructor(
668
+ _typ,
669
+ lambda _c, _n: globals().get(
670
+ _n.tag.lstrip("!")(**_c.construct_mapping(_n))
671
+ ),
672
+ ),
673
+ )
@@ -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 SaveData, compute_upp_test_counts
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 "recapture_form", "{self.share_spec.recapture_form}" '
108
- "requires Firm 2 margin must have property, "
109
- f'"{FM2Constraint.IID}" or "{FM2Constraint.SYM}".'
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.type not in (MarketSampleData, UPPTestsCounts)
481
+ if _a.name not in ("data", "enf_counts")
488
482
  },
489
483
  )
490
484
  return _ret
@@ -46,8 +46,8 @@ def gen_share_data(
46
46
  _sample_size: int,
47
47
  _share_spec: ShareSpec,
48
48
  _fcount_rng_seed_seq: SeedSequence | None,
49
- _mktshr_rng_seed_seq: SeedSequence | None = None,
50
- _nthreads: int = NTHREADS,
49
+ _mktshr_rng_seed_seq: SeedSequence,
50
+ _nthreads: int,
51
51
  /,
52
52
  ) -> ShareDataSample:
53
53
  """Helper function for generating share data.
@@ -69,9 +69,9 @@ def gen_share_data(
69
69
 
70
70
  """
71
71
 
72
- _recapture_form, _dist_type_mktshr, _dist_parms_mktshr, _firm_count_prob_wts = (
72
+ _dist_type_mktshr, _firm_count_prob_wts, _dist_parms_mktshr, _recapture_form = (
73
73
  getattr(_share_spec, _f)
74
- for _f in ("recapture_form", "dist_type", "dist_parms", "firm_counts_weights")
74
+ for _f in ("dist_type", "firm_counts_weights", "dist_parms", "recapture_form")
75
75
  )
76
76
 
77
77
  _ssz = _sample_size
@@ -126,8 +126,8 @@ def gen_share_data(
126
126
  def gen_market_shares_uniform(
127
127
  _s_size: int,
128
128
  _dist_parms_mktshr: ArrayDouble,
129
- _mktshr_rng_seed_seq: SeedSequence | None = None,
130
- _nthreads: int = NTHREADS,
129
+ _mktshr_rng_seed_seq: SeedSequence,
130
+ _nthreads: int,
131
131
  /,
132
132
  ) -> ShareDataSample:
133
133
  """Generate merging-firm shares from Uniform distribution on the 3-D simplex.
@@ -159,13 +159,12 @@ def gen_market_shares_uniform(
159
159
  nthreads=_nthreads,
160
160
  )
161
161
  _mrng.fill()
162
- # Convert draws on U[0, 1] to Uniformly-distributed draws on simplex, s_1 + s_2 <= 1
163
- _frmshr_array.sort(axis=1)
164
162
 
165
- _frmshr_array = np.array(
166
- (_frmshr_array[:, 0], _frmshr_array[:, 1] - _frmshr_array[:, 0]),
167
- _frmshr_array.dtype,
168
- ).T # faster than np.stack() and variants
163
+ # Convert draws on U[0, 1] to Uniformly-distributed draws on simplex, s_1 + s_2 <= 1
164
+ _frmshr_array = np.hstack((
165
+ _frmshr_array.min(axis=1, keepdims=True),
166
+ np.abs(np.diff(_frmshr_array, axis=1)),
167
+ ))
169
168
 
170
169
  # Keep only share combinations representing feasible mergers
171
170
  # This is a no-op for 64-bit floats, but is necessary for smaller floats
@@ -199,8 +198,8 @@ def _gen_market_shares_dirichlet_multimarket(
199
198
  _dist_type_dir: SHRDistribution,
200
199
  _dist_parms_dir: ArrayDouble,
201
200
  _firm_count_wts: ArrayDouble,
202
- _fcount_rng_seed_seq: SeedSequence | None = None,
203
- _mktshr_rng_seed_seq: SeedSequence | None = None,
201
+ _fcount_rng_seed_seq: SeedSequence | None,
202
+ _mktshr_rng_seed_seq: SeedSequence,
204
203
  _nthreads: int = NTHREADS,
205
204
  /,
206
205
  ) -> ShareDataSample:
@@ -341,8 +340,8 @@ def gen_market_shares_dirichlet(
341
340
  _dir_alphas: ArrayDouble,
342
341
  _s_size: int,
343
342
  _recapture_form: RECForm,
344
- _mktshr_rng_seed_seq: SeedSequence | None = None,
345
- _nthreads: int = NTHREADS,
343
+ _mktshr_rng_seed_seq: SeedSequence,
344
+ _nthreads: int,
346
345
  /,
347
346
  ) -> ShareDataSample:
348
347
  """Dirichlet-distributed shares with fixed firm-count.
@@ -497,7 +496,7 @@ def gen_margin_price_data(
497
496
  _hsr_filing_test_type: SSZConstant,
498
497
  _pcm_rng_seed_seq: SeedSequence,
499
498
  _pr_rng_seed_seq: SeedSequence | None,
500
- _nthreads: int = NTHREADS,
499
+ _nthreads: int,
501
500
  /,
502
501
  ) -> tuple[MarginDataSample, PriceDataSample]:
503
502
  """Generate margin and price data for mergers in the sample.
@@ -680,8 +679,8 @@ def _gen_margin_data(
680
679
  _price_array: ArrayDouble,
681
680
  _aggregate_purchase_prob: ArrayDouble,
682
681
  _pcm_spec: PCMSpec,
683
- _pcm_rng_seed_seq: SeedSequence | None,
684
- _nthreads: int = NTHREADS,
682
+ _pcm_rng_seed_seq: SeedSequence,
683
+ _nthreads: int,
685
684
  /,
686
685
  ) -> MarginDataSample:
687
686
  _dist_type_pcm, _dist_firm2_pcm, _dist_parms_pcm = (