Skip to main content

A torch.linalg.solve for tinygrad: batched, differentiable, pivoted linear solve as a single custom kernel

Project description

tinysolve

A torch.linalg.solve for tinygrad: solve A @ x = B for x, batched, differentiable, and JIT-friendly — as a single custom kernel.

from tinygrad import Tensor
from tinysolve import solve

A = Tensor.randn(2000, 16, 16, dtype="float64") + 16 * Tensor.eye(16, dtype="float64")
B = Tensor.randn(2000, 16, 4, dtype="float64")

x = solve(A, B)  # (2000, 16, 4)

# differentiable (higher-order too)
gA, gB = solve(A, B).sum().gradient(A, B)

Install

uv add tinysolve  # or: pip install tinysolve

API

solve(A, B) follows torch.linalg.solve shape semantics:

  • A: (*, n, n) — a (batch of) square matrices; batch dims broadcast against B's.
  • B: (*, n, k) for a matrix RHS → result (*, n, k), or a batch of vectors (B.ndim == 1, or B.ndim == A.ndim - 1 with B.shape == A.shape[:-1]) → result (*, n).

Partial pivoting is used, so matrices like [[0, 1], [1, 0]] are handled robustly (unpivoted LU would produce nan). Gradients use the implicit-function identity for a linear solve (same as PyTorch), and the backward reuses the same differentiable solve, so higher-order gradients work.

Contract difference vs torch: this kernel is lazy/JIT-compatible, so it cannot raise on a singular A without forcing a device sync. A singular input surfaces as non-finite (inf/nan) output instead of a LinAlgError.

Why a custom kernel

Batched small-matrix solves are memory-bound (arithmetic intensity ≈ n/12 FLOP/byte, far below the fp64 roofline ridge) — the game is how few times each matrix streams through HBM. A high-level tensor program can't win here: every op round-trips global memory, and the sequential elimination dependency crosses kernel boundaries (~64 kernels per solve for a tensor-level QR).

tinysolve instead uses tinygrad's custom_kernel (UOp) API with the same execution model cuSOLVER uses for small batches: one thread per matrix, the whole n×n system held in registers, and a fully-unrolled partial-pivoted Gaussian elimination + back-substitution run entirely in-register — one kernel, ~one HBM pass per matrix.

Performance (H100, fp64, JIT, vs torch.linalg.solve, k=1)

speedup vs torch M=500 M=2000 M=20000
n=4 4.40× 4.46× 4.62×
n=8 3.64× 3.60× 2.81×
n=16 0.74× 0.73× 0.89×

3–4× faster than torch for n ≤ 8, ~parity at n = 16. Beyond n ≈ 16 the per-thread working set (n·(n+k) doubles) exceeds the register file and spills; cuSOLVER's sub-warp-per-matrix cooperative kernels win there.

Development

uv run pytest                     # tests (property-based, vs torch as oracle)
uv run pytest tests/benchmark.py  # benchmarks
uv run ruff check . && uv run ty check

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tinysolve-0.1.0.tar.gz (5.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tinysolve-0.1.0-py3-none-any.whl (6.0 kB view details)

Uploaded Python 3

File details

Details for the file tinysolve-0.1.0.tar.gz.

File metadata

  • Download URL: tinysolve-0.1.0.tar.gz
  • Upload date:
  • Size: 5.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tinysolve-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5e05fb7880a6841e99bbccebb3016e38d86e3361f551a89a32b999dcafb50c16
MD5 3da4fcd3b20425ebe16b7fc03c5dd4f8
BLAKE2b-256 68efafdaece9a1a19e259e611aba07b9bb47a462eeb4bf6ecdeabeee816eb7bd

See more details on using hashes here.

File details

Details for the file tinysolve-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: tinysolve-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tinysolve-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4b60f04184b791d15adff7bbb42a16baacdf032da435b9b84203bbed7f2c6865
MD5 c5d437c4e1030e0eafce74a2e273c87b
BLAKE2b-256 0759f2f5908cea80d017924ba9792a9ede73f273f3afbb4e24c5c9a87f0df023

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page