Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

simdpunk from Python — a minimal ctypes wrapper

One compiled C ABI and a thin Python layer: numpy is the only runtime dependency.

pip install simdpunk                               # a manylinux wheel: x86_64, and aarch64 where the release has one
python -m simdpunk.mnist --data DIR                # the MNIST example; DIR holds the four MNIST files (see below)
file what it is
simdpunk_c.cpp a C ABI over the registry: the registry as text, each operand's extent, one predicate (arm_accepts_arrangement), and one call — every arm is void fn(const call_desc&, void* const*), so one entry point reaches every row of the registry
CMakeLists.txt builds it as _simdpunk.so against the library's own INTERFACE target; OpenMP for the openmp executor, no -march (the ISA arms choose at run time)
simdpunk/__init__.py the Python side: call, describe, accepts, arm_of, REGISTRY
simdpunk/mnist.py the MNIST example on it — mnist_train --path plan's step, node by node
tests/ the smoke tests every wheel is tested with
ci/build-wheel.sh the CI's one step, inside a manylinux image: sdist, wheel from it, auditwheel repair, tests on the installed wheel
../pyproject.toml the package: scikit-build-core drives the CMake project; the wheel is py3-none-<platform> (no Python.h, so one build serves every Python 3); [tool.cibuildwheel] is the GitHub mirror's

From a checkout: pip install . builds and installs it; python3 build.py builds simdpunk/_simdpunk.so in place (the same CMake project) for PYTHONPATH=python. Either needs CMake ≥ 3.20 and a C++23 compiler (built and tested here with g++ 15.2).

The API

import numpy as np, simdpunk as sp

sp.describe("gemm.fp32_x_fp32.nt")     # operands by slot, shape parameters, arms (* = default)
C = np.empty((M, N), np.float32)
sp.call("gemm.fp32_x_fp32.nt", {"in.a": A, "in.b": B, "out.c": C}, m=M, n=N, k=K)
  • Operands by slot name, shape by parameter name — the family's own vocabulary (sp.describe). The shape is a prefix of the declared list and the rest derive, as in a direct C++ call. A parameter skipped before the last one given is a TypeError: a spelled 0 is a zero stride, not "derive it".
  • Checked before any kernel runs: every operand present, fp32/u8/int32 operands of the right dtype, C-contiguous, and every dense operand at least the extent the family declares at this shape (extents.h). A short buffer is a ValueError, not a heap overrun.
  • arm= names an arm (default: the family's default_arm). arrangement={"in.codes": ("rowmajor", 0)} states an arranged operand's layout — the u8 GEMM refuses an unstated one. recipe= is the emission (absmean, absmax_kbit); exec= is serial or openmp.
  • A Python number passed for an input slot is a one-element array of the slot's format. An operand updated in place (Adam's m, v, w) is the same array under its in. and out. slots.
  • A precondition only the arm checks is still the arm's FATAL, and it ends the process, as it would in C++.

What mnist.py does

Each sp.call is one node of the training step (trace_step) or the evaluation (trace_eval) of the library's C++ MNIST example, on the arm that node runs: 784 → hidden → 10 (the head padded to 64 columns), ternary weights emitted from fp32 masters at the head of every step, layer 1 an exact uint8 × ternary GEMM on the pixel bytes, layer 2 an fp32 GEMM on fake-quantised int8 rows, softmax cross-entropy, Adam. The initial weights and the shuffle come from numpy, not std::mt19937, and evaluation reads the rowmajor codes where the example's eval plan reads the pack, so a run follows that example's steps but not its bits.

DIR holds the four uncompressed MNIST files: train-images-idx3-ubyte, train-labels-idx1-ubyte, t10k-images-idx3-ubyte and t10k-labels-idx1-ubyte. Nothing is downloaded for you.

  • --check holds every GEMM of the first step to numpy float64 on the same inputs (the run fails beyond 1e-5 of the largest value); the wheel's smoke tests run it.
  • Accuracy: the defaults (3 epochs, 256 hidden units) reach about 97.5 % test accuracy on MNIST, measured with this release's scalar arms.
  • --model FILE starts from a checkpoint (format 2) that the C++ mnist_train wrote.

What it does not wrap

The l1 planner — graph, lowering, validate, verify, the arena and staged_plan. Here Python calls the arms one at a time, the way the example's direct path does, and a plan's checks are not made. Also not wrapped: the program tier, the state::qparam facets, the pack builders (host code, not families) and the fixture reader. Each would be one more small function in simdpunk_c.cpp.

License

AGPL-3.0-or-later — the GNU Affero General Public License, version 3 or any later version; the sdist and every wheel carry the text (LICENSE), and the metadata says so (License-Expression, PEP 639).

Linux only: the wheels are glibc (musllinux is skipped), and macOS and Windows are not built. The library's ISA arms are GCC/Clang target attributes, and the openmp executor wants libgomp.

Metadata

Release files for simdpunk 0.1.0.dev1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for simdpunk 0.1.0.dev1
File Size Uploaded Provenance
simdpunk-0.1.0.dev1.tar.gz 38.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for simdpunk 0.1.0.dev1
File Interpreter ABI Platform
simdpunk-0.1.0.dev1-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 Details

Total release size: 213.2 kB

Release files / simdpunk-0.1.0.dev1.tar.gz

Download URL simdpunk-0.1.0.dev1.tar.gz
Size 38.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b1bbfcbca11fd865327e6ef05317f6e543b51b8d2935257ea5e415cd7e11253f
BLAKE2b-256 checksum
How to use checksums
c447962cd7238cc4727e3d99ea072d781a6dd91b726e477e2a67b6a2f5076c10
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / simdpunk-0.1.0.dev1-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL simdpunk-0.1.0.dev1-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Size 174.6 kB
Tags Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
07b1e6f1497c7535e8587f20e1b3591bb9dfec1a0dbcf922bd547520193bad3d
BLAKE2b-256 checksum
How to use checksums
574092ad02ffb0afaad3a1e0d9144da0ffb684f524af76ed45d41e93776fc22c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Security for simdpunk 0.1.0.dev1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page