tsbootstrap 0.3.0__tar.gz → 0.4.0__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.
- {tsbootstrap-0.3.0/src/tsbootstrap.egg-info → tsbootstrap-0.4.0}/PKG-INFO +32 -7
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/README.md +30 -6
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/pyproject.toml +72 -6
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/__init__.py +26 -1
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/adapters/estimators.py +43 -7
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/block/_compiled.py +24 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/mcp.py +4 -5
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/metadata.py +8 -1
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/methods.py +56 -1
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/model/recursive.py +173 -16
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/uq/__init__.py +20 -0
- tsbootstrap-0.4.0/src/tsbootstrap/uq/classical.py +821 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0/src/tsbootstrap.egg-info}/PKG-INFO +32 -7
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap.egg-info/SOURCES.txt +1 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap.egg-info/requires.txt +1 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/LICENSE +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/setup.cfg +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/adapters/__init__.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/api.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/block/__init__.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/block/indices.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/block/pwsd.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/block/stationary.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/block/tapered.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/diagnostics.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/dispatch.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/engines/__init__.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/engines/arma_scipy.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/engines/var.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/errors.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/model/__init__.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/model/arima.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/model/fit.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/model/stability.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/py.typed +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/results.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/rng.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/uq/adaptive.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/uq/calibration.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/uq/conformal.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/uq/forecast.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap/validation.py +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap.egg-info/dependency_links.txt +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/src/tsbootstrap.egg-info/entry_points.txt +0 -0
- {tsbootstrap-0.3.0 → tsbootstrap-0.4.0}/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.
|
|
3
|
+
Version: 0.4.0
|
|
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>
|
|
@@ -89,6 +89,7 @@ Requires-Dist: pytest; extra == "dev"
|
|
|
89
89
|
Requires-Dist: pytest-xdist[psutil]; extra == "dev"
|
|
90
90
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
91
91
|
Requires-Dist: pytest-mock; extra == "dev"
|
|
92
|
+
Requires-Dist: pytest-timeout; extra == "dev"
|
|
92
93
|
Requires-Dist: nbmake; extra == "dev"
|
|
93
94
|
Requires-Dist: sktime; extra == "dev"
|
|
94
95
|
Requires-Dist: polars; extra == "dev"
|
|
@@ -232,6 +233,15 @@ from tsbootstrap import AR, forecast_intervals
|
|
|
232
233
|
lower, upper, median = forecast_intervals(x, model=AR(order=2), horizon=12, alpha=0.1)
|
|
233
234
|
```
|
|
234
235
|
|
|
236
|
+
For a confidence interval on a statistic of one series, `conf_int` runs the bootstrap
|
|
237
|
+
and reads the interval in one call:
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
from tsbootstrap import IID, conf_int
|
|
241
|
+
|
|
242
|
+
lower, upper, point = conf_int(x, "mean", method=IID(), kind="bca", alpha=0.1)
|
|
243
|
+
```
|
|
244
|
+
|
|
235
245
|
The conformal pieces (`EnbPIEnsemble` and the calibrators) need the `uq` extra
|
|
236
246
|
(scikit-learn). The interactive
|
|
237
247
|
[tutorial gallery](https://tsbootstrap.readthedocs.io/en/latest/tutorials/index.html)
|
|
@@ -278,7 +288,7 @@ the `models` extra is missing.
|
|
|
278
288
|
|
|
279
289
|
## ⚡ Performance
|
|
280
290
|
|
|
281
|
-

|
|
282
292
|
|
|
283
293
|
*Left: speedup of the compiled reduce path over the arch library on the four overlapping methods. Right: peak memory before and after on the two headline reduce workloads (baseline = materialize every path, then reduce). Regenerate with `python benchmarks/plot_launch.py`.*
|
|
284
294
|
|
|
@@ -319,7 +329,7 @@ Package layout:
|
|
|
319
329
|
| Infrastructure | `rng.py`, `validation.py`, `dispatch.py`, `metadata.py` | deterministic RNG contract, input coercion (incl. the narwhals DataFrame boundary), spec to executor dispatch, method metadata |
|
|
320
330
|
| Block methods | `block/` | vectorized index kernels, true Politis-Romano stationary, energy-normalized tapering, PWSD block length, OOB primitives |
|
|
321
331
|
| Model methods | `model/`, `engines/` | model fitting, stability guards, and recursive AR/ARMA/VAR simulation |
|
|
322
|
-
| Uncertainty quantification | `uq/` | EnbPI prediction intervals, the static / sliding-window / ACI / NexCP calibrators, and AR forecast intervals |
|
|
332
|
+
| Uncertainty quantification | `uq/` | classical confidence intervals (percentile, basic, studentized, BCa) via `conf_int`, EnbPI prediction intervals, the static / sliding-window / ACI / NexCP calibrators, and AR forecast intervals |
|
|
323
333
|
| Ecosystem | `adapters/` | skbase / sktime estimator classes over the functional core |
|
|
324
334
|
|
|
325
335
|
|
|
@@ -327,14 +337,13 @@ Package layout:
|
|
|
327
337
|
|
|
328
338
|
The full, living roadmap is [issue #181](https://github.com/astrogilda/tsbootstrap/issues/181). Highlights:
|
|
329
339
|
|
|
330
|
-
Near term
|
|
331
|
-
- Out-of-sample forecast intervals for ARIMA and VAR (
|
|
332
|
-
- The tutorial gallery and getting-started notebook ([#46](https://github.com/astrogilda/tsbootstrap/issues/46)).
|
|
340
|
+
Near term:
|
|
341
|
+
- Out-of-sample forecast intervals for ARIMA and VAR (currently AR-only).
|
|
333
342
|
- Python 3.14, once statsmodels publishes a 3.14 wheel ([#202](https://github.com/astrogilda/tsbootstrap/issues/202)).
|
|
334
343
|
|
|
335
344
|
Candidate methods (good first issues):
|
|
336
345
|
- Generalized block ([#104](https://github.com/astrogilda/tsbootstrap/issues/104)), local block ([#105](https://github.com/astrogilda/tsbootstrap/issues/105)), and frequency-domain ([#107](https://github.com/astrogilda/tsbootstrap/issues/107)) bootstraps.
|
|
337
|
-
-
|
|
346
|
+
- A GARCH / volatility residual bootstrap, and the smooth-kernel dependent-wild bootstrap.
|
|
338
347
|
|
|
339
348
|
Distributed execution (`Dask` / `Spark` / `Ray`), an async layer, and a string-keyed
|
|
340
349
|
factory were considered and deliberately left out. The library is a CPU-bound,
|
|
@@ -476,6 +485,22 @@ explosive paths.
|
|
|
476
485
|
`SieveAR` selects an autoregressive order on the original series, then runs the AR recursion;
|
|
477
486
|
suited to data with autoregressive structure.
|
|
478
487
|
|
|
488
|
+
### Innovation resamplers
|
|
489
|
+
The `innovation` argument on `ResidualBootstrap` and `SieveAR` controls how the centered
|
|
490
|
+
residuals are resampled. It defaults to `IID` (uniform resampling); two wild resamplers relax
|
|
491
|
+
the exchangeability that assumes.
|
|
492
|
+
|
|
493
|
+
- **Wild** (`Wild(distribution=...)`): multiplies each residual in place by a mean-zero,
|
|
494
|
+
unit-variance draw (`e*_t = v_t * e_hat_t`), keeping its time position and magnitude, so it
|
|
495
|
+
stays valid under conditional heteroskedasticity (Wu 1986; Liu 1988; Rademacher default per
|
|
496
|
+
Davidson-Flachaire 2008).
|
|
497
|
+
- **Block-wild** (`BlockWild(block_length=...)`): holds one multiplier constant across each
|
|
498
|
+
block of residuals, so serial dependence left by a misspecified mean survives the resampling
|
|
499
|
+
(piecewise-constant dependent wild bootstrap, Shao 2010).
|
|
500
|
+
|
|
501
|
+
Both require the host model's `burn_in=0` and `initial="fixed"` defaults so the multipliers
|
|
502
|
+
align one-to-one with the residuals.
|
|
503
|
+
|
|
479
504
|
### Deferred to a later release
|
|
480
505
|
Markov resampling, the distribution bootstrap, GARCH/volatility models, and
|
|
481
506
|
frequency-domain / seasonal block methods are planned for a future version. The
|
|
@@ -116,6 +116,15 @@ from tsbootstrap import AR, forecast_intervals
|
|
|
116
116
|
lower, upper, median = forecast_intervals(x, model=AR(order=2), horizon=12, alpha=0.1)
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
+
For a confidence interval on a statistic of one series, `conf_int` runs the bootstrap
|
|
120
|
+
and reads the interval in one call:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from tsbootstrap import IID, conf_int
|
|
124
|
+
|
|
125
|
+
lower, upper, point = conf_int(x, "mean", method=IID(), kind="bca", alpha=0.1)
|
|
126
|
+
```
|
|
127
|
+
|
|
119
128
|
The conformal pieces (`EnbPIEnsemble` and the calibrators) need the `uq` extra
|
|
120
129
|
(scikit-learn). The interactive
|
|
121
130
|
[tutorial gallery](https://tsbootstrap.readthedocs.io/en/latest/tutorials/index.html)
|
|
@@ -162,7 +171,7 @@ the `models` extra is missing.
|
|
|
162
171
|
|
|
163
172
|
## ⚡ Performance
|
|
164
173
|
|
|
165
|
-

|
|
166
175
|
|
|
167
176
|
*Left: speedup of the compiled reduce path over the arch library on the four overlapping methods. Right: peak memory before and after on the two headline reduce workloads (baseline = materialize every path, then reduce). Regenerate with `python benchmarks/plot_launch.py`.*
|
|
168
177
|
|
|
@@ -203,7 +212,7 @@ Package layout:
|
|
|
203
212
|
| Infrastructure | `rng.py`, `validation.py`, `dispatch.py`, `metadata.py` | deterministic RNG contract, input coercion (incl. the narwhals DataFrame boundary), spec to executor dispatch, method metadata |
|
|
204
213
|
| Block methods | `block/` | vectorized index kernels, true Politis-Romano stationary, energy-normalized tapering, PWSD block length, OOB primitives |
|
|
205
214
|
| Model methods | `model/`, `engines/` | model fitting, stability guards, and recursive AR/ARMA/VAR simulation |
|
|
206
|
-
| Uncertainty quantification | `uq/` | EnbPI prediction intervals, the static / sliding-window / ACI / NexCP calibrators, and AR forecast intervals |
|
|
215
|
+
| Uncertainty quantification | `uq/` | classical confidence intervals (percentile, basic, studentized, BCa) via `conf_int`, EnbPI prediction intervals, the static / sliding-window / ACI / NexCP calibrators, and AR forecast intervals |
|
|
207
216
|
| Ecosystem | `adapters/` | skbase / sktime estimator classes over the functional core |
|
|
208
217
|
|
|
209
218
|
|
|
@@ -211,14 +220,13 @@ Package layout:
|
|
|
211
220
|
|
|
212
221
|
The full, living roadmap is [issue #181](https://github.com/astrogilda/tsbootstrap/issues/181). Highlights:
|
|
213
222
|
|
|
214
|
-
Near term
|
|
215
|
-
- Out-of-sample forecast intervals for ARIMA and VAR (
|
|
216
|
-
- The tutorial gallery and getting-started notebook ([#46](https://github.com/astrogilda/tsbootstrap/issues/46)).
|
|
223
|
+
Near term:
|
|
224
|
+
- Out-of-sample forecast intervals for ARIMA and VAR (currently AR-only).
|
|
217
225
|
- Python 3.14, once statsmodels publishes a 3.14 wheel ([#202](https://github.com/astrogilda/tsbootstrap/issues/202)).
|
|
218
226
|
|
|
219
227
|
Candidate methods (good first issues):
|
|
220
228
|
- Generalized block ([#104](https://github.com/astrogilda/tsbootstrap/issues/104)), local block ([#105](https://github.com/astrogilda/tsbootstrap/issues/105)), and frequency-domain ([#107](https://github.com/astrogilda/tsbootstrap/issues/107)) bootstraps.
|
|
221
|
-
-
|
|
229
|
+
- A GARCH / volatility residual bootstrap, and the smooth-kernel dependent-wild bootstrap.
|
|
222
230
|
|
|
223
231
|
Distributed execution (`Dask` / `Spark` / `Ray`), an async layer, and a string-keyed
|
|
224
232
|
factory were considered and deliberately left out. The library is a CPU-bound,
|
|
@@ -360,6 +368,22 @@ explosive paths.
|
|
|
360
368
|
`SieveAR` selects an autoregressive order on the original series, then runs the AR recursion;
|
|
361
369
|
suited to data with autoregressive structure.
|
|
362
370
|
|
|
371
|
+
### Innovation resamplers
|
|
372
|
+
The `innovation` argument on `ResidualBootstrap` and `SieveAR` controls how the centered
|
|
373
|
+
residuals are resampled. It defaults to `IID` (uniform resampling); two wild resamplers relax
|
|
374
|
+
the exchangeability that assumes.
|
|
375
|
+
|
|
376
|
+
- **Wild** (`Wild(distribution=...)`): multiplies each residual in place by a mean-zero,
|
|
377
|
+
unit-variance draw (`e*_t = v_t * e_hat_t`), keeping its time position and magnitude, so it
|
|
378
|
+
stays valid under conditional heteroskedasticity (Wu 1986; Liu 1988; Rademacher default per
|
|
379
|
+
Davidson-Flachaire 2008).
|
|
380
|
+
- **Block-wild** (`BlockWild(block_length=...)`): holds one multiplier constant across each
|
|
381
|
+
block of residuals, so serial dependence left by a misspecified mean survives the resampling
|
|
382
|
+
(piecewise-constant dependent wild bootstrap, Shao 2010).
|
|
383
|
+
|
|
384
|
+
Both require the host model's `burn_in=0` and `initial="fixed"` defaults so the multipliers
|
|
385
|
+
align one-to-one with the residuals.
|
|
386
|
+
|
|
363
387
|
### Deferred to a later release
|
|
364
388
|
Markov resampling, the distribution bootstrap, GARCH/volatility models, and
|
|
365
389
|
frequency-domain / seasonal block methods are planned for a future version. The
|
|
@@ -7,7 +7,7 @@ where = ["src"]
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "tsbootstrap"
|
|
10
|
-
version = "0.
|
|
10
|
+
version = "0.4.0"
|
|
11
11
|
description = "A Python package to generate bootstrapped time series"
|
|
12
12
|
maintainers = [
|
|
13
13
|
{ name = "Sankalp Gilda", email = "sankalp.gilda@gmail.com" },
|
|
@@ -114,6 +114,7 @@ dev = [
|
|
|
114
114
|
"pytest-xdist[psutil]",
|
|
115
115
|
"pytest-cov",
|
|
116
116
|
"pytest-mock",
|
|
117
|
+
"pytest-timeout", # hang guard for the mutation ratchet (kills a non-terminating mutant)
|
|
117
118
|
"nbmake", # execute the tutorial notebooks as a CI test gate (issue #46)
|
|
118
119
|
"sktime", # validates the skbase/sktime adapter discovery + check_estimator
|
|
119
120
|
"polars", # exercises the narwhals DataFrame boundary with a second backend
|
|
@@ -382,15 +383,80 @@ reportUnnecessaryIsInstance = false
|
|
|
382
383
|
reportConstantRedefinition = false
|
|
383
384
|
|
|
384
385
|
[tool.mutmut]
|
|
386
|
+
# STATUS (2026-06-24): in-process mutmut is NOT a blocking CI gate. Root cause, proven this session
|
|
387
|
+
# and reproduced on a clean 16-core box (not CPU contention): mutmut 3.x runs pytest IN-PROCESS via
|
|
388
|
+
# repeated pytest.main(), and numba's @njit(parallel=True) kernels (engines/var.py + block/_compiled.py)
|
|
389
|
+
# DEADLOCK in LLVM finalize_object/parse_assembly when that compile recurs inside one interpreter, so
|
|
390
|
+
# the stats pass times out and the run aborts before any mutant is tested. NUMBA_DISABLE_JIT=1 avoids
|
|
391
|
+
# the deadlock but runs the kernels interpreted, which then blows the per-test timeout. The locked path
|
|
392
|
+
# (cross-family debate 2026-06-24) is a Layer-2 subprocess-per-mutant runner: keep mutmut ONLY for AST
|
|
393
|
+
# mutant generation, execute each mutant in an isolated subprocess so LLVM never churns in one process,
|
|
394
|
+
# run nightly/non-blocking, gate on the new-survivor diff vs tests/mutation_equivalents.md. The config
|
|
395
|
+
# below + tools/mutmut_sitecustomize remain usable for a one-off LOCAL inspection on an idle box, but
|
|
396
|
+
# the durable value already landed is the killing tests + the equivalents registry, not this in-process
|
|
397
|
+
# runner. See ~/.claude/skills/mutation-ratchet and the debate transcript for the subprocess design.
|
|
398
|
+
#
|
|
385
399
|
# Mutation-score ratchet over the engine + model core (the established baseline scope).
|
|
386
|
-
# Run with:
|
|
387
|
-
# -
|
|
388
|
-
#
|
|
389
|
-
#
|
|
400
|
+
# Run with: PYTHONPATH=tools/mutmut_sitecustomize HYPOTHESIS_PROFILE=mutmut uv run mutmut run
|
|
401
|
+
# - PYTHONPATH=tools/mutmut_sitecustomize (REQUIRED): mutate_only_covered_lines below makes mutmut
|
|
402
|
+
# run an in-process coverage pass and then UNLOAD every module imported during it
|
|
403
|
+
# (mutmut.code_coverage._unload_modules_not_in) so the source reloads fresh per mutant. That
|
|
404
|
+
# unload is fatal to C-extension libraries that cannot re-import in the same process: numpy
|
|
405
|
+
# ("cannot load module more than once per process" from _multiarray_umath) and numba
|
|
406
|
+
# ("duplicate registration for PolynomialType"). The sitecustomize on this path patches the
|
|
407
|
+
# unload to keep numpy/numba/scipy/statsmodels/... resident while still reloading tsbootstrap.
|
|
408
|
+
# It is gated on HYPOTHESIS_PROFILE=mutmut, so it is inert outside the ratchet. This is an
|
|
409
|
+
# upstream mutmut-3.x interaction (2.x did not copy + reload this way), not specific to this repo.
|
|
390
410
|
# - HYPOTHESIS_PROFILE=mutmut: derandomized profile so the property baseline is reproducible.
|
|
411
|
+
# It also activates the mutmut-only test fixture in tests/conftest.py:
|
|
412
|
+
# * an ephemeral per-session NUMBA_CACHE_DIR so the @njit VAR kernel recompiles its mutated
|
|
413
|
+
# source fresh on every mutant (JIT stays ON, at native speed). This replaces the old
|
|
414
|
+
# NUMBA_DISABLE_JIT=1 workaround, whose interpreted execution cost ~28 minutes per run;
|
|
415
|
+
# the cache, not the JIT, was what masked source mutations to the compiled kernel.
|
|
416
|
+
# There is deliberately NO solver-maxiter clamp (see the long note in tests/conftest.py): it
|
|
417
|
+
# changed the numerics on the unmutated code and broke the clean-baseline ARIMA golden, which
|
|
418
|
+
# mutmut requires to pass. Spinning mutants are bounded by --timeout below instead.
|
|
419
|
+
# RUN ON AN IDLE / DEDICATED MACHINE. mutmut 3.x runs its stats and per-mutant suites in-process
|
|
420
|
+
# (pytest.main) with --timeout below; under heavy CPU contention (e.g. other multi-hour jobs) the
|
|
421
|
+
# in-process stats pass can exceed the per-test timeout and abort the whole run before any mutant is
|
|
422
|
+
# tested. The full run is reliable on an idle box or a dedicated remote runner. Accepted equivalent
|
|
423
|
+
# survivors are catalogued in tests/mutation_equivalents.md (the ratchet baseline).
|
|
391
424
|
# source_paths is the whole importable tree (subdirs alone yield an incomplete copied package);
|
|
392
425
|
# only_mutate then restricts mutation to the engines+model scope.
|
|
393
426
|
source_paths = ["src/"]
|
|
394
427
|
only_mutate = ["src/tsbootstrap/engines/*", "src/tsbootstrap/model/*"]
|
|
428
|
+
|
|
429
|
+
# MUST stay false for the subprocess gate. true makes mutmut run an IN-PROCESS coverage pass (the
|
|
430
|
+
# whole suite under coverage.py) before generating, which hits the same numba parallel-JIT LLVM
|
|
431
|
+
# deadlock as the in-process executor -> empty coverage -> ZERO mutants generated. false skips that
|
|
432
|
+
# pass entirely: generation is pure libcst (no suite run, no deadlock) and mutates every in-scope
|
|
433
|
+
# line. The subprocess gate runs all generated mutants anyway, so covered-lines filtering is not
|
|
434
|
+
# needed; uncovered-line survivors are correct signal (a real "no test exercises this line").
|
|
435
|
+
mutate_only_covered_lines = false
|
|
436
|
+
|
|
437
|
+
# Systemic non-behavioral equivalents, suppressed at the source-pattern level (~164 of these were
|
|
438
|
+
# hand-classified as equivalent in the v0.2.0 mutation work). In mutmut 3.6 do_not_mutate_patterns
|
|
439
|
+
# is a list of PYTHON REGEXES, each re.search()-matched against every raw source LINE; a matching
|
|
440
|
+
# line has its expression nodes excluded from mutation (it is line-granular, NOT AST-node text and
|
|
441
|
+
# NOT a glob). Patterns are therefore anchored to their own kwarg/continuation lines so they do not
|
|
442
|
+
# over-suppress mutation of a real algorithmic expression that happens to share the line.
|
|
443
|
+
# - code=Codes.X / context={...}: error-construction kwargs (enum tag + diagnostic dict). Mutating
|
|
444
|
+
# these never changes behavior, only the exception payload, which no test asserts on by value.
|
|
445
|
+
# - dtype=np.<type>: the dtype-default class (e.g. dtype=np.float64 -> None). Inputs are already
|
|
446
|
+
# float64/int by construction, so dropping the explicit dtype is behavior-preserving.
|
|
447
|
+
# - def __<dunder>__ and logger/logging/log.<level>(...) call args: covered for fleet generality
|
|
448
|
+
# (no occurrences in the current engines+model scope, so inert here, but harmless to keep).
|
|
449
|
+
do_not_mutate_patterns = [
|
|
450
|
+
"^\\s*code=Codes\\.",
|
|
451
|
+
"^\\s*context=",
|
|
452
|
+
"dtype=np\\.",
|
|
453
|
+
"^\\s*def __[a-zA-Z]+__\\s*\\(",
|
|
454
|
+
"(?:logger|logging|log)\\.(?:debug|info|warning|error|critical|exception)\\(",
|
|
455
|
+
]
|
|
456
|
+
|
|
395
457
|
pytest_add_cli_args_test_selection = ["-m", "not slow", "tests/"]
|
|
396
|
-
|
|
458
|
+
# -o addopts= drops the project's default addopts (coverage, xdist, durations). The per-test
|
|
459
|
+
# timeout is mutmut's hang guard: a mutant that sends an iterative solver or a recurrence into a
|
|
460
|
+
# non-terminating loop is killed at 60s (thread method, so it interrupts even C-extension calls)
|
|
461
|
+
# instead of stalling the whole run.
|
|
462
|
+
pytest_add_cli_args = ["-o", "addopts=", "--timeout=60", "--timeout-method=thread"]
|
|
@@ -35,12 +35,14 @@ from tsbootstrap.errors import (
|
|
|
35
35
|
TSBootstrapError,
|
|
36
36
|
TSBootstrapWarning,
|
|
37
37
|
)
|
|
38
|
+
from tsbootstrap.metadata import MethodMetadata, metadata_for
|
|
38
39
|
from tsbootstrap.methods import (
|
|
39
40
|
AR,
|
|
40
41
|
ARIMA,
|
|
41
42
|
IID,
|
|
42
43
|
VAR,
|
|
43
44
|
BaseMethodSpec,
|
|
45
|
+
BlockWild,
|
|
44
46
|
CircularBlock,
|
|
45
47
|
MethodSpec,
|
|
46
48
|
MovingBlock,
|
|
@@ -49,6 +51,7 @@ from tsbootstrap.methods import (
|
|
|
49
51
|
SieveAR,
|
|
50
52
|
StationaryBlock,
|
|
51
53
|
TaperedBlock,
|
|
54
|
+
Wild,
|
|
52
55
|
)
|
|
53
56
|
from tsbootstrap.results import (
|
|
54
57
|
BootstrapResult,
|
|
@@ -64,12 +67,21 @@ from tsbootstrap.results import (
|
|
|
64
67
|
from tsbootstrap.uq import (
|
|
65
68
|
EnbPIEnsemble,
|
|
66
69
|
aci_halfwidths,
|
|
70
|
+
basic_interval,
|
|
71
|
+
bca_interval,
|
|
72
|
+
block_jackknife_se,
|
|
73
|
+
conf_int,
|
|
74
|
+
conf_int_panel,
|
|
67
75
|
enbpi_intervals,
|
|
68
76
|
fit_predict_oob,
|
|
69
77
|
forecast_intervals,
|
|
78
|
+
jackknife_acceleration,
|
|
79
|
+
jackknife_statistics,
|
|
70
80
|
nexcp_quantile,
|
|
81
|
+
percentile_interval,
|
|
71
82
|
sliding_window_halfwidths,
|
|
72
83
|
static_halfwidths,
|
|
84
|
+
studentized_interval,
|
|
73
85
|
)
|
|
74
86
|
|
|
75
87
|
try:
|
|
@@ -84,9 +96,11 @@ __all__ = [
|
|
|
84
96
|
"bootstrap_iter",
|
|
85
97
|
"bootstrap_reduce",
|
|
86
98
|
"bootstrap_reduce_panel",
|
|
87
|
-
# diagnostics
|
|
99
|
+
# diagnostics and method introspection
|
|
88
100
|
"diagnose",
|
|
89
101
|
"Diagnosis",
|
|
102
|
+
"metadata_for",
|
|
103
|
+
"MethodMetadata",
|
|
90
104
|
# method specifications
|
|
91
105
|
"IID",
|
|
92
106
|
"MovingBlock",
|
|
@@ -94,6 +108,8 @@ __all__ = [
|
|
|
94
108
|
"StationaryBlock",
|
|
95
109
|
"NonOverlappingBlock",
|
|
96
110
|
"TaperedBlock",
|
|
111
|
+
"Wild",
|
|
112
|
+
"BlockWild",
|
|
97
113
|
"AR",
|
|
98
114
|
"ARIMA",
|
|
99
115
|
"VAR",
|
|
@@ -115,6 +131,15 @@ __all__ = [
|
|
|
115
131
|
"nexcp_quantile",
|
|
116
132
|
"static_halfwidths",
|
|
117
133
|
"sliding_window_halfwidths",
|
|
134
|
+
"percentile_interval",
|
|
135
|
+
"basic_interval",
|
|
136
|
+
"jackknife_statistics",
|
|
137
|
+
"block_jackknife_se",
|
|
138
|
+
"studentized_interval",
|
|
139
|
+
"jackknife_acceleration",
|
|
140
|
+
"bca_interval",
|
|
141
|
+
"conf_int",
|
|
142
|
+
"conf_int_panel",
|
|
118
143
|
# errors and warnings
|
|
119
144
|
"Codes",
|
|
120
145
|
"TSBootstrapError",
|
|
@@ -22,7 +22,9 @@ from tsbootstrap.methods import (
|
|
|
22
22
|
IID,
|
|
23
23
|
VAR,
|
|
24
24
|
BlockLength,
|
|
25
|
+
BlockWild,
|
|
25
26
|
CircularBlock,
|
|
27
|
+
Innovation,
|
|
26
28
|
MethodSpec,
|
|
27
29
|
MovingBlock,
|
|
28
30
|
NonOverlappingBlock,
|
|
@@ -30,6 +32,7 @@ from tsbootstrap.methods import (
|
|
|
30
32
|
SieveAR,
|
|
31
33
|
StationaryBlock,
|
|
32
34
|
TaperedBlock,
|
|
35
|
+
Wild,
|
|
33
36
|
)
|
|
34
37
|
|
|
35
38
|
_Sample = NDArray[np.floating]
|
|
@@ -251,17 +254,30 @@ class ARResidualBootstrap(BaseTimeSeriesBootstrap):
|
|
|
251
254
|
}
|
|
252
255
|
|
|
253
256
|
def __init__(
|
|
254
|
-
self,
|
|
257
|
+
self,
|
|
258
|
+
order: int = 1,
|
|
259
|
+
innovation: Innovation | None = None,
|
|
260
|
+
n_bootstraps: int = 999,
|
|
261
|
+
random_state: int | None = None,
|
|
255
262
|
) -> None:
|
|
256
263
|
self.order = order
|
|
264
|
+
self.innovation = innovation
|
|
257
265
|
super().__init__(n_bootstraps=n_bootstraps, random_state=random_state)
|
|
258
266
|
|
|
259
267
|
def _make_spec(self) -> MethodSpec:
|
|
260
|
-
return ResidualBootstrap(
|
|
268
|
+
return ResidualBootstrap(
|
|
269
|
+
model=AR(order=self.order),
|
|
270
|
+
innovation=self.innovation if self.innovation is not None else IID(),
|
|
271
|
+
)
|
|
261
272
|
|
|
262
273
|
@classmethod
|
|
263
274
|
def get_test_params(cls) -> list[dict[str, Any]]:
|
|
264
|
-
return [
|
|
275
|
+
return [
|
|
276
|
+
{"order": 1, "n_bootstraps": 10},
|
|
277
|
+
{"order": 2, "n_bootstraps": 5},
|
|
278
|
+
{"order": 1, "innovation": Wild(), "n_bootstraps": 5},
|
|
279
|
+
{"order": 1, "innovation": BlockWild(block_length=5), "n_bootstraps": 5},
|
|
280
|
+
]
|
|
265
281
|
|
|
266
282
|
|
|
267
283
|
class ARIMAResidualBootstrap(BaseTimeSeriesBootstrap):
|
|
@@ -276,14 +292,19 @@ class ARIMAResidualBootstrap(BaseTimeSeriesBootstrap):
|
|
|
276
292
|
def __init__(
|
|
277
293
|
self,
|
|
278
294
|
order: tuple[int, int, int] = (1, 1, 1),
|
|
295
|
+
innovation: Innovation | None = None,
|
|
279
296
|
n_bootstraps: int = 999,
|
|
280
297
|
random_state: int | None = None,
|
|
281
298
|
) -> None:
|
|
282
299
|
self.order = order
|
|
300
|
+
self.innovation = innovation
|
|
283
301
|
super().__init__(n_bootstraps=n_bootstraps, random_state=random_state)
|
|
284
302
|
|
|
285
303
|
def _make_spec(self) -> MethodSpec:
|
|
286
|
-
return ResidualBootstrap(
|
|
304
|
+
return ResidualBootstrap(
|
|
305
|
+
model=ARIMA(order=self.order),
|
|
306
|
+
innovation=self.innovation if self.innovation is not None else IID(),
|
|
307
|
+
)
|
|
287
308
|
|
|
288
309
|
@classmethod
|
|
289
310
|
def get_test_params(cls) -> list[dict[str, Any]]:
|
|
@@ -300,13 +321,21 @@ class VARResidualBootstrap(BaseTimeSeriesBootstrap):
|
|
|
300
321
|
}
|
|
301
322
|
|
|
302
323
|
def __init__(
|
|
303
|
-
self,
|
|
324
|
+
self,
|
|
325
|
+
order: int = 1,
|
|
326
|
+
innovation: Innovation | None = None,
|
|
327
|
+
n_bootstraps: int = 999,
|
|
328
|
+
random_state: int | None = None,
|
|
304
329
|
) -> None:
|
|
305
330
|
self.order = order
|
|
331
|
+
self.innovation = innovation
|
|
306
332
|
super().__init__(n_bootstraps=n_bootstraps, random_state=random_state)
|
|
307
333
|
|
|
308
334
|
def _make_spec(self) -> MethodSpec:
|
|
309
|
-
return ResidualBootstrap(
|
|
335
|
+
return ResidualBootstrap(
|
|
336
|
+
model=VAR(order=self.order),
|
|
337
|
+
innovation=self.innovation if self.innovation is not None else IID(),
|
|
338
|
+
)
|
|
310
339
|
|
|
311
340
|
@classmethod
|
|
312
341
|
def get_test_params(cls) -> list[dict[str, Any]]:
|
|
@@ -327,16 +356,23 @@ class SieveBootstrap(BaseTimeSeriesBootstrap):
|
|
|
327
356
|
min_lag: int = 1,
|
|
328
357
|
max_lag: int | None = None,
|
|
329
358
|
criterion: Literal["aic", "bic", "hqic"] = "bic",
|
|
359
|
+
innovation: Innovation | None = None,
|
|
330
360
|
n_bootstraps: int = 999,
|
|
331
361
|
random_state: int | None = None,
|
|
332
362
|
) -> None:
|
|
333
363
|
self.min_lag = min_lag
|
|
334
364
|
self.max_lag = max_lag
|
|
335
365
|
self.criterion: Literal["aic", "bic", "hqic"] = criterion
|
|
366
|
+
self.innovation = innovation
|
|
336
367
|
super().__init__(n_bootstraps=n_bootstraps, random_state=random_state)
|
|
337
368
|
|
|
338
369
|
def _make_spec(self) -> MethodSpec:
|
|
339
|
-
return SieveAR(
|
|
370
|
+
return SieveAR(
|
|
371
|
+
min_lag=self.min_lag,
|
|
372
|
+
max_lag=self.max_lag,
|
|
373
|
+
criterion=self.criterion,
|
|
374
|
+
innovation=self.innovation if self.innovation is not None else IID(),
|
|
375
|
+
)
|
|
340
376
|
|
|
341
377
|
@classmethod
|
|
342
378
|
def get_test_params(cls) -> list[dict[str, Any]]:
|
|
@@ -2114,6 +2114,12 @@ def compiled_supports(method: object) -> bool:
|
|
|
2114
2114
|
if isinstance(method, ResidualBootstrap):
|
|
2115
2115
|
# The recursive residual AR and VAR fast paths are built; ARIMA models stay
|
|
2116
2116
|
# on the numpy backend (the unified entry raises the typed error for them).
|
|
2117
|
+
# The residual kernels resample IID innovations inside the compiled loop, so
|
|
2118
|
+
# any other innovation (the wild multiplier family, block innovations) must be
|
|
2119
|
+
# rejected here: running the IID kernel for them would silently return a
|
|
2120
|
+
# different bootstrap distribution than the one the spec asks for.
|
|
2121
|
+
if not isinstance(method.innovation, IID):
|
|
2122
|
+
return False
|
|
2117
2123
|
return isinstance(method.model, (AR, VAR))
|
|
2118
2124
|
return isinstance(
|
|
2119
2125
|
method, (IID, MovingBlock, CircularBlock, StationaryBlock, NonOverlappingBlock)
|
|
@@ -2122,6 +2128,24 @@ def compiled_supports(method: object) -> bool:
|
|
|
2122
2128
|
|
|
2123
2129
|
def unsupported_method_error(method: object) -> MethodConfigError:
|
|
2124
2130
|
"""The typed error raised when the compiled backend has no kernel for a method."""
|
|
2131
|
+
from tsbootstrap.methods import AR, IID, VAR, ResidualBootstrap
|
|
2132
|
+
|
|
2133
|
+
# A residual bootstrap whose MODEL is supported but whose INNOVATION is not:
|
|
2134
|
+
# name the innovation, not the method, so the message does not falsely imply
|
|
2135
|
+
# that ResidualBootstrap itself lacks a compiled kernel.
|
|
2136
|
+
if (
|
|
2137
|
+
isinstance(method, ResidualBootstrap)
|
|
2138
|
+
and isinstance(method.model, (AR, VAR))
|
|
2139
|
+
and not isinstance(method.innovation, IID)
|
|
2140
|
+
):
|
|
2141
|
+
innovation_name = type(method.innovation).__name__
|
|
2142
|
+
return MethodConfigError(
|
|
2143
|
+
f"backend='compiled' does not support {innovation_name} innovations; "
|
|
2144
|
+
"the compiled residual kernels resample IID innovations only",
|
|
2145
|
+
code=Codes.INVALID_PARAMETER,
|
|
2146
|
+
context={"method": type(method).__name__, "innovation": innovation_name},
|
|
2147
|
+
hint="Use the default backend='numpy' for wild-type or block innovations.",
|
|
2148
|
+
)
|
|
2125
2149
|
return MethodConfigError(
|
|
2126
2150
|
f"backend='compiled' does not support {type(method).__name__}; "
|
|
2127
2151
|
f"supported methods: {list(_SUPPORTED_METHOD_NAMES)}.",
|
|
@@ -40,6 +40,7 @@ from tsbootstrap.methods import (
|
|
|
40
40
|
StationaryBlock,
|
|
41
41
|
TaperedBlock,
|
|
42
42
|
)
|
|
43
|
+
from tsbootstrap.uq.classical import percentile_interval
|
|
43
44
|
|
|
44
45
|
if TYPE_CHECKING: # pragma: no cover - import only for type checkers
|
|
45
46
|
from mcp.server.fastmcp import FastMCP
|
|
@@ -373,15 +374,13 @@ def bootstrap_confidence_interval(
|
|
|
373
374
|
return _error(f"bootstrap run failed: {result.failure_reason}")
|
|
374
375
|
|
|
375
376
|
replicate_stats = np.asarray(result.statistics, dtype=np.float64).reshape(-1)
|
|
376
|
-
|
|
377
|
-
lower_q = 100.0 * (alpha / 2.0)
|
|
378
|
-
upper_q = 100.0 * (1.0 - alpha / 2.0)
|
|
377
|
+
ci_lower, ci_upper = percentile_interval(replicate_stats, alpha=1.0 - confidence_level)
|
|
379
378
|
|
|
380
379
|
return {
|
|
381
380
|
"point_estimate": float(reducer(arr)),
|
|
382
381
|
"standard_error": float(np.std(replicate_stats, ddof=0)),
|
|
383
|
-
"ci_lower": float(
|
|
384
|
-
"ci_upper": float(
|
|
382
|
+
"ci_lower": float(ci_lower),
|
|
383
|
+
"ci_upper": float(ci_upper),
|
|
385
384
|
"confidence_level": float(confidence_level),
|
|
386
385
|
"n_bootstraps": int(n_bootstraps),
|
|
387
386
|
"method": method_name,
|
|
@@ -118,7 +118,14 @@ METHODS: dict[type, MethodMetadata] = {
|
|
|
118
118
|
supports_indices=False,
|
|
119
119
|
supports_oob=False,
|
|
120
120
|
preserves_temporal_dependence=True,
|
|
121
|
-
references=(
|
|
121
|
+
references=(
|
|
122
|
+
"Efron-Tibshirani 1993",
|
|
123
|
+
"Kreiss-Lahiri 2012",
|
|
124
|
+
"Wu 1986 (wild innovations)",
|
|
125
|
+
"Mammen 1993 (wild innovations)",
|
|
126
|
+
"Davidson-Flachaire 2008 (Rademacher default)",
|
|
127
|
+
"Shao 2010 (block-wild innovations)",
|
|
128
|
+
),
|
|
122
129
|
complexity="O(B*n*p) AR; O(B*n*p*d^2) VAR",
|
|
123
130
|
failure_modes=("model misspecification", "near-unit-root instability"),
|
|
124
131
|
),
|
|
@@ -14,6 +14,8 @@ Composition:
|
|
|
14
14
|
|
|
15
15
|
- Observation-resampling specs (:class:`IID`, the ``*Block`` family) double as
|
|
16
16
|
the ``innovation`` resampler for residual/sieve bootstraps.
|
|
17
|
+
- :class:`Wild` and :class:`BlockWild` are innovation-only specs (multiplier
|
|
18
|
+
resamplers); they are valid as ``innovation`` but not as a top-level method.
|
|
17
19
|
- :class:`ResidualBootstrap` pairs a model (:class:`AR`/:class:`ARIMA`/
|
|
18
20
|
:class:`VAR`) with an innovation resampler.
|
|
19
21
|
"""
|
|
@@ -121,6 +123,56 @@ class TaperedBlock(BaseMethodSpec):
|
|
|
121
123
|
_v = field_validator("block_length", mode="before")(_check_block_length)
|
|
122
124
|
|
|
123
125
|
|
|
126
|
+
# --------------------------------------------------------------------------- #
|
|
127
|
+
# Innovation-only specs (valid ONLY as an `innovation` resampler, never as a
|
|
128
|
+
# top-level method: they transform residuals in place rather than resample
|
|
129
|
+
# observations, so no observation indices exist).
|
|
130
|
+
# --------------------------------------------------------------------------- #
|
|
131
|
+
WildDistribution = Literal["rademacher", "gaussian", "mammen"]
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class Wild(BaseMethodSpec):
|
|
135
|
+
"""Wild bootstrap innovations (Wu 1986; Liu 1988): ``e*_t = v_t * e_hat_t``.
|
|
136
|
+
|
|
137
|
+
Each centered residual keeps its time position and magnitude; an i.i.d.
|
|
138
|
+
external multiplier ``v_t`` (mean 0, variance 1) randomizes its sign/scale.
|
|
139
|
+
Valid under conditional heteroskedasticity of unknown form, where index
|
|
140
|
+
resampling would average the variance profile away. The default Rademacher
|
|
141
|
+
multiplier follows Davidson and Flachaire (2008); ``"mammen"`` is the
|
|
142
|
+
two-point distribution of Mammen (1993) matching the third moment;
|
|
143
|
+
``"gaussian"`` is the standard normal multiplier.
|
|
144
|
+
|
|
145
|
+
Requires ``burn_in=0`` and ``initial="fixed"`` on the host model spec: the
|
|
146
|
+
multiplier stream is aligned one-to-one with the residuals, conditional on
|
|
147
|
+
the observed initial values.
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
kind: Literal["wild"] = "wild"
|
|
151
|
+
distribution: WildDistribution = "rademacher"
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class BlockWild(BaseMethodSpec):
|
|
155
|
+
"""Block-wild bootstrap innovations: multipliers constant on time blocks.
|
|
156
|
+
|
|
157
|
+
One multiplier is drawn per contiguous non-overlapping block of the
|
|
158
|
+
residual sequence and repeated across that block, so within-block residual
|
|
159
|
+
dependence survives the resampling (a piecewise-constant special case of
|
|
160
|
+
the dependent wild bootstrap of Shao 2010; the block-constant construction
|
|
161
|
+
mirrors the wild cluster bootstrap of Cameron, Gelbach, and Miller 2008
|
|
162
|
+
with time blocks as clusters). ``block_length=1`` degenerates to
|
|
163
|
+
:class:`Wild`. ``"auto"`` resolves the block length from the centered
|
|
164
|
+
residuals via the Politis-White rule at fit time.
|
|
165
|
+
|
|
166
|
+
Same host-model constraints as :class:`Wild` (``burn_in=0``,
|
|
167
|
+
``initial="fixed"``).
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
kind: Literal["block_wild"] = "block_wild"
|
|
171
|
+
distribution: WildDistribution = "rademacher"
|
|
172
|
+
block_length: BlockLength = "auto"
|
|
173
|
+
_v = field_validator("block_length", mode="before")(_check_block_length)
|
|
174
|
+
|
|
175
|
+
|
|
124
176
|
# --------------------------------------------------------------------------- #
|
|
125
177
|
# Model specs (the conditional mean for residual bootstraps).
|
|
126
178
|
# --------------------------------------------------------------------------- #
|
|
@@ -160,7 +212,7 @@ class VAR(_RecursiveInitSpec):
|
|
|
160
212
|
|
|
161
213
|
|
|
162
214
|
Innovation = Annotated[
|
|
163
|
-
Union[IID, MovingBlock, CircularBlock, StationaryBlock, NonOverlappingBlock],
|
|
215
|
+
Union[IID, MovingBlock, CircularBlock, StationaryBlock, NonOverlappingBlock, Wild, BlockWild],
|
|
164
216
|
Field(discriminator="kind"),
|
|
165
217
|
]
|
|
166
218
|
ModelSpec = Annotated[Union[AR, ARIMA, VAR], Field(discriminator="kind")]
|
|
@@ -223,6 +275,9 @@ __all__ = [
|
|
|
223
275
|
"StationaryBlock",
|
|
224
276
|
"NonOverlappingBlock",
|
|
225
277
|
"TaperedBlock",
|
|
278
|
+
"Wild",
|
|
279
|
+
"BlockWild",
|
|
280
|
+
"WildDistribution",
|
|
226
281
|
"AR",
|
|
227
282
|
"ARIMA",
|
|
228
283
|
"VAR",
|