SpinTensor
A Python library for constructing linear constraints on tensors under transformations using Kronecker products. Supports operation-dependent T-parity, P-parity, and index-permutation symmetries, with automatic nullspace computation via SVD and LaTeX output.
Overview
This library constructs linear constraints for order-r tensors in dimension n under spin-group operations (Rs, Rr) of the form:
Tᵢ₁…ᵢᵣ = sign_T · sign_P · Rrᵢ₁ⱼ₁ … Rrᵢᵣⱼᵣ Tⱼ₁…ⱼᵣ
where the per-operation sign factors are computed from matrix determinants:
sign_T = det(Rs) ** T_constraint
sign_P = det(Rr) ** P_constraint
Rsis the spin-space matrix:det(Rs) = -1contributes an effective time-reversal sign for T-odd tensors (T_constraint = 1).Rris the real-space matrix applied to every tensor axis:det(Rr) = -1contributes a parity sign for P-odd tensors (P_constraint = 1).- The real-space action
Rr ⊗ Rr ⊗ ... ⊗ Rralways drives the tensor transformation;Rsonly contributes a sign.
The library builds constraint matrices, computes their nullspace using SVD (not row reduction), and outputs readable LaTeX relations with automatic index-to-symbol mapping.
Installation
pip install spintensor
Or install in development mode:
pip install -e .
Features
- Operation-Dependent Sign Logic: Per-operation sign factors
sign_T = det(Rs)**T_constraintandsign_P = det(Rr)**P_constraint(not global fixed values) - Kronecker Product Transformations: Efficiently build transformation matrices using Kronecker products of the real-space matrix
Rr - T-parity and P-parity: Support for time reversal and spatial parity symmetries
- Index Permutation Symmetries: Handle symmetric, antisymmetric, and general permutation symmetries
- SVD-based Nullspace: Numerically stable nullspace computation using Singular Value Decomposition
- LaTeX Output: Automatic generation of readable constraint relations with smart index notation
Quick Start
import numpy as np
from spintensor import solve_tensor_constraints
# Define operations in [Rs, Rr] format
# Rs: spin-space matrix; Rr: real-space matrix
n = 3 # dimension
r = 2 # tensor rank
# Spin reflection (det(Rs) = -1) in spin space, identity in real space
Rs = np.diag([1., 1., -1.]) # det = -1
Rr = np.eye(3) # det = +1
# T-odd tensor: sign_T = det(Rs)**1 = -1
A, nullspace, relations, components = solve_tensor_constraints(
[[Rs, Rr]], n, r, T_constraint=1, P_constraint=0
)
print(f"Independent components: {nullspace.shape[1]}")
for rel in relations:
print(f" {rel}")
Input Formats
All transformation formats are supported. The [Rs, Rr] format is the primary API for the new per-operation sign convention:
Format 1: [Rs, Rr] (recommended)
# Each entry is [spin_matrix, real_space_matrix]
transformations = [
[Rs1, Rr1], # sign_T = det(Rs1)**T_constraint, sign_P = det(Rr1)**P_constraint
[Rs2, Rr2],
]
With spin_axes set, Rs is also applied to the specified tensor axes.
Format 2: [Tflag, Rr] (explicit anti-unitary flag)
# Tflag=True means the operation is anti-unitary (contributes sign_T=-1 when T_constraint=1)
transformations = [
[False, Rr_unitary], # sign_T = +1
[True, Rr_antiunitary], # sign_T = -1
]
Format 3: Rr only (no spin component)
# Single numpy array: treated as Rs = identity (det=+1, no T sign)
transformations = [Rr1, Rr2] # sign_T = +1 always
Format 4: Legacy (R, s_T, s_P) tuple
# Explicit parity values (backward compatible)
transformations = [(R, s_T, s_P)]
API Reference
Main Function
solve_tensor_constraints(transformations, n, r, symmetries=None, antisymmetries=None, tol=1e-10, spin_axes=None, T_constraint=0, det_tol=1e-6, symbol='\\sigma', extra_constraints=None, P_constraint=0)
Complete solver for tensor constraints.
Parameters:
transformations: List of transformations in any supported formatn: int, dimension of the tensor spacer: int, order (rank) of the tensorsymmetries: list of tuples, optional index permutations for symmetric constraints (T_perm = T)antisymmetries: list of tuples, optional index permutations for antisymmetric constraints (T_perm = -T)tol: float, tolerance for numerical operationsspin_axes: optional tuple of axis indices for spin axes (used with [Rs, Rr] format)T_constraint: int, exponent for time-reversal sign.sign_T = det(Rs)**T_constraint. Use1for T-odd tensors (default0)P_constraint: int, exponent for parity sign.sign_P = det(Rr)**P_constraint. Use1for P-odd/axial tensors (default0)det_tol: float, tolerance for determinant comparison to ±1
Returns:
constraint_matrix: numpy array, full constraint matrixnullspace_basis: numpy array, columns are basis vectorslatex_relations: list of strings, formatted LaTeX relationstensor_components: nested list of component expressions
Convenience Functions
solve_qmd(transformations, n=3, tol=1e-10)
Solve for QMD (quadrupole moment derivative) tensors: T-odd, rank-3, with last-two-index symmetry.
solve_imd(transformations, n=3, tol=1e-10)
Solve for IMD tensors: T-odd, rank-3, with both last-two and first-two index symmetry.
solve_bcd(transformations, n=3, tol=1e-10, use_cyclic_constraint=True)
Solve for BCD (Berry curvature dipole) tensors: T-even, rank-3, with last-two-index symmetry and optional cyclic sum constraint.
Core Functions
build_constraint_matrix(transformations, n, r, ...)
Build the full constraint matrix from transformations and symmetries.
compute_nullspace_svd(A, tol=1e-10)
Compute nullspace of matrix A using SVD.
format_latex_relations(nullspace, n, r, tol=1e-10)
Format nullspace basis vectors as readable LaTeX relations.
Examples
Example 1: AHE Conductivity (T-odd, polar, rank-2)
import numpy as np
from spintensor import solve_tensor_constraints
# Operations in [Rs, Rr] format
# T-odd tensor: sign_T = det(Rs)**1
ops = [
[np.diag([1., 1., 1.]), np.diag([1., 1., 1.])], # identity
[np.diag([1., 1., -1.]), np.diag([1., 1.,-1.])], # z-mirror: det(Rs)=-1 → s_T=-1
]
A, nullspace, relations, comps = solve_tensor_constraints(
ops, n=3, r=2, T_constraint=1, P_constraint=0
)
print(f"Independent components: {nullspace.shape[1]}")
Example 2: QMD Tensor with Spin-Group Operations
import numpy as np
from spintensor import solve_qmd
# Operations in [Rs, Rr] format
# Mirror op: det(Rs) = -1 → T-odd sign applies
s = np.sqrt(3) / 2
ops = [
[np.eye(3), np.eye(3)],
[np.array([[-0.5, s, 0], [s, 0.5, 0], [0, 0, 1]]),
np.array([[-0.5, s, 0], [s, 0.5, 0], [0, 0, 1]])],
# ... more operations
]
A, nullspace, relations, comps = solve_qmd(ops)
Example 3: P-odd (Axial) Tensor
import numpy as np
from spintensor import solve_tensor_constraints
# P_constraint=1: sign_P = det(Rr)**1
# For a reflection with det(Rr)=-1, this adds a -1 sign factor
R_reflect = np.diag([1., 1., -1.])
A, nullspace, relations, comps = solve_tensor_constraints(
[[np.eye(3), R_reflect]], n=3, r=2,
T_constraint=0, P_constraint=1
)
Example 4: Legacy Format (Backward Compatible)
import numpy as np
from spintensor import solve_tensor_constraints
R_z = np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]])
# Legacy tuple format: (R, s_T, s_P) — explicit parity values
transformations = [(R_z, 1.0, 1.0)]
A, nullspace, relations, comps = solve_tensor_constraints(
transformations, n=3, r=2, symmetries=[(1, 0)]
)
Mathematical Background
Operation-Dependent Sign Logic
For each operation (Rs, Rr), the transformation matrix acting on the flattened tensor is:
M = sign_T · sign_P · (Rr ⊗ Rr ⊗ ... ⊗ Rr)
where:
sign_T = det(Rs) ** T_constraint
sign_P = det(Rr) ** P_constraint
The constraint for a symmetry-invariant tensor is (M - I) · T = 0.
Physical interpretation:
det(Rs) = -1: The spin-space operation flips the spin (effective time-reversal character). For T-odd tensors (T_constraint=1), this contributes a factor of-1.det(Rr) = -1: The real-space operation is an improper rotation (parity-odd). For P-odd/axial tensors (P_constraint=1), this contributes a factor of-1.- These factors are per-operation — each operation in the symmetry group can independently flip or not flip each parity sign.
Index Symmetries
Index permutation symmetries impose additional constraints:
(P_perm - I) · T = 0 (symmetric)
(P_perm + I) · T = 0 (antisymmetric)
Nullspace Computation
The solution space consists of all tensors satisfying the constraints. This is the nullspace of the combined constraint matrix A, computed via SVD:
A = U · Σ · Vᵀ
The nullspace is spanned by columns of V corresponding to zero singular values. The basis is further reduced to RREF form for clean, canonical coefficients.
Output Format
Relations are output in LaTeX format with automatic index notation:
- For n ≤ 4: uses letters (x, y, z, w)
- For n > 4: uses numbers (1, 2, 3, ...)
Example output:
\sigma_{xxy} = \sigma_{xyx} = \sigma_{yxx} = -\sigma_{yyy}
\sigma_{xyz} = \sigma_{xzy} = -\sigma_{yxz} = -\sigma_{yzx}
Requirements
- Python ≥ 3.7
- NumPy ≥ 1.19.0
License
MIT License
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Citation
If you use this library in your research, please cite:
@software{spintensor,
title = {SpinTensor: Linear Constraints for Tensors Under Transformations},
author = {Connor1y},
year = {2026},
url = {https://github.com/Connor1y/spintensor}
}
Metadata
Release files for spintensor 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| spintensor-0.1.0.tar.gz | 46.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| spintensor-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 62.7 kB
Release files / spintensor-0.1.0.tar.gz
| Download URL | spintensor-0.1.0.tar.gz |
|---|---|
| Size | 46.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cc52b31cec3140b90f7d039d7727adef0a81e60baf9a8a94ed19e1cf3c2457de
|
|
BLAKE2b-256 checksum How to use checksums |
cc788016f3f7a28e177fa335b59c3491176bc92afacad710da7327a48c48463e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 8, 2026.
Transparency logRelease files / spintensor-0.1.0-py3-none-any.whl
| Download URL | spintensor-0.1.0-py3-none-any.whl |
|---|---|
| Size | 16.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f2b2e1ca0ca8f430b58c5a06aa053d1fbee48b6dd6d652ef9a885a72fdc5670b
|
|
BLAKE2b-256 checksum How to use checksums |
4b180804633ed877a16b264be8023b8485e510f71461b1f9f93566349a7e4416
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 8, 2026.
Transparency log