Define signatures and layouts¶
Choose the signature from the quadratic form your computation needs. In
make_algebra(p, q, r), the first p basis vectors square to \(+1\), the next
q to \(-1\), and the remaining r to zero. Distinct basis vectors anticommute.
Changing a signature changes products, not just metadata attached to tensors.
A layout defines the coefficient space. algebra.layout((1,)) contains every
vector lane; algebra.layout((0, 2)) contains the scalar and every bivector
lane. Grades are normalized to a sorted set, but coefficient lanes follow
increasing canonical bitmask index, not a concatenation of grade blocks.
Bit \(i-1\) denotes basis vector \(e_i\), for \(i=1,\ldots,n\).
import torch
from clifra import make_algebra
algebra = make_algebra(2, 1, dtype=torch.float64)
vectors = algebra.layout((1,))
mixed = algebra.layout((0, 1, 2))
assert vectors.basis_indices == (1, 2, 4)
assert mixed.basis_indices == (0, 1, 2, 3, 4, 5, 6)
# Mixed lanes: 1, e1, e2, e12, e3, e13, e23.
e3 = torch.tensor([0.0, 0.0, 1.0], dtype=torch.float64)
square = algebra.scalar_product(e3, e3, left=vectors, right=vectors)
torch.testing.assert_close(square, torch.tensor([-1.0], dtype=torch.float64))
assert mixed.positions_for_grades((1,)).tolist() == [1, 2, 4]
Use positions_for_grades or positions_for_basis when selecting lanes;
contiguous slices are not generally grade selections. A grade-\(k\) layout in
dimension \(n\) has \(\binom nk\) lanes, while algebra.layout() has \(2^n\).
Whole-grade layouts are the currently supported layout implementation.
Pass the layout explicitly at operation boundaries. Clifra relies on these declarations rather than inferring layout from tensor shape, since the same width can represent different grades. Omitting a declaration implies the full basis.