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 aTypeError: 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 aValueError, not a heap overrun. arm=names an arm (default: the family'sdefault_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=isserialoropenmp.- 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 itsin.andout.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.
--checkholds 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 FILEstarts from a checkpoint (format 2) that the C++mnist_trainwrote.
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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| simdpunk-0.1.0.dev1.tar.gz | 38.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| simdpunk-0.1.0.dev1-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | Python 3 | none | Linux glibc 2.28+ x86-64, Linux glibc 2.24+ 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.