Exact sparse lattice neighbor search in pure Python — 12KB, zero compilation, zero dependencies.
Project description
voxel-graph
Exact sparse lattice neighbor search in pure Python — 12KB, zero compilation, zero dependencies.
This is not a replacement for scipy.spatial.cKDTree, faiss, or torch_cluster. Those libraries are faster, more general, and better maintained. They are also heavy, compiled, and often impossible to install in constrained environments.
voxel-graph exists for the edge cases where the heavy tools fail:
- You need exact integer offsets, not approximate Euclidean radius queries.
- You are running on a Raspberry Pi, embedded controller, or browser WASM where
scipywon't compile. - You are prototyping a paper or architecture and need working code in 30 seconds, not 30 minutes of dependency resolution.
- You are teaching spatial algorithms and need readable, benchmarked, self-contained code.
- You are building serverless functions with a 250MB deployment package limit.
If you have scipy and torch installed, use those. If you don't — or can't — use this.
What it does
Given a list of integer coordinates on a lattice (e.g., voxelized point clouds, discretized sensor grids, tick data) and a fixed set of offset vectors, find all unordered pairs (i, j) where coordinates[j] - coordinates[i] is exactly one of the allowed offsets.
- Time complexity:
O(n * |U| * bucket_size). For sparse data,bucket_size ~ 1, so effectivelyO(n). - Space complexity:
O(n)for the hash table. - Correctness: Verified against brute-force
O(n^2)ground truth on every release.
Install
pip install voxel-graph
Hard dependency: numpy only.
Optional: torch (for to_pyg), networkx (for to_networkx), scipy (for benchmark comparisons).
Quick start
from voxel_graph import build_edges
# Integer coordinates only
voxels = [(12, 45, 3), (12, 46, 3), (13, 45, 3), ...]
# 6-connectivity (face neighbors) or 26-connectivity (full cube)
edges = build_edges(voxels, connectivity=6)
# Returns: [(0, 1), (0, 2), ...] -- index pairs into your input list
Five use cases (honest assessment)
1. Academic reproducibility
You are: A researcher publishing a paper on percolation, lattice-based cryptography, or spatial graph theory. Reviewers demand reproducible code. You need a reference implementation that is small enough to include as supplementary material and clear enough to verify by inspection.
Why not scipy: Your algorithm depends on exact lattice offsets, not Euclidean distance. cKDTree query + post-filter is conceptually messy in a methods section. You want code that maps 1:1 to your paper's pseudocode.
Why this: 200 lines of pure Python. No black boxes. The spatial hash logic is exposed and documented. Reviewers can read it in one sitting.
from voxel_graph import build_edges
# Reproduce Figure 3 from your paper
voxels = load_simulation_data()
edges = build_edges(voxels, offsets=[(1,0,0), (-1,0,0), (0,1,0), (0,-1,0)])
G = nx.Graph()
G.add_edges_from(edges)
# ... compute percolation threshold
2. ML prototyping before CUDA commitment
You are: A machine learning engineer experimenting with a new 3D GNN architecture. You want to know if graph connectivity pattern matters before spending a day writing CUDA kernels and fighting torch_sparse compilation.
Why not torch_cluster: It requires matching PyTorch, CUDA, and OS versions. On a fresh machine, pip install torch-scatter can take 45 minutes and still fail. You want to test your idea in a Jupyter notebook now.
Why this: pip install voxel-graph takes 3 seconds. build_edges() returns a Python list you can convert to torch.tensor manually. Your architecture experiment runs in minutes, not hours.
from voxel_graph import build_edges, to_pyg
voxels = voxelize_lidar(points, voxel_size=0.1)
edges = build_edges(voxels, connectivity=26)
edge_index = to_pyg(edges) # torch.tensor of shape [2, num_edges]
# Feed to your experimental GNN
out = model(x, edge_index)
Limitation: This is for prototyping only. If your architecture works, you will rewrite the neighbor search in CUDA. This package buys you time, not performance.
3. Embedded and edge devices
You are: An IoT developer with a Raspberry Pi, microcontroller, or industrial PLC running Python (or MicroPython). You need to find neighbors in a sensor grid. You cannot install scipy (150MB, requires compilation) or torch (impossible on most embedded targets).
Why not scipy: It does not compile on ARM without a full toolchain. It exceeds the storage budget of most microcontrollers. It is overkill for finding adjacent cells in a 50x50 temperature sensor grid.
Why this: Pure Python. Works on any Python interpreter with numpy. 12KB installed size. No C compiler, no wheel hunting, no version matching.
from voxel_graph import build_edges
# Temperature sensor grid: (x, y) integer positions
sensors = [(i, j) for i in range(50) for j in range(50) if sensor_active(i, j)]
# Find adjacent sensors for heat diffusion model
edges = build_edges(sensors, connectivity=4)
4. Browser and serverless Python
You are: Building a web-based data tool with Pyodide (Python in WebAssembly) or an AWS Lambda function with a 250MB deployment package limit. You need spatial neighbor search inside the browser or in a cold-started function.
Why not scipy: Pyodide can load scipy, but it adds 30MB to the initial download. AWS Lambda layers with scipy are 150MB, leaving no room for your actual application. Cold start latency kills user experience.
Why this: 12KB. Downloads in milliseconds. No C extensions to load. Works in Pyodide's restricted WASM environment where ctypes and compiled extensions are limited.
from voxel_graph import build_edges
# Running in Pyodide inside the browser
voxels = js.getVoxelData() # From JavaScript
edges = build_edges(voxels, connectivity=6)
# Render graph with D3.js
5. Teaching and interview preparation
You are: A CS instructor teaching spatial data structures, or a student preparing for quant/ML interviews where you must implement fast neighbor search from scratch.
Why not leetcode: LeetCode solutions are fragments. They don't show benchmarking, edge cases, packaging, or real-world integration. You need a complete, runnable project.
Why this: The entire algorithm is ~200 lines. It includes a spatial hash, bit-packing for exact matching, and a verified A/B benchmark against brute force. You can read it in one sitting, modify it, and explain it in an interview.
# Interview question: "Implement fast 3D grid neighbor search"
from voxel_graph.core import _VoxelGraphEngine
# The entire algorithm is exposed. Read the source, understand the hash,
# then explain why it's O(n) for sparse data and O(n^2) in the worst case.
Benchmarks
Exact 26-connectivity on random 3D integer lattices. Verified against brute-force ground truth.
| Voxels | Brute O(n^2) (s) | voxel-graph (s) | Speedup | Edges |
|---|---|---|---|---|
| 1,000 | 0.24 | 0.04 | 6.7x | 0 |
| 5,000 | 6.19 | 0.17 | 34.3x | 1 |
| 10,000 | 23.80 | 0.36 | 68.9x | 6 |
| 50,000 | ~2,500* | 1.90 | ~1,300x | 138 |
*Estimated from quadratic scaling.
A/B test methodology:
- Generate
nrandom integer coordinates in a1000^3lattice. - Offsets: 26-connectivity.
- Ground truth: brute-force
O(n^2)double loop. - Assert:
sorted(brute_edges) == sorted(voxel_graph_edges). - Measure: wall-clock time, single run.
When this benchmark matters: When you are comparing against brute force because you have no other option. When you have scipy installed, compare against cKDTree instead — it will win on float data, lose on exact integer offsets.
API
build_edges(coordinates, connectivity=None, offsets=None)
coordinates: list of(x, y)or(x, y, z)integer tuples.connectivity:4or8for 2D;6or26for 3D. Mutually exclusive withoffsets.offsets: custom list of(dx, dy)or(dx, dy, dz)vectors. Overridesconnectivity.- Returns: list of
(i, j)index pairs withj > i.
to_pyg(edges)
- Converts edge list to
torch.tensorof shape[2, num_edges]. - Requires
torchinstalled.
to_networkx(coordinates, edges, node_attrs=None)
- Returns a
networkx.Graphwith node attributescoordand any custom attrs.
build_tick_graph(trades, price_radius=2, time_radius=5)
trades: list of(price_tick, time_ms)integer tuples.- Returns edge list for market microstructure analysis.
Requirements
- Python 3.8+
numpy(only hard dependency)
Optional:
torchforto_pygnetworkxforto_networkxscipyfor benchmark comparisons
When not to use this
| Situation | Use instead |
|---|---|
| Float coordinates, approximate neighbors | scipy.spatial.cKDTree, sklearn.neighbors |
| High-dimensional data (d > 3) | faiss, annoy, hnswlib |
| GPU-accelerated batch processing | torch_cluster.radius_graph, MinkowskiEngine |
| Dense grid where every cell exists | networkx.grid_graph, scipy.ndimage |
| Production at scale | Rewrite in C++/CUDA |
License
MIT
Contributing
Pull requests welcome. Please add tests and ensure pytest passes. If you have a new use case for constrained environments, open an issue with a description of your target platform and its limitations (e.g., "MicroPython on ESP32 with 512KB RAM").
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file voxel_graph-0.1.0.tar.gz.
File metadata
- Download URL: voxel_graph-0.1.0.tar.gz
- Upload date:
- Size: 10.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a623889635f2bc1a149395c32d105782ce27f6ccb964beb1c5e2126c4288597e
|
|
| MD5 |
220248050a5ca9f1309004e36333e087
|
|
| BLAKE2b-256 |
780b2280c102a34f317d5302fe856041279be09a947a0386038ca5e8426c3b90
|
File details
Details for the file voxel_graph-0.1.0-py3-none-any.whl.
File metadata
- Download URL: voxel_graph-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd405b124623741db92c5c1a9499f621c905b916912a2034c9bab5ad1a9c0560
|
|
| MD5 |
78297a095572ff0a082dfe80d3d5b6ec
|
|
| BLAKE2b-256 |
3cd29e7019c086356d0fb4202e0a2c4d307ad9df695d4d4ba90302eb8694ad2b
|