cython-blis
Fast BLAS-style matrix multiplication for Python, bundled as a self-contained C extension with no system BLAS dependency.
Repository Health
Technical Analysis
Blis wraps the BLIS linear algebra framework in a self-contained Cython extension, giving Python and NumPy code fast matrix multiplication, matrix-vector products, and vector operations without requiring a system-installed BLAS library such as OpenBLAS or MKL. It ships prebuilt wheels for x86_64, ARM64, and Windows, and can be built from source for less common CPU architectures using the BLIS_ARCH environment variable and a jsonl-driven build pipeline.
Originally built by Explosion AI to remove the BLAS/LAPACK dependency headache from spaCy and Thinc, blis exposes low-level routines (gemm, gemv, ger, axpy, dotv) through a thin Cython layer plus a NumPy-friendly blis.py API and an einsum-style dispatcher, and it is thread-safe for concurrent use with immutable data, including free-threaded (nogil) CPython builds.
What You Get
- Prebuilt wheels for x86_64, ARM64, and Windows — no separate BLAS/LAPACK installation required
- Core BLAS-like routines (gemm, gemv, ger, axpy, dotv) exposed through a thin Cython API
- A NumPy-friendly
blis.pylayer plus an einsum-style operation dispatcher - Thread-safe execution with immutable inputs, including free-threaded (nogil) Python builds
- Source builds for custom CPU architectures via the BLIS_ARCH environment variable
Common Use Cases
- Dependency-free deployment - shipping a Python package that needs fast matrix multiplication without asking users to install a system BLAS
- NLP pipeline acceleration - powering the dense-layer math inside spaCy and Thinc’s neural network components
- Custom numerical extensions - calling gemm/gemv/ger directly from Cython or C code that already manages its own memory buffers
- Portable ML tooling - building wheels that run consistently across x86_64, ARM64, and Windows without per-platform BLAS setup
Under The Hood
Architecture blis/cy.pyx declares thin cdef wrappers around the vendored BLIS C routines (BLIS kernels live under blis/_src, generated per OS/architecture from jsonl build manifests), while blis/py.pyx layers an ergonomic NumPy-facing API (axpy, ger, gemm, gemv, dotv, and an einsum-style dispatcher) on top, using Cython fused types to dispatch float/double variants at compile time and releasing the GIL around the actual BLIS calls. The package is effectively three layers — raw BLIS C kernels, typed Cython bindings, and a friendly Python API — with no application-level abstractions since it’s a numerical primitives library; the fused-type dispatch in py.pyx is the main coupling point that has to track the C-level declarations in cy.pxd.
Tech Stack The bulk of the codebase (99% of bytes) is C implementing the vendored/generated BLIS kernels, glued to Python via Cython (cythonize, cython>=3.1,<4.0) and built with a custom setuptools build_ext that shells out to a per-architecture make/jsonl pipeline instead of a standard compile step. It targets NumPy>=2.0,<3.0 as the array runtime, is packaged as native wheels across platforms via cibuildwheel with delocate/auditwheel repair steps, and is tested with pytest plus hypothesis property-based testing; CI runs on GitHub Actions (tests, cibuildwheel, sanitizers, jsonl generation, PyPI publish), with legacy Travis/AppVeyor/Azure configs still present from earlier CI generations.
Code Quality The test suite is small but targeted — pytest and hypothesis-driven property tests validate gemm/dotv results against NumPy reference output via assert_allclose, including a dedicated thread-safety test that runs gemm concurrently across threads to back the free-threading claims. Error handling is explicit where it matters (ValueError on shape mismatches, TypeError on unhandled fused-type combinations), naming follows terse BLAS convention (gemm, gemv, ger) rather than descriptive names, and no linter or static type-checker configuration is present in the repo; a separate sanitizers CI workflow suggests additional memory-safety checks run outside the visible test suite.
API Design The public API is low-friction for anyone familiar with NumPy: plain arrays in, plain arrays out, with sensible defaults (out=None auto-allocates, alpha/beta scaling follows classic BLAS convention), so blis.py.gemm can often substitute for numpy.dot with little adjustment. The einsum-style dispatcher (blis.py.einsum(‘ab,bc->ac’, A, B)) further lowers the barrier by mapping familiar einsum notation onto the right underlying routine. Documentation is comparatively weak, though — the README is almost entirely about build/packaging/cross-compilation concerns rather than usage examples or docstrings for the exposed functions, so the actual computational API has to be learned from source rather than docs.