volengine 0.9.0__py3-none-win_amd64.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.
- volengine/__init__.py +37 -0
- volengine/_dcc.py +264 -0
- volengine/_diagnostics.py +51 -0
- volengine/_fit.py +209 -0
- volengine/_forecast.py +65 -0
- volengine/_lib/libvolengine.dll +0 -0
- volengine/_native.py +329 -0
- volengine/_simulation.py +70 -0
- volengine/_spec.py +240 -0
- volengine/api.py +417 -0
- volengine/py.typed +0 -0
- volengine-0.9.0.dist-info/METADATA +6 -0
- volengine-0.9.0.dist-info/RECORD +14 -0
- volengine-0.9.0.dist-info/WHEEL +4 -0
volengine/api.py
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"""Public API: the fitting context and the re-exported spec, options and result types."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import ctypes
|
|
6
|
+
import operator
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
from contextlib import ExitStack
|
|
9
|
+
from typing import TYPE_CHECKING, Any, TypedDict, overload
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
from numpy.typing import ArrayLike, NDArray
|
|
13
|
+
|
|
14
|
+
from ._dcc import DccFit, DccSpec, fit_dcc, open_future
|
|
15
|
+
from ._diagnostics import DiagnosticResult, Nyblom, SignBias
|
|
16
|
+
from ._fit import CoefTable, Fit, future_panel
|
|
17
|
+
from ._forecast import DccForecast, Forecast
|
|
18
|
+
from ._native import (
|
|
19
|
+
ELEMENT_BYTES,
|
|
20
|
+
Handle,
|
|
21
|
+
VolEngineError,
|
|
22
|
+
check,
|
|
23
|
+
create_handle,
|
|
24
|
+
int32,
|
|
25
|
+
lib,
|
|
26
|
+
open_panel,
|
|
27
|
+
)
|
|
28
|
+
from ._simulation import DccSimulation, Simulation
|
|
29
|
+
from ._spec import FitOptions, Spec
|
|
30
|
+
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from typing import Unpack
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"CoefTable",
|
|
36
|
+
"Context",
|
|
37
|
+
"DccFit",
|
|
38
|
+
"DccForecast",
|
|
39
|
+
"DccSimulation",
|
|
40
|
+
"DccSpec",
|
|
41
|
+
"DiagnosticResult",
|
|
42
|
+
"Fit",
|
|
43
|
+
"FitOptions",
|
|
44
|
+
"Forecast",
|
|
45
|
+
"Nyblom",
|
|
46
|
+
"SignBias",
|
|
47
|
+
"Simulation",
|
|
48
|
+
"Spec",
|
|
49
|
+
"VolEngineError",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
Series1D = Sequence[float]
|
|
53
|
+
UINT64_END = 2**64
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class FitKeywords(TypedDict, total=False):
|
|
57
|
+
"""The optional keywords of `Context.fit`."""
|
|
58
|
+
|
|
59
|
+
options: FitOptions | None
|
|
60
|
+
starts: ArrayLike | None
|
|
61
|
+
lengths: ArrayLike | None
|
|
62
|
+
mxreg: ArrayLike | None
|
|
63
|
+
vxreg: ArrayLike | None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class FutureKeywords(TypedDict, total=False):
|
|
67
|
+
"""The optional keywords of `Context.simulate`: the regressors of the horizon."""
|
|
68
|
+
|
|
69
|
+
mxreg: ArrayLike | None
|
|
70
|
+
vxreg: ArrayLike | None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class DccSimulateKeywords(TypedDict, total=False):
|
|
74
|
+
"""The optional keywords of `Context.simulate` from a DccFit: `correlations` and one entry per series of each
|
|
75
|
+
regressor kind, as in `DccFit.forecast`."""
|
|
76
|
+
|
|
77
|
+
correlations: bool
|
|
78
|
+
mxreg: Sequence[ArrayLike | None] | None
|
|
79
|
+
vxreg: Sequence[ArrayLike | None] | None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def panel_array(data: ArrayLike) -> tuple[NDArray[np.float64], bool]:
|
|
83
|
+
array = np.asarray(data, dtype=np.float64)
|
|
84
|
+
if array.ndim == 1:
|
|
85
|
+
return array.reshape(-1, 1), True
|
|
86
|
+
if array.ndim == 2:
|
|
87
|
+
return array, False
|
|
88
|
+
raise ValueError(f"data must be 1D (T,) or 2D (T, N), got {array.ndim} dimensions")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def require_integral(array: NDArray[Any], name: str) -> None:
|
|
92
|
+
if array.dtype.kind in "iu" and not (array < 0).any():
|
|
93
|
+
return
|
|
94
|
+
if array.dtype.kind == "f" and np.isfinite(array).all() and (array >= 0).all() and (array == np.floor(array)).all():
|
|
95
|
+
return
|
|
96
|
+
raise ValueError(f"{name} must hold non-negative integers, got dtype {array.dtype} with values {array.tolist()}")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def range_array(values: ArrayLike, series_count: int, name: str) -> NDArray[np.uintp]:
|
|
100
|
+
array = np.asarray(values)
|
|
101
|
+
if array.shape != (series_count,):
|
|
102
|
+
raise ValueError(f"{name} must have one entry per series ({series_count}), got shape {array.shape}")
|
|
103
|
+
require_integral(array, name)
|
|
104
|
+
return np.ascontiguousarray(array, dtype=np.uintp)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def set_ranges(panel: Handle, first: NDArray[np.uintp], size: NDArray[np.uintp]) -> None:
|
|
108
|
+
check(lib.ve_panel_set_ranges(panel.pointer, first.ctypes.data, size.ctypes.data))
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def set_jobs(batch: Handle, spec_count: int, series_count: int) -> None:
|
|
112
|
+
job_spec = np.repeat(np.arange(spec_count, dtype=np.uintp), series_count)
|
|
113
|
+
job_series = np.tile(np.arange(series_count, dtype=np.uintp), spec_count)
|
|
114
|
+
check(lib.ve_batch_set_jobs(batch.pointer, job_spec.ctypes.data, job_series.ctypes.data, job_spec.size))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def open_batch(stack: ExitStack, specs: Sequence[Spec], panel: Handle, options: FitOptions | None) -> Handle:
|
|
118
|
+
batch = stack.enter_context(create_handle(lib.ve_batch_create, lib.ve_batch_free))
|
|
119
|
+
spec_handles = [stack.enter_context(spec.native_handle()) for spec in specs]
|
|
120
|
+
pointers = (ctypes.c_void_p * len(spec_handles))(*(handle.pointer for handle in spec_handles))
|
|
121
|
+
check(lib.ve_batch_set_specs(batch.pointer, pointers, len(spec_handles)))
|
|
122
|
+
check(lib.ve_batch_set_panel(batch.pointer, panel.pointer))
|
|
123
|
+
if options is not None:
|
|
124
|
+
options_handle = stack.enter_context(options.native_handle())
|
|
125
|
+
check(lib.ve_batch_set_options(batch.pointer, options_handle.pointer))
|
|
126
|
+
return batch
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def regressor_array(
|
|
130
|
+
values: ArrayLike | None, name: str, counts: list[int], data_shape: tuple[int, ...]
|
|
131
|
+
) -> NDArray[np.float64] | None:
|
|
132
|
+
"""`values` as (T, N, k), or None when no spec has regressors of this kind; the specs with k = 0 ignore it."""
|
|
133
|
+
widths = {count for count in counts if count > 0}
|
|
134
|
+
if not widths and values is not None:
|
|
135
|
+
raise ValueError(f"{name} was given but no spec has {name} > 0")
|
|
136
|
+
if not widths:
|
|
137
|
+
return None
|
|
138
|
+
if values is None:
|
|
139
|
+
raise ValueError(f"a spec has {name} > 0, so {name} is required")
|
|
140
|
+
array = np.asarray(values, dtype=np.float64)
|
|
141
|
+
for width in widths:
|
|
142
|
+
if array.shape != (*data_shape, width):
|
|
143
|
+
raise ValueError(f"{name} must have shape {(*data_shape, width)} for a spec with {name} = {width}, "
|
|
144
|
+
f"got {array.shape}")
|
|
145
|
+
if len(data_shape) == 1:
|
|
146
|
+
array = array[:, None, :]
|
|
147
|
+
if any(stride % ELEMENT_BYTES for stride in array.strides):
|
|
148
|
+
array = np.ascontiguousarray(array)
|
|
149
|
+
return array
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def open_regressors(stack: ExitStack, array: NDArray[np.float64] | None, counts: list[int]) -> NDArray[np.uintp] | None:
|
|
153
|
+
"""The panel of job j, in the order of `set_jobs`, for each spec in `counts`: series s of `array`, no copy."""
|
|
154
|
+
if array is None:
|
|
155
|
+
return None
|
|
156
|
+
pointers = [open_panel(stack, array[:, series, :]).pointer for series in range(array.shape[1])]
|
|
157
|
+
absent = [0] * len(pointers)
|
|
158
|
+
jobs: list[int] = []
|
|
159
|
+
for count in counts:
|
|
160
|
+
jobs += pointers if count > 0 else absent
|
|
161
|
+
return np.array(jobs, dtype=np.uintp)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def set_regressors(batch: Handle, mean: NDArray[np.uintp] | None, variance: NDArray[np.uintp] | None) -> None:
|
|
165
|
+
jobs = mean if mean is not None else variance
|
|
166
|
+
if jobs is None:
|
|
167
|
+
return
|
|
168
|
+
mean_data = None
|
|
169
|
+
if mean is not None:
|
|
170
|
+
mean_data = mean.ctypes.data
|
|
171
|
+
variance_data = None
|
|
172
|
+
if variance is not None:
|
|
173
|
+
variance_data = variance.ctypes.data
|
|
174
|
+
check(lib.ve_batch_set_regressors(batch.pointer, mean_data, variance_data, jobs.size))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def shaped(fits: list[Fit], shape: tuple[int, ...]) -> NDArray[np.object_]:
|
|
178
|
+
grid = np.empty(len(fits), dtype=object)
|
|
179
|
+
for position, fit in enumerate(fits):
|
|
180
|
+
grid[position] = fit
|
|
181
|
+
return grid.reshape(shape)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def bounded(value: int, name: str, low: int) -> int:
|
|
185
|
+
"""value as an integer in [low, 2**64), the range of the size_t and uint64_t of the C API."""
|
|
186
|
+
value = operator.index(value)
|
|
187
|
+
if not low <= value < UINT64_END:
|
|
188
|
+
raise ValueError(f"{name} must be an integer in [{low}, 2**64), got {value}")
|
|
189
|
+
return value
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def regressor_counts(source: Fit | Spec) -> tuple[int, int]:
|
|
193
|
+
if isinstance(source, Spec):
|
|
194
|
+
return source.mxreg, source.vxreg
|
|
195
|
+
mean = sum(1 for name in source.names if name.startswith("mxreg"))
|
|
196
|
+
variance = sum(1 for name in source.names if name.startswith("vxreg"))
|
|
197
|
+
return mean, variance
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class Context:
|
|
201
|
+
"""Execution context owning the native thread pool; fits do not depend on it afterwards.
|
|
202
|
+
|
|
203
|
+
`threads` is between 1 and 1024 (VE_MAX_THREADS); 0, the default, means the hardware
|
|
204
|
+
concurrency, capped at 1024.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
def __init__(self, threads: int = 0) -> None:
|
|
208
|
+
threads = int32(threads, "threads")
|
|
209
|
+
self._handle = create_handle(lib.ve_context_create, lib.ve_context_free)
|
|
210
|
+
check(lib.ve_context_set_threads(self._handle.pointer, threads))
|
|
211
|
+
|
|
212
|
+
@overload
|
|
213
|
+
def fit(self, spec: Spec, data: Series1D, **keywords: Unpack[FitKeywords]) -> Fit: ...
|
|
214
|
+
|
|
215
|
+
@overload
|
|
216
|
+
def fit(self, spec: Spec, data: ArrayLike, **keywords: Unpack[FitKeywords]) -> Fit | NDArray[np.object_]: ...
|
|
217
|
+
|
|
218
|
+
@overload
|
|
219
|
+
def fit(self, spec: Sequence[Spec], data: ArrayLike, **keywords: Unpack[FitKeywords]) -> NDArray[np.object_]: ...
|
|
220
|
+
|
|
221
|
+
def fit(
|
|
222
|
+
self, spec: Spec | Sequence[Spec], data: ArrayLike, **keywords: Unpack[FitKeywords]
|
|
223
|
+
) -> Fit | NDArray[np.object_]:
|
|
224
|
+
"""Fit every spec on every series of `data`: (T,) or (T, N), optionally with row ranges.
|
|
225
|
+
|
|
226
|
+
One spec and a 1D series give a Fit; one spec and (T, N) data give an object array of
|
|
227
|
+
shape (N,); a list of specs gives (n_specs,) or (n_specs, N).
|
|
228
|
+
|
|
229
|
+
Keywords (all optional): `options` (FitOptions), `starts` and `lengths` (row ranges, given together),
|
|
230
|
+
`mxreg` and `vxreg`, the mean and variance regressors of the specs with mxreg > 0 or vxreg > 0:
|
|
231
|
+
shape (T, k) for 1D data and (T, N, k) for (T, N) data, k being the count of the spec (a different k, a
|
|
232
|
+
different shape or a missing array is a ValueError). Series j uses X[:, j, :] without a copy, and with
|
|
233
|
+
`starts` and `lengths` its rows starts[j] .. starts[j] + lengths[j] - 1 of the regressors. The specs with a
|
|
234
|
+
count of 0 take no regressors; an array given when every spec has a count of 0 is a ValueError.
|
|
235
|
+
"""
|
|
236
|
+
unknown = sorted(keywords.keys() - FitKeywords.__annotations__.keys())
|
|
237
|
+
if unknown:
|
|
238
|
+
raise TypeError(f"fit() got an unexpected keyword argument {unknown[0]!r}")
|
|
239
|
+
starts, lengths = keywords.get("starts"), keywords.get("lengths")
|
|
240
|
+
if (starts is None) != (lengths is None):
|
|
241
|
+
raise ValueError("starts and lengths must be given together")
|
|
242
|
+
specs: list[Spec] = []
|
|
243
|
+
if isinstance(spec, Spec):
|
|
244
|
+
specs.append(spec)
|
|
245
|
+
if not isinstance(spec, Spec):
|
|
246
|
+
specs.extend(spec)
|
|
247
|
+
array, one_dimensional = panel_array(data)
|
|
248
|
+
series_count = array.shape[1]
|
|
249
|
+
ranges = None
|
|
250
|
+
if starts is not None and lengths is not None:
|
|
251
|
+
ranges = (range_array(starts, series_count, "starts"), range_array(lengths, series_count, "lengths"))
|
|
252
|
+
data_shape = array.shape
|
|
253
|
+
if one_dimensional:
|
|
254
|
+
data_shape = array.shape[:1]
|
|
255
|
+
regressors = (
|
|
256
|
+
regressor_array(keywords.get("mxreg"), "mxreg", [item.mxreg for item in specs], data_shape),
|
|
257
|
+
regressor_array(keywords.get("vxreg"), "vxreg", [item.vxreg for item in specs], data_shape),
|
|
258
|
+
)
|
|
259
|
+
fits = self._run(specs, array, keywords.get("options"), ranges, regressors)
|
|
260
|
+
if isinstance(spec, Spec) and one_dimensional:
|
|
261
|
+
return fits[0]
|
|
262
|
+
if isinstance(spec, Spec):
|
|
263
|
+
return shaped(fits, (series_count,))
|
|
264
|
+
if one_dimensional:
|
|
265
|
+
return shaped(fits, (len(specs),))
|
|
266
|
+
return shaped(fits, (len(specs), series_count))
|
|
267
|
+
|
|
268
|
+
@overload
|
|
269
|
+
def fit_dcc(self, spec: DccSpec, univariate: Sequence[Fit], *, standard_errors: bool = True) -> DccFit: ...
|
|
270
|
+
|
|
271
|
+
@overload
|
|
272
|
+
def fit_dcc(
|
|
273
|
+
self, spec: Sequence[DccSpec], univariate: Sequence[Fit], *, standard_errors: bool = True
|
|
274
|
+
) -> list[DccFit]: ...
|
|
275
|
+
|
|
276
|
+
def fit_dcc(
|
|
277
|
+
self, spec: DccSpec | Sequence[DccSpec], univariate: Sequence[Fit], *, standard_errors: bool = True
|
|
278
|
+
) -> DccFit | list[DccFit]:
|
|
279
|
+
"""Fit one DCC spec or a grid over the chosen ordered univariate fits.
|
|
280
|
+
|
|
281
|
+
Fits need at least two series with the same T >= 100 and finite points.
|
|
282
|
+
Disable standard errors for grid selection, then call the selected result's
|
|
283
|
+
standard_errors(univariate). Regressor fits require this option disabled.
|
|
284
|
+
"""
|
|
285
|
+
results = fit_dcc(self._handle, spec, univariate, standard_errors)
|
|
286
|
+
if isinstance(spec, DccSpec):
|
|
287
|
+
return results[0]
|
|
288
|
+
return results
|
|
289
|
+
|
|
290
|
+
@overload
|
|
291
|
+
def simulate(
|
|
292
|
+
self,
|
|
293
|
+
source: Fit | Spec,
|
|
294
|
+
*,
|
|
295
|
+
horizon: int,
|
|
296
|
+
paths: int,
|
|
297
|
+
seed: int,
|
|
298
|
+
**regressors: Unpack[FutureKeywords],
|
|
299
|
+
) -> Simulation: ...
|
|
300
|
+
|
|
301
|
+
@overload
|
|
302
|
+
def simulate(
|
|
303
|
+
self,
|
|
304
|
+
source: DccFit,
|
|
305
|
+
*,
|
|
306
|
+
horizon: int,
|
|
307
|
+
paths: int,
|
|
308
|
+
seed: int,
|
|
309
|
+
**options: Unpack[DccSimulateKeywords],
|
|
310
|
+
) -> DccSimulation: ...
|
|
311
|
+
|
|
312
|
+
def simulate(
|
|
313
|
+
self,
|
|
314
|
+
source: Fit | Spec | DccFit,
|
|
315
|
+
*,
|
|
316
|
+
horizon: int,
|
|
317
|
+
paths: int,
|
|
318
|
+
seed: int,
|
|
319
|
+
**regressors: Any,
|
|
320
|
+
) -> Simulation | DccSimulation:
|
|
321
|
+
"""Simulate `paths` paths of `horizon` steps from a fit or from a spec with every parameter fixed.
|
|
322
|
+
|
|
323
|
+
From a Fit the paths continue after its last observation (rugarch's ugarchsim, startMethod = "sample");
|
|
324
|
+
from a Spec they start at its unconditional state (rugarch's ugarchpath), which needs every parameter
|
|
325
|
+
fixed, no variance targeting, a stationary model and not iGARCH (VolEngineError otherwise). `mxreg` and
|
|
326
|
+
`vxreg` are the regressors of the horizon, as in `Fit.forecast`, the same for every path. The threads of the
|
|
327
|
+
context share the paths; the same seed gives the same paths for any thread count, within one version of
|
|
328
|
+
the library. `seed` is an integer in [0, 2**64).
|
|
329
|
+
|
|
330
|
+
From a DccFit (a result of `fit_dcc`, which keeps the final state of each series and needs no univariate
|
|
331
|
+
`Fit`) the paths are multivariate and give a DccSimulation: `mxreg` and `vxreg` are sequences with one entry
|
|
332
|
+
per series, as in `DccFit.forecast`, and `correlations=True` keeps R and H of every path and step (memory:
|
|
333
|
+
paths x horizon x N^2 x 2 doubles). Path p reads only the stream (seed, p), with the same version rule.
|
|
334
|
+
"""
|
|
335
|
+
horizon = bounded(horizon, "horizon", 1)
|
|
336
|
+
paths = bounded(paths, "paths", 1)
|
|
337
|
+
seed = bounded(seed, "seed", 0)
|
|
338
|
+
if isinstance(source, DccFit):
|
|
339
|
+
return self._simulate_dcc(source, horizon, paths, seed, regressors)
|
|
340
|
+
if "correlations" in regressors:
|
|
341
|
+
raise TypeError("correlations is only for a DccFit")
|
|
342
|
+
unknown = sorted(regressors.keys() - FutureKeywords.__annotations__.keys())
|
|
343
|
+
if unknown:
|
|
344
|
+
raise TypeError(f"simulate() got an unexpected keyword argument {unknown[0]!r}")
|
|
345
|
+
counts = regressor_counts(source)
|
|
346
|
+
with ExitStack() as stack:
|
|
347
|
+
mean = future_panel(stack, regressors.get("mxreg"), "mxreg", counts[0], horizon)
|
|
348
|
+
variance = future_panel(stack, regressors.get("vxreg"), "vxreg", counts[1], horizon)
|
|
349
|
+
options = stack.enter_context(
|
|
350
|
+
create_handle(lib.ve_sim_options_create, lib.ve_sim_options_free, horizon, paths, seed)
|
|
351
|
+
)
|
|
352
|
+
check(lib.ve_sim_options_set_regressors(options.pointer, mean, variance))
|
|
353
|
+
if isinstance(source, Spec):
|
|
354
|
+
spec = stack.enter_context(source.native_handle())
|
|
355
|
+
return Simulation(
|
|
356
|
+
create_handle(
|
|
357
|
+
lib.ve_simulate_spec, lib.ve_sim_free, self._handle.pointer, spec.pointer, options.pointer
|
|
358
|
+
)
|
|
359
|
+
)
|
|
360
|
+
return Simulation(
|
|
361
|
+
create_handle(
|
|
362
|
+
lib.ve_simulate_fit, lib.ve_sim_free, self._handle.pointer, source._handle.pointer, options.pointer
|
|
363
|
+
)
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
def _simulate_dcc(
|
|
367
|
+
self, source: DccFit, horizon: int, paths: int, seed: int, options: dict[str, Any]
|
|
368
|
+
) -> DccSimulation:
|
|
369
|
+
unknown = sorted(options.keys() - DccSimulateKeywords.__annotations__.keys())
|
|
370
|
+
if unknown:
|
|
371
|
+
raise TypeError(f"simulate() got an unexpected keyword argument {unknown[0]!r}")
|
|
372
|
+
with ExitStack() as stack:
|
|
373
|
+
future = open_future(stack, horizon, options.get("mxreg"), options.get("vxreg"))
|
|
374
|
+
handle = stack.enter_context(
|
|
375
|
+
create_handle(lib.ve_sim_options_create, lib.ve_sim_options_free, horizon, paths, seed)
|
|
376
|
+
)
|
|
377
|
+
check(lib.ve_sim_options_set_correlations(handle.pointer, int(bool(options.get("correlations", False)))))
|
|
378
|
+
return DccSimulation(
|
|
379
|
+
create_handle(
|
|
380
|
+
lib.ve_simulate_dcc,
|
|
381
|
+
lib.ve_dcc_sim_free,
|
|
382
|
+
self._handle.pointer,
|
|
383
|
+
source._handle.pointer,
|
|
384
|
+
handle.pointer,
|
|
385
|
+
future,
|
|
386
|
+
)
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
def _run(
|
|
390
|
+
self,
|
|
391
|
+
specs: list[Spec],
|
|
392
|
+
array: NDArray[np.float64],
|
|
393
|
+
options: FitOptions | None,
|
|
394
|
+
ranges: tuple[NDArray[np.uintp], NDArray[np.uintp]] | None,
|
|
395
|
+
regressors: tuple[NDArray[np.float64] | None, NDArray[np.float64] | None],
|
|
396
|
+
) -> list[Fit]:
|
|
397
|
+
if any(stride % ELEMENT_BYTES for stride in array.strides):
|
|
398
|
+
array = np.ascontiguousarray(array)
|
|
399
|
+
series_count = array.shape[1]
|
|
400
|
+
with ExitStack() as stack:
|
|
401
|
+
panel = open_panel(stack, array)
|
|
402
|
+
if ranges is not None:
|
|
403
|
+
set_ranges(panel, ranges[0], ranges[1])
|
|
404
|
+
batch = open_batch(stack, specs, panel, options)
|
|
405
|
+
set_jobs(batch, len(specs), series_count)
|
|
406
|
+
mean = open_regressors(stack, regressors[0], [spec.mxreg for spec in specs])
|
|
407
|
+
variance = open_regressors(stack, regressors[1], [spec.vxreg for spec in specs])
|
|
408
|
+
set_regressors(batch, mean, variance)
|
|
409
|
+
return self._fit_batch(batch)
|
|
410
|
+
|
|
411
|
+
def _fit_batch(self, batch: Handle) -> list[Fit]:
|
|
412
|
+
count = ctypes.c_size_t()
|
|
413
|
+
check(lib.ve_batch_job_count(batch.pointer, ctypes.byref(count)))
|
|
414
|
+
pointers = (ctypes.c_void_p * count.value)()
|
|
415
|
+
check(lib.ve_fit_batch(self._handle.pointer, batch.pointer, pointers))
|
|
416
|
+
handles = [Handle(pointer, lib.ve_fit_free) for pointer in pointers]
|
|
417
|
+
return [Fit(handle) for handle in handles]
|
volengine/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
volengine/__init__.py,sha256=KVxuLMbldIavrfwTggf3MAsSs4mc9088nyPVtyW7MOo,608
|
|
2
|
+
volengine/_dcc.py,sha256=-dLUE27huFh6QyWxURMYYBJkkTgCs_rJ7O5kBpGjoOs,12510
|
|
3
|
+
volengine/_diagnostics.py,sha256=qLaZaNwxv0peZ3IikitlvRL3iHn556c9kZy1dwSah80,1419
|
|
4
|
+
volengine/_fit.py,sha256=-dsMyQqTp7zVKIQrwYi5T2kQFYq-fFc7nCdoP1y9F7A,9259
|
|
5
|
+
volengine/_forecast.py,sha256=uKVSKmTusu26G6L8qPxYwI6awFwjiMn6q7yiCh6Bv2Y,2912
|
|
6
|
+
volengine/_native.py,sha256=vVC-6H8ZNDEh7MBjTGTVmx98MSmj_rybqc28QEKEHtU,14354
|
|
7
|
+
volengine/_simulation.py,sha256=52Ebjwr3_1zzWDPNt3j8M7nrjackF5WjpoNxPpQBhJY,3123
|
|
8
|
+
volengine/_spec.py,sha256=q1DbCU_8FDG75C6z4DrelCUfrfdajSelS3Zg4nhMcos,12886
|
|
9
|
+
volengine/api.py,sha256=38OeiXpn0apcJ5ZW03UVCfxfTUh1I31s7lqsOJgs7c4,17968
|
|
10
|
+
volengine/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
volengine/_lib/libvolengine.dll,sha256=gEwKxhqXHPLp1TqD-38ZsHrJ5oURZz0te43bA_xw3PA,6224908
|
|
12
|
+
volengine-0.9.0.dist-info/METADATA,sha256=HmzwJGEhpK8LYuy0F6v5He2MBwkHOR1TJi1wTQXrUTc,160
|
|
13
|
+
volengine-0.9.0.dist-info/WHEEL,sha256=lpoBGaIUIidvvdZ4qRAP61bBKYJdt4FI3WXFL50Gzyo,94
|
|
14
|
+
volengine-0.9.0.dist-info/RECORD,,
|