Quaternion algebra library with vector/matrix/tensor collections, linear algebra (SVD), interpolation (SLERP/squad), signal processing (QFFT/QConv), and optimized einsum kernels.
Project description
quat
Quaternion Algebra for NumPy
quat brings first-class quaternion support to NumPy. Scalar quaternions, vector/matrix/tensor collections, SVD, SLERP interpolation, QFFT signal processing, serialization — with a three-tier-einsum Hamilton kernel that picks the fastest strategy at every data size. All in pure Python, zero C extensions.
pip install quat-numpy
Why quat?
Most quaternion libraries stop at rotating 3D vectors. quat gives you the full toolbox:
| What | How |
|---|---|
| Scalar quaternions | Full algebra — +, *, /, exp, log, pow, Hamilton product |
| Collections | QuatVector (1D), QuatMatrix (2D), QuatTensor (3D) — broadcast-aware |
| Linear algebra | SVD, rank, condition number, pseudo-inverse, determinant — on quaternion matrices |
| Interpolation | SLERP (shortest arc on S³), squad cubic spline, batch SLERP |
| Signal processing | 1D/2D QFFT, quaternion convolution, FIR filter design |
| Random generation | Reproducible generators for all four types |
| Serialization | JSON + compact binary roundtrip for all types; SciPy Rotation interop |
| Performance | Three-tier Hamilton kernel (component-wise → einsum), ~20x faster SVD fast-path |
Quickstart
import numpy as np
from quat import Quaternion, QuatVector, QuatMatrix
from quat import slerp, squad, random_unit_quat
# ---- Construction -------------------------------------------------
q = Quaternion(1, 2, 3, 4) # a + bi + cj + dk
r = Quaternion(5.0) # pure real
u = Quaternion.from_axis_angle((0,0,1), np.pi/2) # 90 deg around z
e = Quaternion.from_euler((0.1, 0.2, 0.3)) # intrinsic ZYX
# ---- Hamilton product ---------------------------------------------
i, j, k = Quaternion(0,1,0,0), Quaternion(0,0,1,0), Quaternion(0,0,0,1)
print(i * j) # Quaternion(0, 0, 0, 1) — i*j = k
print(i * j * k) # Quaternion(-1, 0, 0, 0) — i² = j² = k² = ijk = -1
# ---- Algebra ------------------------------------------------------
q.conjugate() # Quaternion(1, -2, -3, -4)
q.norm() # Euclidean norm
q.inverse() * q # ≈ identity
q.exp() # quaternion exponential
q.log() # quaternion logarithm
# ---- 3D rotation --------------------------------------------------
u = Quaternion.from_axis_angle((0, 0, 1), np.pi / 2)
u.rotate_vector((1, 0, 0)) # ≈ (0, 1, 0) — 90° rotation
axis, angle = u.to_axis_angle() # roundtrip (axis, angle)
# ---- Smooth interpolation -----------------------------------------
a = Quaternion(1, 0, 0, 0)
b = Quaternion(0, 1, 0, 0)
mid = slerp(a, b, 0.5) # shortest arc on the 3-sphere
q0, q1, q2, q3 = [random_unit_quat() for _ in range(4)]
curve = squad(q0, q1, q2, q3, 0.75) # cubic spline (Shoemake 1987)
# ---- Collections --------------------------------------------------
v = QuatVector([
Quaternion(1,0,0,0), Quaternion(0,1,0,0), Quaternion(0,0,1,0)
])
v.real # array([1., 0., 0.])
v.data.shape # (3, 4)
A = QuatMatrix.eye(3)
B = QuatMatrix(np.random.randn(3, 4, 4))
C = A @ B # quaternion matrix multiply (A * B also works)
C.shape # (3, 4)
# ---- Linear algebra -----------------------------------------------
from quat.linalg import svd, pseudo_inverse, solve
U, s, Vh = svd(C)
A_pinv = pseudo_inverse(C)
x = solve(A_pinv, QuatVector(np.ones((3, 4))))
# ---- Signal processing --------------------------------------------
from quat.signal import qfft, qconv, lowpass
X = qfft(np.random.randn(256, 4)) # 1D quaternion FFT
k = lowpass(16, cutoff=0.2) # FIR lowpass filter
y = qconv(np.random.randn(128, 4), k._data) # quaternion convolution
# ---- Serialization ------------------------------------------------
s = q.to_json() # → '{"type":"Quaternion","data":[...]}'
b = q.to_bytes() # → compact binary
q2 = Quaternion.from_json(s)
q3 = Quaternion.from_bytes(b)
# ---- Basis constants ----------------------------------------------
from quat import _I, _J, _K, _R, _ZERO
print(_I * _J * _K) # -1 (Hamilton's fundamental identity)
API Reference
Quaternion — scalar quaternion
| category | methods |
|---|---|
| constructors | zero(), one_q(), from_axis_angle(), from_euler(), from_complex_matrix(), from_real_matrix_left() |
| components | .r, .i, .j, .k, .real, .imag, .components, .data |
| arithmetic | +, -, *, /, -q, @ |
| algebra | .conjugate(), .norm(), .normalize(), .inverse(), .exp(), .log(), .pow(t), .re_inner(q), .commutator(q) |
| rotation | .rotate_vector(v), .to_axis_angle(), .to_euler(seq='zyx') |
| validation | .isnan(), .isinf(), .isfinite(), .isclose(q) |
| serialization | .to_json(), .from_json(s), .to_bytes(), .from_bytes(b) |
| matrices | .to_complex_matrix(), .to_real_matrix_left(), .to_real_matrix_right() |
| conversion | float(q), int(q), complex(q), abs(q), np.asarray(q) |
QuatVector / QuatMatrix / QuatTensor
| QuatVector | QuatMatrix | QuatTensor | |
|---|---|---|---|
| ndim | 1D | 2D | 3D |
| shape | (n,) |
(m, n) |
(p, q, r) |
| create | zeros, ones |
zeros, eye |
zeros |
| access | .data, .real/.i/.j/.k |
.data, .real/.i/.j/.k, .row(i), .col(j) |
.data, .real/.i/.j/.k |
| ops | .inner(v), .norm() |
.norm(), .T, .H, .conjugate() |
.inner(T), .unfold(mode), .mode_n_product(A) |
Module overview
| module | exports |
|---|---|
quat.random |
random_quat, random_unit_quat, random_quat_vector, random_quat_matrix, random_quat_tensor |
quat.interpolate |
slerp, slerp_vector, squad |
quat.linalg |
svd, rank, condition_number, pseudo_inverse, trace, det, norm, solve |
quat.serialization |
to_json, from_json, to_bytes, from_bytes, to_scipy_rotation, from_scipy_rotation |
quat.signal |
qfft, iqfft, qfft2, iqfft2, qconv, qconv2, lowpass, highpass, bandpass, bandstop |
quat.optimized |
hamilton_einsum, quat_matmul, conjugate_batch, norm_squared_batch, normalize_batch |
Performance
The Hamilton product kernel uses a three-tier dispatch that selects the fastest strategy based on data size:
| size | kernel | strategy |
|---|---|---|
| ≤ 500 elements | _hamilton_component |
direct float arithmetic |
| 500 – 5000 | _hamilton_einsum_noopt |
einsum without contraction-path optimisation |
| > 5000 | _hamilton_einsum |
einsum with full optimisation |
SVD fast-path: rank(), condition_number(), and norm(A, 2) compute
only singular values via the complex (2×2) representation — ~20× faster
than the full 4m×4n real SVD.
Zero-copy interop: q.to_numpy(copy=False) returns the internal buffer
without copying. .to_complex_matrix() and .to_real_matrix_left() use
np.empty to skip zero-initialisation.
Install
pip install quat-numpy
Requires Python ≥ 3.9, NumPy ≥ 1.21. Optional scipy for
to_scipy_rotation / from_scipy_rotation.
For development:
git clone https://github.com/gealachlee/quat.git
cd quat
pip install -e .
pytest tests/
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 quat_numpy-0.2.0.tar.gz.
File metadata
- Download URL: quat_numpy-0.2.0.tar.gz
- Upload date:
- Size: 42.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b4953581c052a93f96172dd59843e815706e9607fc0b69f3b28d110f70f1d23
|
|
| MD5 |
b9edb5f5305fc9fa7c375a75f7c7e422
|
|
| BLAKE2b-256 |
b76bec58885463c45bb5d5e7677576909feb732941a165f15325a5dfdc1bfb74
|
Provenance
The following attestation bundles were made for quat_numpy-0.2.0.tar.gz:
Publisher:
publish.yml on gealachlee/quat
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
quat_numpy-0.2.0.tar.gz -
Subject digest:
6b4953581c052a93f96172dd59843e815706e9607fc0b69f3b28d110f70f1d23 - Sigstore transparency entry: 2010917849
- Sigstore integration time:
-
Permalink:
gealachlee/quat@a73eb125bc579da30eed94f32984bd55730cc9be -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/gealachlee
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a73eb125bc579da30eed94f32984bd55730cc9be -
Trigger Event:
push
-
Statement type:
File details
Details for the file quat_numpy-0.2.0-py3-none-any.whl.
File metadata
- Download URL: quat_numpy-0.2.0-py3-none-any.whl
- Upload date:
- Size: 35.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4746f81a294a791c3a45ce351eec87de0a753f414dc1c1c3068b921fdd6cec32
|
|
| MD5 |
ac3f19ae848166f9ca60c96a71a9ca34
|
|
| BLAKE2b-256 |
3f5af84e1db0d40f0756897c3a57e39cc0bb30be2ad950cf323a1fbd61b146b5
|
Provenance
The following attestation bundles were made for quat_numpy-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on gealachlee/quat
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
quat_numpy-0.2.0-py3-none-any.whl -
Subject digest:
4746f81a294a791c3a45ce351eec87de0a753f414dc1c1c3068b921fdd6cec32 - Sigstore transparency entry: 2010917964
- Sigstore integration time:
-
Permalink:
gealachlee/quat@a73eb125bc579da30eed94f32984bd55730cc9be -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/gealachlee
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a73eb125bc579da30eed94f32984bd55730cc9be -
Trigger Event:
push
-
Statement type: