TSIGenerator
Bases: BaseGenerator
Generate series by composing randomized Trend, Seasonality and
Irregularity components.
The component-based construction is based on Bahrpeyma et al. (2021),
“A Methodology for Validating Diversity in Synthetic Time Series
Generation,” https://doi.org/10.1016/j.mex.2021.101459. SynForecast’s
component families, sampling distributions, and stability guards are its
own extensions rather than a reproduction of that paper’s generator.
Every series draws a fresh random configuration: a trend type from
trend_types, 0-3 seasonal harmonics with periods from
seasonal_periods (integer and non-integer, so multiple harmonics are
incommensurate), and an irregular (noise) process from
irregular_types. The components are combined additively, or
multiplicatively with probability multiplicative_prob when the trend
base can be kept positive:
trend_slope_range regardless of length; harmonic
amplitudes are log-uniform; the noise scale is a log-uniform fraction
of the structural signal’s standard deviation, so the pool spans
signal-dominated through noise-dominated series. A per-series level
and log-uniform scale spread series across magnitudes. Degenerate or
exploding draws (non-finite, |y| >= 1e8, or constant) are redrawn a
bounded number of times.
Parameters:
TSIGenerator.generate_single_series
Returns:
TCMGenerator
Bases: BaseGenerator
Generate series from a random temporal structural causal model (SCM).
Each series gets a freshly sampled SCM over n_vars latent variables:
a sparse dependency graph over the (variable x lag) space is drawn, each
edge is assigned a random edge function, and the system is rolled out
autoregressively. Node i evolves as
f_e(x) in
x' is a second randomly-paired parent (product interaction) and
tau a random threshold. Saturating kinds carry a log-uniform softness
scale s and contribute c*s*tanh(x/s) (slope c near 0, bounded
output). The returned univariate series is node 0 (nodes are exchangeable
by construction); the remaining nodes act as latent parents, i.e.
realistic exogenous-looking drivers. This produces genuine causal
temporal structure — autocorrelation at sampled lags, lead-lag effects,
nonlinear/regime-like dynamics — that component mixing cannot.
Diversity is shaped per series: edge kinds follow a random Dirichlet
mixture over edge_kinds (some series linear-dominated, others
nonlinearity-dominated), coefficient magnitudes decay geometrically with
lag (short-lag dominance), and, when ‘linear’ is in the pool, every node
gets a positive linear self lag-1 edge so the observed node carries its
own persistence.
Stability: the linear-gain part (linear/tanh/relu edges) is assembled
into VAR companion form and its coefficients are rescaled toward a
per-series spectral-radius target below stability_margin — drawn
near the margin with probability 0.22 (persistent, spectrally peaked
series) and well below it otherwise (noise-like series); bounded-output
edges cannot destabilize the core and keep their coefficients. During
rollout every state is additionally soft-clamped via
clamp * tanh(x / clamp) so nonlinear feedback cannot diverge. If a
trajectory still fails the finiteness/scale guard, the SCM is redrawn
(up to 5 times), then a guaranteed-stable linear AR(1) is used. The
counters _redraw_total / _fallback_total and the last accepted
SCM _last_scm are exposed for introspection on direct
generate_single_series calls.
Multivariate mode: with multivariate=True, generate(n_series)
samples a single SCM (with at least n_series variables — the lower
bound of n_vars_range is clamped up as needed) and one shared length,
rolls the system out once, and returns the first n_series nodes as
separate series in the long-format output (one unique_id per node,
following VARGenerator). Because the nodes share one causal graph,
they are genuinely cross-dependent at the sampled lags. The default
multivariate=False keeps the univariate behavior: n_series
independent SCMs, one observed node each.
Parameters:
TCMGenerator.generate_single_series
_MAX_REDRAWS redraws.
Parameters:
Returns:
TCMGenerator.generate
multivariate=False (default) this is the base behavior:
n_series independent SCMs, one observed node each. With
multivariate=True the n_series series are the first n_series
nodes of one shared SCM, sharing a single length (following
VARGenerator); generation is inherently joint, so n_jobs has no
effect in that mode.
Parameters:
Returns:
KernelSynthGenerator
Bases: BaseGenerator
Generate series by sampling from randomly composed Gaussian-process kernels.
This adapts the KernelSynth recipe introduced for pretraining the Chronos
forecasting models (Ansari et al. 2024,
“Chronos: Learning the Language of Time Series”,
https://arxiv.org/abs/2403.07815) and its Apache-2.0-licensed reference
implementation (https://github.com/amazon-science/chronos-forecasting/blob/main/scripts/kernel-synth.py).
For each series the
generator draws 1..max_kernels base kernels (with replacement) from a
fixed bank, folds them together with randomly chosen binary operators
(+ or *), and samples one path from the resulting GP prior on the
normalized grid x = linspace(0, 1, length). Kernel addition mixes
behaviors (e.g. trend + seasonality); kernel multiplication modulates them
(e.g. locally periodic, amplitude-varying seasonality). SynForecast makes
the bank configurable, expresses seasonal periods in time steps on a
normalized grid, and adds bounded retries, divergence guards, and optional
standardization.
Base kernels (r = |x_i - x_j|, all on the normalized grid):
- rbf:
exp(-r^2 / (2 l^2))— smooth, length-scalel - rational_quadratic:
(1 + r^2 / (2 a))^(-a)— scale mixture of RBFs, shapea - periodic (ExpSineSquared):
exp(-2 sin^2(pi r / p_norm))withp_norm = period / lengthsoperiodis expressed in time steps - linear (DotProduct):
s^2 + x_i x_j— trend / drift - white:
won the diagonal — independent noise - constant: a constant offset
|y| >= 1e8 draws are redrawn a
bounded number of times before falling back to Gaussian noise.
Parameters:
KernelSynthGenerator.generate_single_series
Returns:
MARGenerator
Bases: BaseGenerator
Generate GRATIS-style mixtures of autoregressive components.
The mixture autoregressive model is due to Wong and Li (2000, “On a
mixture autoregressive model”, Journal of the Royal Statistical Society
Series B 62(1), https://doi.org/10.1111/1467-9868.00222). This generator
adapts the MAR simulation used for diverse series by GRATIS (Kang,
Hyndman, and Li, 2020, “GRATIS: GeneRAting TIme Series with diverse and
controllable characteristics”, https://arxiv.org/abs/1903.02787). At each
step a component k is drawn from the mixture weights, then
y_t = c_k + sum_i phi[k, i] y[t-i] + sigma_k eps_t. The parameter
sampling, partial-autocorrelation reparameterization via Durbin-Levinson,
defaults, and stability guards are SynForecast’s own design rather than a
reproduction of the reference gratis R package.
Random mode samples one to max_components components for every series;
seasonal_period only affects random mode, where it enables a seasonal
AR factor for a random subset of components. Fixed mode supplies all four
of weights, ar_coefficients, intercepts, and noise_scales
and is used by feature targeting. Every fixed component must be
stationary, and the mixture must be second-order stationary (Wong and Li
2000). The numerical mixture check handles effective AR orders through 32,
using covariance contraction certificates and a NumPy dense eigenvalue
fallback. Solver failures are rejected. Validation results are cached.
Larger mixtures are accepted when all components are identical and stable,
or every component’s sum of absolute AR coefficients is below one.
Other large mixtures raise an error because stationarity could not be
verified; this conservative policy can reject valid mixtures. Trailing
zero coefficients do not count toward effective order. A fixed model
that fails the finite, bounded, non-constant output guards raises a
ValueError at generation time instead of silently substituting noise.
Moment handling is explicit: standardize=True (the default) maps every
accepted multi-observation draw to zero mean and unit standard deviation,
rather than retaining the MAR model’s component-implied level and scale.
Set standardize=False to preserve those raw simulated moments. This
output normalization is SynForecast’s own design and is not source-series
moment matching. Bulk :meth:generate calls use the native Rust batch
path; :meth:generate_single_series remains the Python reference path, so
their seeded RNG streams are not bit-for-bit equivalent.
MARGenerator.generate_single_series
length observations.
Random mode falls back to standard normal noise after _MAX_RETRIES
rejected draws. Fixed mode raises ValueError instead.
MARGenerator.tune_to_features
spectral_entropy, trend_strength,
seasonal_strength, and acf1, as defined by
:func:synforecast._features.compute_targeting_features. This implements
GRATIS feature-targeted generation (Kang et al. 2020,
https://arxiv.org/abs/1903.02787) as a seeded evolutionary search over
MAR parameters. The elitism, PACF-space Gaussian mutation, and minimal
feature set are SynForecast’s own design rather than a reproduction of
the GRATIS genetic algorithm. Candidate draw lengths are spaced evenly
across min_length..max_length so the result targets the configured
length range rather than one endpoint. The default budget evaluates at
most 15 * 30 * 3 series; the search stops early once the best L2
feature distance is at or below tolerance. Infeasible targets
return the best candidate after the fixed budget. Candidates whose
mixture is not second-order stationary, or whose simulation fails the
output guards, receive infinite fitness.
The returned generator’s tuning_diagnostics records the best observed
distance, whether tolerance was reached, generations run, and candidates
evaluated.
Each generation scores its valid candidates together in native Rust,
parallelized across candidates. Failed simulations affect only their
own candidate. n_jobs=-1 uses the default Rayon pool; a positive
value selects the worker count. Results are independent of worker count.
This native search uses a different seeded stream from the former
Python simulation loop. Lengths are limited to 1,000,000 observations.
Additional generator options are forwarded to candidate evaluation and
the returned generator: standardize, burn_in,
innovation_distribution, innovation_params, engine, alias,
id_col, time_col, target_col, and start_datetime.
Search-owned model parameters and pattern injection options are rejected.
MARGenerator.tuning_diagnostics
best_distance is the selected candidate’s observed training fitness,
not a guarantee about new draws. The returned dictionary is a copy.
