Drift Variation Score
Composable Python primitives compute the per-modality variation of your drift. Plug them into any graph-diffusion pipeline and decide exactly where adaptation should happen.
driftflow is a pure-Python implementation of the Drift Variation Score — a training-free, plug-in sampler that adapts its timestep to the local Fisher-Rao curvature of the transition manifold. Wrap any graph-diffusion drift. Get sharper samples, faster.
# driftflow — adaptive SDE sampling for graph diffusion
from driftflow import (
CommonConfig, DVSSampler, GruMApproximation,
LinearSchedule, get_dataset_config, make_drift_function,
)
approx = GruMApproximation(num_nodes=9, feature_dim=4, seed=42)
drift = make_drift_function(approx)
common = CommonConfig()
dataset = get_dataset_config("GruM", "QM9")
sampler = DVSSampler(
drift_function = drift,
noise_schedule = LinearSchedule(sigma_min=0.01, sigma_max=0.5),
common_config = common,
dataset_config = dataset,
solver = "Heun",
seed = 42,
)
features_t, adjacency_t, info = sampler.sample(
initial_features = features_0,
initial_adjacency = adjacency_0,
terminal_time = 1.0,
)
print(f"steps={info['total_steps'][0]} time={info['final_time'][0]:.4f}") Overview
Graph-diffusion SDE solvers waste work in flat regions and miss curvature in steep ones. driftflow measures the local Drift Variation Score — a Fisher-Rao–style signal of how quickly the drift is turning — and resizes each timestep in a single power-law rule. The result is a sampler that takes fewer, better-placed steps without touching your model.
Signal · Adaptive timestep
live previewFeatures
A small, opinionated surface area built on six primitives. Each one earns its keep — no boilerplate, no half-features.
Composable Python primitives compute the per-modality variation of your drift. Plug them into any graph-diffusion pipeline and decide exactly where adaptation should happen.
First-order Euler-Maruyama for speed, second-order Heun for accuracy — both with the shared diffusion noise scale g(t) · √dt. Register your own via the SOLVERS extension point.
Common and dataset-specific settings are validated, named, and ready to import. CommonConfig + get_dataset_config() reproduce paper defaults without hand-tuning.
Adapt only where it pays off — e.g. [0, 0.2] ∪ [0.95, 1.0] for GDSS/QM9. Outside the range, the sampler falls back to dt_base for predictable cost.
No NumPy, no PyTorch. Every numerical primitive operates on nested list[float] containers so driftflow runs anywhere — educational tools, edge inference, lightweight servers.
A single seed makes the entire trajectory bit-for-bit reproducible, including the per-step history returned by sample(). Fail-fast errors surface before any work is done.
Algorithms
The paper presents three sampler variants. driftflow implements all of them behind one class — DVSSampler — and dispatches through a solver registry so you can add your own.
Compute the DVS, smooth it with EMA, scale the timestep by a power law, and refresh globally each step. The orchestration that every other algorithm composes on top of.
First-order SDE stepping with shared diffusion noise g(t) · √dt. Fast, predictable, and the natural baseline for any graph-diffusion drift.
Predictor-corrector second-order step. Same diffusion noise scale, with one extra drift evaluation per step in exchange for tighter error control.
Developer API
Four imports. One sampler. Hyperparameters pre-validated for GruM and GDSS. Everything else is just a dataclass.
from driftflow import (
CommonConfig, DVSSampler, GruMApproximation,
LinearSchedule, get_dataset_config, make_drift_function,
)
approx = GruMApproximation(num_nodes=9, feature_dim=4, seed=42)
drift = make_drift_function(approx)
common = CommonConfig()
dataset = get_dataset_config("GruM", "QM9")
sampler = DVSSampler(
drift_function = drift,
noise_schedule = LinearSchedule(sigma_min=0.01, sigma_max=0.5),
common_config = common,
dataset_config = dataset,
solver = "Heun",
seed = 42,
)
features_t, adjacency_t, info = sampler.sample(
initial_features = features_0,
initial_adjacency = adjacency_0,
terminal_time = 1.0,
)
print(f"steps={info['total_steps'][0]} time={info['final_time'][0]:.4f}")
See docs/API_REFERENCE.md for the full public surface.
Built with rigor
driftflow is treated like infrastructure — strict types, gated coverage, deterministic runs, and explicit fail-fast input validation.
Mathematical correctness, edge cases, determinism, input validation.
Coverage-gated in CI: a single missed branch breaks the build.
Pure-Python standard library — embeddable anywhere.
CommonConfig + every (GruM, GDSS) × dataset entry from Table 7.
Architecture
The adaptive controller (DVS, EMA, power-law scaling) is fully decoupled from the SDE solver and the denoiser network. Drop in any of the three without touching the others.
Any callable (X, A, t) → (f_X, f_A). Real networks or simplified stand-ins.
EMA-smoothed variation of the drift, scaled by a power-law rule into a timestep.
First- or second-order SDE step with shared diffusion noise g(t) · √dt.
Sample features, adjacency, and per-step history (steps, times, dt_k).
Sampler loop · per step
Install
driftflow is a pure-Python package with no compiled extensions. A normal pip install is everything you need — the smoke-test CLI is included for GruM and GDSS on QM9.
git clone https://github.com/sachncs/driftflow.git
cd driftflow
pip install -e . pip install -e ".[dev]" # Euler with GruM approximation
python examples/demo.py --model GruM --dataset QM9 --solver Euler --use-approximation
# Heun with GDSS approximation
python examples/demo.py --model GDSS --dataset QM9 --solver Heun --use-approximation Cite
If you use driftflow in academic work, please cite the original paper. The package is a pure-Python reproduction of Algorithms 1–3 from the reference below.
@article{driftflow2026,
title = {Information-Geometric Adaptive Sampling for Graph Diffusion},
journal = {arXiv preprint arXiv:2605.00250},
year = {2026}
} Get started
pip-install driftflow, point it at any graph-diffusion denoiser, and let the Drift Variation Score take it from there.