tsbootstrap 0.7.0__tar.gz → 0.7.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.
Files changed (47) hide show
  1. {tsbootstrap-0.7.0/src/tsbootstrap.egg-info → tsbootstrap-0.7.2}/PKG-INFO +17 -6
  2. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/README.md +13 -1
  3. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/pyproject.toml +32 -11
  4. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/api.py +8 -1
  5. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/model/arima.py +78 -3
  6. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2/src/tsbootstrap.egg-info}/PKG-INFO +17 -6
  7. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap.egg-info/requires.txt +1 -3
  8. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/LICENSE +0 -0
  9. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/setup.cfg +0 -0
  10. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/__init__.py +0 -0
  11. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/adapters/__init__.py +0 -0
  12. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/adapters/estimators.py +0 -0
  13. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/block/__init__.py +0 -0
  14. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/block/_compiled.py +0 -0
  15. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/block/indices.py +0 -0
  16. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/block/pwsd.py +0 -0
  17. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/block/stationary.py +0 -0
  18. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/block/tapered.py +0 -0
  19. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/diagnostics.py +0 -0
  20. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/dispatch.py +0 -0
  21. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/engines/__init__.py +0 -0
  22. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/engines/arma_scipy.py +0 -0
  23. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/engines/var.py +0 -0
  24. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/errors.py +0 -0
  25. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/mcp.py +0 -0
  26. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/metadata.py +0 -0
  27. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/methods.py +0 -0
  28. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/model/__init__.py +0 -0
  29. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/model/fit.py +0 -0
  30. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/model/recursive.py +0 -0
  31. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/model/stability.py +0 -0
  32. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/prng_keys.py +0 -0
  33. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/py.typed +0 -0
  34. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/results.py +0 -0
  35. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/rng.py +0 -0
  36. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/uq/__init__.py +0 -0
  37. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/uq/adaptive.py +0 -0
  38. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/uq/calibration.py +0 -0
  39. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/uq/calibrators.py +0 -0
  40. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/uq/classical.py +0 -0
  41. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/uq/conformal.py +0 -0
  42. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/uq/forecast.py +0 -0
  43. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap/validation.py +0 -0
  44. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap.egg-info/SOURCES.txt +0 -0
  45. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap.egg-info/dependency_links.txt +0 -0
  46. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap.egg-info/entry_points.txt +0 -0
  47. {tsbootstrap-0.7.0 → tsbootstrap-0.7.2}/src/tsbootstrap.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tsbootstrap
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: A Python package to generate bootstrapped time series
5
5
  Author-email: Sankalp Gilda <sankalp.gilda@gmail.com>
6
6
  Maintainer-email: Sankalp Gilda <sankalp.gilda@gmail.com>, Franz Kiraly <franz.kiraly@sktime.net>, Benedikt Heidrich <benedikt.heidrich@sktime.net>
@@ -38,7 +38,8 @@ Classifier: Programming Language :: Python :: 3.10
38
38
  Classifier: Programming Language :: Python :: 3.11
39
39
  Classifier: Programming Language :: Python :: 3.12
40
40
  Classifier: Programming Language :: Python :: 3.13
41
- Requires-Python: <3.14,>=3.10
41
+ Classifier: Programming Language :: Python :: 3.14
42
+ Requires-Python: <3.15,>=3.10
42
43
  Description-Content-Type: text/markdown
43
44
  License-File: LICENSE
44
45
  Requires-Dist: numpy
@@ -51,7 +52,7 @@ Requires-Dist: statsmodels; extra == "models"
51
52
  Provides-Extra: uq
52
53
  Requires-Dist: scikit-learn; extra == "uq"
53
54
  Provides-Extra: mcp
54
- Requires-Dist: mcp<2,>=1.28; extra == "mcp"
55
+ Requires-Dist: mcp<2,>=1.28.1; extra == "mcp"
55
56
  Provides-Extra: accel
56
57
  Requires-Dist: numba; extra == "accel"
57
58
  Provides-Extra: examples
@@ -108,8 +109,6 @@ Requires-Dist: pyright; extra == "dev"
108
109
  Requires-Dist: ruff; extra == "dev"
109
110
  Requires-Dist: autoflake; extra == "dev"
110
111
  Requires-Dist: typos; extra == "dev"
111
- Requires-Dist: tox; extra == "dev"
112
- Requires-Dist: tox-gh-actions; extra == "dev"
113
112
  Requires-Dist: pycobertura; extra == "dev"
114
113
  Requires-Dist: tomlkit; extra == "dev"
115
114
  Requires-Dist: memory-profiler>=0.60.0; extra == "dev"
@@ -318,7 +317,12 @@ reduce holds about 20 MB at B=50000 where materializing every replicate takes
318
317
  about 1.94 GB (roughly 96x lighter), from
319
318
  [`benchmarks/results/membench_2026-07-04.json`](benchmarks/results/membench_2026-07-04.json).
320
319
  The multivariate and ragged-panel reduce
321
- paths have no equivalent in `arch`. Full methodology,
320
+ paths have no equivalent in `arch`. The panel reduce
321
+ (`bootstrap_reduce_panel`) returns the full per-series bootstrap distribution
322
+ of the statistic (`n_bootstraps x num_series`), so quantile and tail workflows
323
+ on an estimator are served directly with no replicate tensor. Use the
324
+ materializing path only when the workflow consumes the resampled paths
325
+ themselves. Full methodology,
322
326
  single-threaded numbers, and the reproduction script are in
323
327
  [benchmarks/README.md](benchmarks/README.md).
324
328
 
@@ -436,6 +440,13 @@ To run all tests, in your developer environment, run:
436
440
  uv run pytest tests/
437
441
  ```
438
442
 
443
+ That runs in a single process. Add the pytest-xdist flags CI uses to run the
444
+ suite in parallel, which is several times faster on a multi-core machine:
445
+
446
+ ```sh
447
+ uv run pytest tests/ -n auto --dist loadscope --max-worker-restart 3
448
+ ```
449
+
439
450
  The sktime adapter classes can be validated with sktime's estimator checks:
440
451
 
441
452
  ```python
@@ -201,7 +201,12 @@ reduce holds about 20 MB at B=50000 where materializing every replicate takes
201
201
  about 1.94 GB (roughly 96x lighter), from
202
202
  [`benchmarks/results/membench_2026-07-04.json`](benchmarks/results/membench_2026-07-04.json).
203
203
  The multivariate and ragged-panel reduce
204
- paths have no equivalent in `arch`. Full methodology,
204
+ paths have no equivalent in `arch`. The panel reduce
205
+ (`bootstrap_reduce_panel`) returns the full per-series bootstrap distribution
206
+ of the statistic (`n_bootstraps x num_series`), so quantile and tail workflows
207
+ on an estimator are served directly with no replicate tensor. Use the
208
+ materializing path only when the workflow consumes the resampled paths
209
+ themselves. Full methodology,
205
210
  single-threaded numbers, and the reproduction script are in
206
211
  [benchmarks/README.md](benchmarks/README.md).
207
212
 
@@ -319,6 +324,13 @@ To run all tests, in your developer environment, run:
319
324
  uv run pytest tests/
320
325
  ```
321
326
 
327
+ That runs in a single process. Add the pytest-xdist flags CI uses to run the
328
+ suite in parallel, which is several times faster on a multi-core machine:
329
+
330
+ ```sh
331
+ uv run pytest tests/ -n auto --dist loadscope --max-worker-restart 3
332
+ ```
333
+
322
334
  The sktime adapter classes can be validated with sktime's estimator checks:
323
335
 
324
336
  ```python
@@ -1,5 +1,11 @@
1
1
  [build-system]
2
- requires = ["setuptools>=61", "wheel"]
2
+ # Floor is 83, not 61: setuptools below 83.0.0 lets a MANIFEST.in exclusion be
3
+ # bypassed in an sdist through a Unicode NFC/NFD normalization collision on the
4
+ # case-folding macOS filesystems (CVE-2026-59890), so a file the manifest excludes
5
+ # can still be published in the source distribution. This is the bound that governs
6
+ # our own sdist build. 83.0.0 requires Python >= 3.10, which matches requires-python
7
+ # below, so the floor costs no supported interpreter.
8
+ requires = ["setuptools>=83", "wheel"]
3
9
  build-backend = "setuptools.build_meta"
4
10
 
5
11
  [tool.setuptools.packages.find]
@@ -7,7 +13,7 @@ where = ["src"]
7
13
 
8
14
  [project]
9
15
  name = "tsbootstrap"
10
- version = "0.7.0"
16
+ version = "0.7.2"
11
17
  description = "A Python package to generate bootstrapped time series"
12
18
  maintainers = [
13
19
  { name = "Sankalp Gilda", email = "sankalp.gilda@gmail.com" },
@@ -19,7 +25,7 @@ authors = [
19
25
  ]
20
26
  license = { file = "LICENSE" }
21
27
  readme = "README.md"
22
- requires-python = ">=3.10,<3.14"
28
+ requires-python = ">=3.10,<3.15"
23
29
  classifiers = [
24
30
  "Development Status :: 4 - Beta",
25
31
  "Intended Audience :: Science/Research",
@@ -33,6 +39,7 @@ classifiers = [
33
39
  "Programming Language :: Python :: 3.11",
34
40
  "Programming Language :: Python :: 3.12",
35
41
  "Programming Language :: Python :: 3.13",
42
+ "Programming Language :: Python :: 3.14",
36
43
  ]
37
44
 
38
45
  dependencies = [
@@ -60,7 +67,11 @@ uq = [
60
67
  # on top of CORE tsbootstrap only (it does NOT pull the models or uq extras): the two
61
68
  # tools are observation-resampling bootstraps, which are pure-numpy.
62
69
  mcp = [
63
- "mcp>=1.28,<2",
70
+ # Lower bound is 1.28.1, not 1.28: the WebSocket server transport in <= 1.28.0
71
+ # performs no Host/Origin validation (CVE-2026-59950), so a browser page can drive
72
+ # a locally bound server. tsbootstrap-mcp speaks stdio, but the bound keeps a
73
+ # consumer that imports the SDK for its own transport off the vulnerable release.
74
+ "mcp>=1.28.1,<2",
64
75
  ]
65
76
 
66
77
  # Compiled acceleration: a numba kernel for the VAR recurrence (replicate-parallel).
@@ -133,8 +144,6 @@ dev = [
133
144
  "ruff",
134
145
  "autoflake",
135
146
  "typos",
136
- "tox",
137
- "tox-gh-actions",
138
147
  "pycobertura",
139
148
  "tomlkit",
140
149
  "memory-profiler>=0.60.0", # For performance testing
@@ -161,7 +170,15 @@ required-version = "==0.11.28"
161
170
  [tool.pytest.ini_options]
162
171
  minversion = "6.0"
163
172
  pythonpath = ["."] # repo root on sys.path so tests can import the shared tests._helpers package
164
- addopts = "-ra -q -n auto --dist loadscope --max-worker-restart 3 --durations=20"
173
+ # Reporting only. Parallelism is deliberately NOT here: addopts applies to every pytest
174
+ # invocation in this repository, so putting "-n auto" in it made xdist the default for
175
+ # callers that must not have it, and each of those then had to remember to undo it. The
176
+ # notebook job forgot, started one Jupyter kernel per worker, and the kernels raced to
177
+ # bind their ZMQ ports. The obvious escape hatch does not work either: "-p no:xdist"
178
+ # unregisters the -n / --dist / --max-worker-restart options that addopts still passes,
179
+ # so pytest exits 4 on unrecognized arguments. Callers that want parallelism now ask for
180
+ # it: see the Run tests steps in .github/workflows/CI.yml and DEVELOPER_NOTES.md.
181
+ addopts = "-ra -q --durations=20"
165
182
  testpaths = [
166
183
  "tests",
167
184
  ]
@@ -482,8 +499,12 @@ do_not_mutate_patterns = [
482
499
  ]
483
500
 
484
501
  pytest_add_cli_args_test_selection = ["-m", "not slow", "tests/"]
485
- # -o addopts= drops the project's default addopts (coverage, xdist, durations). The per-test
486
- # timeout is mutmut's hang guard: a mutant that sends an iterative solver or a recurrence into a
487
- # non-terminating loop is killed at 60s (thread method, so it interrupts even C-extension calls)
488
- # instead of stalling the whole run.
502
+ # -o addopts= drops the project's default addopts, which is now reporting only: -ra, -q and
503
+ # --durations=20. mutmut runs pytest once per mutant, so a per-run durations table and a summary
504
+ # of every non-passing outcome are pure noise across thousands of runs. It has nothing to do
505
+ # with xdist any more:
506
+ # parallelism has left addopts and lives on the callers that want it.
507
+ # The per-test timeout is mutmut's hang guard: a mutant that sends an iterative solver or a
508
+ # recurrence into a non-terminating loop is killed at 60s (thread method, so it interrupts even
509
+ # C-extension calls) instead of stalling the whole run.
489
510
  pytest_add_cli_args = ["-o", "addopts=", "--timeout=60", "--timeout-method=thread"]
@@ -694,7 +694,9 @@ def bootstrap_reduce_panel(
694
694
  representation is a list of per-series arrays (or a flat array plus a CSR ``indptr``),
695
695
  not the rectangular ``(n, d)`` that :func:`bootstrap_reduce` assumes. The output gains
696
696
  a series axis, and ``.values()`` is mathematically incoherent across unequal lengths,
697
- so the reduce IS the panel API.
697
+ so the reduce IS the panel API. The compiled kernels consume the
698
+ flat-values-plus-offsets layout directly, so access is contiguous within each series
699
+ rather than per-element pointer chasing.
698
700
 
699
701
  Parameters
700
702
  ----------
@@ -737,6 +739,11 @@ def bootstrap_reduce_panel(
737
739
  ``.statistics`` of shape ``(n_bootstraps, num_series, |theta|)``, collapsed to
738
740
  ``(n_bootstraps, num_series)`` when the series are univariate and the statistic is
739
741
  scalar (mirroring the ``(B,)`` collapse of the rectangular reduce).
742
+
743
+ The reduce returns the full per-series bootstrap distribution of the statistic
744
+ (``n_bootstraps x num_series``), so quantile and tail workflows on an estimator
745
+ are served directly with no replicate tensor. Use the materializing path only
746
+ when the workflow consumes the resampled paths themselves.
740
747
  """
741
748
  if backend not in ("numpy", "compiled"):
742
749
  raise MethodConfigError(
@@ -8,14 +8,20 @@ back using the original initial levels. statsmodels is imported lazily.
8
8
  from __future__ import annotations
9
9
 
10
10
  from dataclasses import dataclass
11
+ from typing import Any
11
12
 
12
13
  import numpy as np
14
+ from numpy.linalg import LinAlgError
13
15
  from numpy.typing import NDArray
14
16
  from scipy.signal import lfilter, lfiltic
15
17
 
16
- from tsbootstrap.errors import Codes, MethodConfigError
18
+ from tsbootstrap.errors import Codes, MethodConfigError, ModelStabilityError
17
19
  from tsbootstrap.model.fit import _require_statsmodels
18
20
 
21
+ # Floor for the innovation variance in the fallback starting values: a constant (or
22
+ # near-constant) series has zero sample variance, which is not a usable sigma2 start.
23
+ _MIN_START_SIGMA2 = 1e-10
24
+
19
25
 
20
26
  @dataclass(frozen=True, slots=True)
21
27
  class ARMAFit:
@@ -66,10 +72,79 @@ def integrate_batched(w: NDArray[np.float64], levels: list[float]) -> NDArray[np
66
72
  return cur
67
73
 
68
74
 
75
+ def _interior_start_params(
76
+ model: Any, demeaned: NDArray[np.float64], p: int, q: int
77
+ ) -> NDArray[np.float64] | None:
78
+ """Return statsmodels' starting values, or a white-noise start when they are unusable.
79
+
80
+ Returns ``None`` when the model's Hannan-Rissanen starting values survive the
81
+ stationarity transform, so the refit keeps statsmodels' default start. Returns an
82
+ explicit interior start (zero AR/MA, sigma2 at the sample variance) otherwise.
83
+
84
+ statsmodels already replaces starting AR parameters it judges non-stationary with
85
+ zeros, but that check accepts values sitting exactly ON the unit circle. Their
86
+ inverse stationarity transform divides by ``sqrt(1 - r**2) == 0`` and yields
87
+ ``+/-inf``, whose forward transform is NaN, so an optimization started there returns
88
+ NaN parameters rather than raising.
89
+ """
90
+ with np.errstate(divide="ignore", invalid="ignore"):
91
+ unconstrained = np.asarray(model.untransform_params(model.start_params), dtype=np.float64)
92
+ if np.isfinite(unconstrained).all():
93
+ return None
94
+ sigma2 = max(float(np.var(demeaned)), _MIN_START_SIGMA2)
95
+ return np.concatenate([np.zeros(p + q, dtype=np.float64), [sigma2]])
96
+
97
+
98
+ def _fit_arma_mle(demeaned: NDArray[np.float64], p: int, q: int) -> Any:
99
+ """Maximum-likelihood ARMA(p, q) fit of ``demeaned``, robust at the unit circle.
100
+
101
+ statsmodels enforces stationarity with ``r = u / sqrt(1 + u**2)``. Once ``|u|``
102
+ passes roughly 1e8 that expression rounds to exactly ``+/-1.0`` in float64, so the
103
+ AR polynomial acquires a root exactly ON the unit circle. The stationary state-space
104
+ initialization must then solve a discrete Lyapunov equation whose transition matrix
105
+ is singular, and LAPACK fails inside the Kalman machinery -- reaching the caller as a
106
+ raw ``numpy.linalg.LinAlgError`` ("LU decomposition error", or "Schur decomposition
107
+ solver error" depending on which factorization is reached first). This happens either
108
+ at the Hannan-Rissanen starting values or at an intermediate optimizer step, so
109
+ conditioning the starting values alone does not close it.
110
+
111
+ The recovery refits the identical model under an approximate-diffuse initialization,
112
+ which solves no Lyapunov equation and so stays well defined for a transition matrix
113
+ with unit-modulus eigenvalues, starting from the interior when the default starting
114
+ values are themselves unusable. The recovered fit is returned as-is: it may well be
115
+ non-stationary, and rejecting it is the stability layer's job, not this one's. If the
116
+ recovery cannot produce finite parameters either, the failure is reported as a typed
117
+ :class:`~tsbootstrap.errors.ModelStabilityError`.
118
+ """
119
+ from statsmodels.tsa.arima.model import ARIMA as _SMARIMA
120
+
121
+ try:
122
+ return _SMARIMA(demeaned, order=(p, 0, q), trend="n").fit()
123
+ except LinAlgError as exc:
124
+ recovery = _SMARIMA(demeaned, order=(p, 0, q), trend="n")
125
+ recovery.ssm.initialize_approximate_diffuse()
126
+ start_params = _interior_start_params(recovery, demeaned, p, q)
127
+ try:
128
+ res = recovery.fit(start_params=start_params)
129
+ if np.isfinite(res.arparams).all() and np.isfinite(res.maparams).all():
130
+ return res
131
+ except LinAlgError:
132
+ # The diffuse re-fit reached the same singularity. Fall through to the typed
133
+ # error rather than let a linear-algebra internal reach the caller.
134
+ pass
135
+ raise ModelStabilityError(
136
+ f"ARMA(p={p}, q={q}) maximum likelihood reached an autoregressive root on the "
137
+ f"unit circle and could not be re-fit under a diffuse initialization; the series "
138
+ f"is probably under-differenced",
139
+ code=Codes.NEAR_UNIT_ROOT,
140
+ context={"p": p, "q": q, "n": int(demeaned.shape[0])},
141
+ hint="Increase the differencing order d, or reduce the ARMA order.",
142
+ ) from exc
143
+
144
+
69
145
  def fit_arma(w: NDArray[np.float64], p: int, q: int) -> ARMAFit:
70
146
  """Fit a demeaned ARMA(p, q) to the (already differenced) series ``w``."""
71
147
  _require_statsmodels()
72
- from statsmodels.tsa.arima.model import ARIMA as _SMARIMA
73
148
 
74
149
  series = np.ascontiguousarray(np.asarray(w, dtype=np.float64).ravel())
75
150
  n = series.shape[0]
@@ -80,7 +155,7 @@ def fit_arma(w: NDArray[np.float64], p: int, q: int) -> ARMAFit:
80
155
  context={"p": p, "q": q, "n": n},
81
156
  )
82
157
  mean = float(series.mean())
83
- res = _SMARIMA(series - mean, order=(p, 0, q), trend="n").fit()
158
+ res = _fit_arma_mle(series - mean, p, q)
84
159
  ar_coefs = np.ascontiguousarray(np.asarray(res.arparams, dtype=np.float64))
85
160
  ma_coefs = np.ascontiguousarray(np.asarray(res.maparams, dtype=np.float64))
86
161
  # Derive the innovations in OUR engine's convention (scipy lfilter), not statsmodels'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tsbootstrap
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: A Python package to generate bootstrapped time series
5
5
  Author-email: Sankalp Gilda <sankalp.gilda@gmail.com>
6
6
  Maintainer-email: Sankalp Gilda <sankalp.gilda@gmail.com>, Franz Kiraly <franz.kiraly@sktime.net>, Benedikt Heidrich <benedikt.heidrich@sktime.net>
@@ -38,7 +38,8 @@ Classifier: Programming Language :: Python :: 3.10
38
38
  Classifier: Programming Language :: Python :: 3.11
39
39
  Classifier: Programming Language :: Python :: 3.12
40
40
  Classifier: Programming Language :: Python :: 3.13
41
- Requires-Python: <3.14,>=3.10
41
+ Classifier: Programming Language :: Python :: 3.14
42
+ Requires-Python: <3.15,>=3.10
42
43
  Description-Content-Type: text/markdown
43
44
  License-File: LICENSE
44
45
  Requires-Dist: numpy
@@ -51,7 +52,7 @@ Requires-Dist: statsmodels; extra == "models"
51
52
  Provides-Extra: uq
52
53
  Requires-Dist: scikit-learn; extra == "uq"
53
54
  Provides-Extra: mcp
54
- Requires-Dist: mcp<2,>=1.28; extra == "mcp"
55
+ Requires-Dist: mcp<2,>=1.28.1; extra == "mcp"
55
56
  Provides-Extra: accel
56
57
  Requires-Dist: numba; extra == "accel"
57
58
  Provides-Extra: examples
@@ -108,8 +109,6 @@ Requires-Dist: pyright; extra == "dev"
108
109
  Requires-Dist: ruff; extra == "dev"
109
110
  Requires-Dist: autoflake; extra == "dev"
110
111
  Requires-Dist: typos; extra == "dev"
111
- Requires-Dist: tox; extra == "dev"
112
- Requires-Dist: tox-gh-actions; extra == "dev"
113
112
  Requires-Dist: pycobertura; extra == "dev"
114
113
  Requires-Dist: tomlkit; extra == "dev"
115
114
  Requires-Dist: memory-profiler>=0.60.0; extra == "dev"
@@ -318,7 +317,12 @@ reduce holds about 20 MB at B=50000 where materializing every replicate takes
318
317
  about 1.94 GB (roughly 96x lighter), from
319
318
  [`benchmarks/results/membench_2026-07-04.json`](benchmarks/results/membench_2026-07-04.json).
320
319
  The multivariate and ragged-panel reduce
321
- paths have no equivalent in `arch`. Full methodology,
320
+ paths have no equivalent in `arch`. The panel reduce
321
+ (`bootstrap_reduce_panel`) returns the full per-series bootstrap distribution
322
+ of the statistic (`n_bootstraps x num_series`), so quantile and tail workflows
323
+ on an estimator are served directly with no replicate tensor. Use the
324
+ materializing path only when the workflow consumes the resampled paths
325
+ themselves. Full methodology,
322
326
  single-threaded numbers, and the reproduction script are in
323
327
  [benchmarks/README.md](benchmarks/README.md).
324
328
 
@@ -436,6 +440,13 @@ To run all tests, in your developer environment, run:
436
440
  uv run pytest tests/
437
441
  ```
438
442
 
443
+ That runs in a single process. Add the pytest-xdist flags CI uses to run the
444
+ suite in parallel, which is several times faster on a multi-core machine:
445
+
446
+ ```sh
447
+ uv run pytest tests/ -n auto --dist loadscope --max-worker-restart 3
448
+ ```
449
+
439
450
  The sktime adapter classes can be validated with sktime's estimator checks:
440
451
 
441
452
  ```python
@@ -34,8 +34,6 @@ pyright
34
34
  ruff
35
35
  autoflake
36
36
  typos
37
- tox
38
- tox-gh-actions
39
37
  pycobertura
40
38
  tomlkit
41
39
  memory-profiler>=0.60.0
@@ -64,7 +62,7 @@ sktime
64
62
  jupyter
65
63
 
66
64
  [mcp]
67
- mcp<2,>=1.28
65
+ mcp<2,>=1.28.1
68
66
 
69
67
  [models]
70
68
  statsmodels
File without changes
File without changes