Metadata-Version: 2.4
Name: tempest-rw
Version: 0.0.4
Summary: GPU-accelerated temporal random walks on streaming graphs
Author-email: Ashfaq Salehin <ashfaq.salehin1701@gmail.com>
Maintainer-email: Ashfaq Salehin <ashfaq.salehin1701@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/ashfaq1701/tempest
Project-URL: Repository, https://github.com/ashfaq1701/tempest
Project-URL: Issues, https://github.com/ashfaq1701/tempest/issues
Keywords: temporal-graph,random-walk,gpu,cuda,streaming-graph
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: C++
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.21
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"

# Tempest

[![CPU Tests](https://github.com/ashfaq1701/tempest/actions/workflows/cpu-tests.yml/badge.svg?branch=master)](https://github.com/ashfaq1701/tempest/actions/workflows/cpu-tests.yml)
[![PyPI Latest Release](https://img.shields.io/pypi/v/tempest-rw.svg)](https://pypi.org/project/tempest-rw/)
[![PyPI Downloads](https://img.shields.io/pypi/dm/tempest-rw.svg)](https://pypi.org/project/tempest-rw/)

GPU-accelerated library for streaming temporal random walks. Walks follow a
temporal graph's edges forward or backward in time under configurable bias
(uniform, linear, exponential, reservoir-exponential, or temporal Node2Vec),
with a sliding window that evicts old edges as new ones arrive. Edges may
optionally carry a float feature vector that stays in sync with the edge
store and is returned per hop alongside walks.

## Documentation

- **[C++ API (Doxygen) →](https://htmlpreview.github.io/?https://github.com/ashfaq1701/tempest/blob/master/docs/html/index.html)**
- **[Python API (pdoc) →](docs/tempest/index.md)**

## Installation

```bash
pip install tempest-rw
```

Or from a local checkout:

```bash
pip install .
```

Requires CMake ≥ 3.24, a C++17 compiler, and pybind11. A CUDA toolkit is
optional; without it the package builds CPU-only.

To disable the CUDA backend at build time:

```bash
TEMPEST_DISABLE_CUDA=1 pip install .
```

## Quick Start

One import, one class, one object:

```python
from tempest import Tempest
import numpy as np

t = Tempest(is_directed=True, use_gpu=True)

t.add_edges(
    np.array([0, 1, 2], dtype=np.int32),
    np.array([1, 2, 3], dtype=np.int32),
    np.array([100, 200, 300], dtype=np.int64),
)

walks = t.get_walks(
    max_walk_len=10,
    num_walks_per_node=5,
    walk_bias="ReservoirExponential",
    direction="Forward",
    seed=42,
)
print(walks["nodes"].shape)           # (num_walks, max_walk_len)
print(walks["timestamps"].shape)      # (num_walks, max_walk_len)
print(walks["walk_lens"].shape)       # (num_walks,)
print(walks["edge_features"])         # None when no features were attached
```

Unused positions in `nodes` and `timestamps` are padded with `-1`. When edge
features are attached at `add_edges` time they come back resolved per hop as
`walks["edge_features"]` — see [Edge Features (Optional)](#edge-features-optional)
below.

Other entry points:

- `t.get_walks_for_nodes(node_ids, ...)` — one walk per entry in `node_ids`.
- `t.get_walks_for_last_batch(...)` — walks starting only from the nodes
  touched by the most recent `add_edges` call.

## Walk Bias Types

| Bias                    | Description                                                       |
| ----------------------- | ----------------------------------------------------------------- |
| `Uniform`               | Equal probability across valid timestamp groups.                  |
| `Linear`                | Triangular probability, linear in group index.                    |
| `ExponentialIndex`      | Exponential probability via inverse CDF over group index.         |
| `ReservoirExponential`  | Temporal exponential bias via Efraimidis-Spirakis reservoir sampling (zero precomputed weights). |
| `TemporalNode2Vec`      | Structural (p, q) bias combined with temporal reservoir draw; pass `enable_node2vec=True` + `node2vec_p` + `node2vec_q` at construction time. |

## Edge Features (Optional)

Every edge can carry a fixed-size float feature vector. Features are stored
CPU-side regardless of `use_gpu` and are **never** read during walk generation
— they exist purely as a lookup table. Tempest keeps them in sync with the
edge arrays across ingest-time sort/merge and sliding-window eviction, and
`get_walks` / `get_walks_for_nodes` / `get_walks_for_last_batch` return them
already resolved for every hop of every walk:

```python
t = Tempest(is_directed=True, use_gpu=True)

sources    = np.array([0, 1, 2], dtype=np.int32)
targets    = np.array([1, 2, 3], dtype=np.int32)
timestamps = np.array([100, 200, 300], dtype=np.int64)
features   = np.array([[1.0, 2.0],
                       [3.0, 4.0],
                       [5.0, 6.0]], dtype=np.float32)  # [num_edges, feature_dim]

t.add_edges(sources, targets, timestamps, features)
assert t.feature_dim == 2

walks = t.get_walks(max_walk_len=5, num_walks_per_node=10, walk_bias="Uniform")
walks["edge_features"]         # float32, shape (num_walks, max_walk_len - 1, 2)
# Each row [w, i] is the feature vector of the edge traversed from
# nodes[w, i] to nodes[w, i + 1]. Padding slots past the walk's length are
# zero rows. When no features were attached, walks["edge_features"] is None.
```

Rules:

- The first `add_edges` call pins `feature_dim`. Every subsequent call must
  match: all-with-features or all-without, same `feature_dim`. Switching modes
  mid-stream raises.
- `t.clear()` wipes features and resets the schema, so the next `add_edges`
  may pick a new `feature_dim`.
- Features accept either a 2D `[num_edges, feature_dim]` float32 array or a
  flat 1D array of length `num_edges * feature_dim`.

## Streaming API

```python
t = Tempest(is_directed=True, max_time_capacity=3600)

for batch in stream_of_batches():
    t.add_edges(batch.sources, batch.targets, batch.timestamps)
    fresh_walks = t.get_walks_for_last_batch(max_walk_len=10, num_walks_per_node=1)
```

`max_time_capacity` defines the sliding-window length in timestamp units. After
every batch, edges older than `latest_timestamp - max_time_capacity` are
evicted and the temporal index is rebuilt. `get_walks_for_last_batch` starts
walks only from the nodes touched by the most recent `add_edges` call —
sources only for directed forward walks, targets only for directed backward
walks, and the union of both for undirected graphs.

## Building from Source

```bash
mkdir build && cd build
cmake .. -DTEMPEST_BUILD_TESTS=ON
cmake --build . -j
ctest --output-on-failure
```

Key CMake options:

- `-DTEMPEST_ENABLE_CUDA=ON|OFF` — build with/without the GPU backend.
- `-DTEMPEST_BUILD_PYTHON=ON|OFF` — build the pybind11 module.
- `-DTEMPEST_BUILD_TESTS=ON|OFF`  — build the C++ test suite.
- `-DTEMPEST_BUILD_BENCH=ON|OFF`  — build the CSV-emitting benchmarks.
