Skip to main content

Geometric temporal embeddings for machine learning — Archimedean spiral positional encodings for LSTMs, Transformers, and any time series model

Project description

spiral-time

Geometric temporal embeddings for machine learning.

Spiral time replaces scalar time features with a geometrically structured embedding derived from an Archimedean spiral. Every timestep is represented as a point in 2D spiral space, decomposing naturally into:

  • Angular component [cos(θ), sin(θ)] — phase within the recurring cycle (seasonality)
  • Radial component r = z-score(θ) — cumulative progression along the trend

In a 10-experiment ablation on US monthly retail sales, multi-period spiral time embeddings achieved 1.69% MAPE — outperforming scalar time (9.76%) by 83% and hand-engineered sinusoidal features (4.62%) by 63%.


Installation

# Core (NumPy only)
pip install spiral-time

# With PyTorch support
pip install spiral-time[torch]

# Full (torch + pandas + sklearn + matplotlib)
pip install spiral-time[full]

Quick Start

NumPy — works with any model

import numpy as np
from spiral_time import spiral_embedding

t   = np.arange(168)                          # 168 monthly timesteps
emb = spiral_embedding(t, periods=[3, 6, 12]) # quarterly + semi-annual + annual
# emb.shape → (168, 9)

# Drop into any sklearn / XGBoost / LightGBM pipeline
from sklearn.ensemble import GradientBoostingRegressor
X = np.hstack([values.reshape(-1, 1), emb])
model = GradientBoostingRegressor().fit(X[:-12], y[:-12])

LSTM / RNN

from spiral_time import spiral_embedding

# Replace scalar time feature with spiral embedding
t_features = spiral_embedding(t, periods=[3, 6, 12])   # (n, 9)
# Concatenate with value sequence as LSTM input
x = np.concatenate([values[:, None], t_features], axis=1)

Transformer — drop-in positional encoding

import torch
from spiral_time import SpiralTimeEncoding

# Replace this:
# self.pos_enc = PositionalEncoding(d_model=128)

# With this:
self.pos_enc = SpiralTimeEncoding(
    d_model=128,
    periods=[24, 168, 720],   # daily, weekly, monthly (hourly data)
)

# Forward call unchanged:
x = self.pos_enc(x)   # (batch, seq_len, 128)

Auto-detect periods from data

from spiral_time.embedding import detect_periods, spiral_embedding

periods = detect_periods(y, n_periods=3)
print(periods)   # e.g. [365.2, 30.4, 7.0]

emb = spiral_embedding(t, periods=periods)

Stateful embedding (no data leakage)

from spiral_time import SpiralEmbedding

emb = SpiralEmbedding(periods=[3, 6, 12])
X_train = emb.fit_transform(t_train)   # fits normalisation on train set
X_test  = emb.transform(t_test)        # applies train stats to test set

The Embedding

For a set of periods {T₁, T₂, ..., T_K}:

MTE(t) = [cos(θ₁), sin(θ₁), r₁,   cos(θ₂), sin(θ₂), r₂,   ...,   cos(θ_K), sin(θ_K), r_K]

where:
  θ_k = 2π·t / T_k
  r_k = z-score(θ_k)   ← independently normalised per period

Output dimension: 3K (with radial) or 2K (phase only).

The angular components [cos(θ), sin(θ)] are identical to the sinusoidal positional encodings used in Transformer architectures. The radial component r_k adds the trend axis — making explicit how many cycles have elapsed at each timescale.


Transformer Classes

from spiral_time import (
    SpiralTimeEncoding,          # fixed multi-period spiral PE
    MultiPeriodSpiralAttention,  # learned period weighting
    SpiralTransformerForecaster, # full reference implementation
)

SpiralTimeEncoding

Drop-in for PositionalEncoding. Pre-computes spiral embeddings and projects to d_model via a learned linear layer.

MultiPeriodSpiralAttention

Learns a softmax-normalised weight over a set of candidate periods. After training, inspect period_weights to discover which timescales the model relied on:

mpa = MultiPeriodSpiralAttention(
    d_model=128,
    candidate_periods=[3, 7, 14, 30, 60, 90, 180, 365],
)
# ... train model ...
weights = torch.softmax(mpa.period_weights, dim=0)
for T, w in sorted(zip(candidate_periods, weights.tolist()), key=lambda x: -x[1]):
    print(f"T={T:>4}  weight={w:.3f}")

SpiralTransformerForecaster

Minimal end-to-end reference implementation. Use this as a template for integrating spiral PE into PatchTST, iTransformer, Autoformer, or any existing architecture.


Benchmark Results

LSTM ablation — US Monthly Retail Sales (168 months)

Encoding MAPE
Scalar time 9.76%
Engineered [cos, sin] 4.62%
Spiral Archimedean (z-score r) 3.19%
Multi-period Spiral ×3 1.69%

Transformer benchmark — ETTh1 / ETTm1 (OT target)

(Run python benchmarks/ett_benchmark.py to reproduce)

Dataset PE pred=24 MAE pred=48 MAE pred=96 MAE
ETTh1 No PE
ETTh1 Sinusoidal
ETTh1 Spiral Time
ETTm1 No PE
ETTm1 Sinusoidal
ETTm1 Spiral Time

Fill in after running the benchmark — results are saved to benchmarks/ett_results.json.


When to Use Spiral Time

Spiral time is most effective when your data has:

  • Known or estimable dominant periods (daily, weekly, annual, etc.)
  • A long-run trend layered on those cycles (growth, decline, drift)
  • Multiple interacting periodicities (the multi-period extension gives the largest gain)

It is a direct drop-in for:

  • Scalar time index features (t = 0, 1, 2, ...)
  • Hand-engineered date features (month, day_of_week, hour)
  • Standard sinusoidal positional encodings in Transformers

Applications

Domain Periods to use Expected benefit
Energy demand (hourly) [24, 168, 8760] Daily + weekly + annual cycles
Retail sales (monthly) [3, 6, 12] Quarterly + semi-annual + annual
Financial returns (daily) [5, 21, 63, 252] Weekly + monthly + quarterly + annual
Drug dosing (hourly) [24, 168] Circadian + weekly schedule
EEG / neural signals [band-specific] Neural oscillation phase encoding
Weather (daily) [365, 1461] Annual + 4-year leap cycle

Theoretical Background

Spiral time is grounded in differential geometry. Each timestep maps to a point on an Archimedean spiral in 2D space:

tₓ(θ) = aθ · cos(θ)
tᵧ(θ) = aθ · sin(θ)

This framework:

  • Generalises Transformer sinusoidal PE by adding an explicit trend coordinate
  • Connects to Hawking–Hartle imaginary time and Kaluza–Klein extra dimensions
  • Provides a geometric basis for phase resonance in attention mechanisms

See the full paper: blog_post.md


Citation

@article{spiraltime2026,
  title   = {Spiral Time: A Geometric Reframing of Temporal Structure and Its Applications in Machine Learning},
  author  = {[Your Name]},
  year    = {2026},
  url     = {https://github.com/your-username/spiral-time}
}

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spiral_time-0.1.0.tar.gz (13.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spiral_time-0.1.0-py3-none-any.whl (10.3 kB view details)

Uploaded Python 3

File details

Details for the file spiral_time-0.1.0.tar.gz.

File metadata

  • Download URL: spiral_time-0.1.0.tar.gz
  • Upload date:
  • Size: 13.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for spiral_time-0.1.0.tar.gz
Algorithm Hash digest
SHA256 437b57aed606c8c406c58d2cc50f1124762bb6b3c377647b119616909a348dae
MD5 07a93d6fcb49a85bdafa7cf7550f8a96
BLAKE2b-256 523a1cea33f47757c2e7f91b8dd1dbd73ec11d3e2cde0403d88ee9381aeb6313

See more details on using hashes here.

File details

Details for the file spiral_time-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: spiral_time-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for spiral_time-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f55a3e8d751838bef9d35e675d9a0f75a5dd495dd2d73ce20870ba7c302c1b41
MD5 08ebd3c3cf419f75a331920ee6738031
BLAKE2b-256 f55a1280980825adc5e0bc69d8358724a76b74a918b1f7d48f950e79078dee3e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page