spintensor 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Connor1y
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ include LICENSE
2
+ include README.md
3
+ include requirements.txt
4
+ recursive-include src *.py
5
+ recursive-include tests *.py
6
+ recursive-include examples *.py
@@ -0,0 +1,343 @@
1
+ Metadata-Version: 2.4
2
+ Name: spintensor
3
+ Version: 0.1.0
4
+ Summary: Build linear constraints for tensors under transformations using Kronecker products
5
+ Author: Connor1y
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Connor1y/spintensor
8
+ Project-URL: Repository, https://github.com/Connor1y/spintensor
9
+ Project-URL: Issues, https://github.com/Connor1y/spintensor/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
13
+ Classifier: Topic :: Scientific/Engineering :: Physics
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.7
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Requires-Python: >=3.7
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: numpy>=1.19.0
25
+ Dynamic: license-file
26
+
27
+ # SpinTensor
28
+
29
+ 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.
30
+
31
+ ## Overview
32
+
33
+ This library constructs linear constraints for order-r tensors in dimension n under spin-group operations `(Rs, Rr)` of the form:
34
+
35
+ ```
36
+ Tᵢ₁…ᵢᵣ = sign_T · sign_P · Rrᵢ₁ⱼ₁ … Rrᵢᵣⱼᵣ Tⱼ₁…ⱼᵣ
37
+ ```
38
+
39
+ where the **per-operation sign factors** are computed from matrix determinants:
40
+
41
+ ```
42
+ sign_T = det(Rs) ** T_constraint
43
+ sign_P = det(Rr) ** P_constraint
44
+ ```
45
+
46
+ - `Rs` is the **spin-space matrix**: `det(Rs) = -1` contributes an effective time-reversal sign for T-odd tensors (`T_constraint = 1`).
47
+ - `Rr` is the **real-space matrix** applied to every tensor axis: `det(Rr) = -1` contributes a parity sign for P-odd tensors (`P_constraint = 1`).
48
+ - The real-space action `Rr ⊗ Rr ⊗ ... ⊗ Rr` always drives the tensor transformation; `Rs` only contributes a sign.
49
+
50
+ The library builds constraint matrices, computes their nullspace using SVD (not row reduction), and outputs readable LaTeX relations with automatic index-to-symbol mapping.
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ pip install spintensor
56
+ ```
57
+
58
+ Or install in development mode:
59
+
60
+ ```bash
61
+ pip install -e .
62
+ ```
63
+
64
+ ## Features
65
+
66
+ - **Operation-Dependent Sign Logic**: Per-operation sign factors `sign_T = det(Rs)**T_constraint` and `sign_P = det(Rr)**P_constraint` (not global fixed values)
67
+ - **Kronecker Product Transformations**: Efficiently build transformation matrices using Kronecker products of the real-space matrix `Rr`
68
+ - **T-parity and P-parity**: Support for time reversal and spatial parity symmetries
69
+ - **Index Permutation Symmetries**: Handle symmetric, antisymmetric, and general permutation symmetries
70
+ - **SVD-based Nullspace**: Numerically stable nullspace computation using Singular Value Decomposition
71
+ - **LaTeX Output**: Automatic generation of readable constraint relations with smart index notation
72
+
73
+ ## Quick Start
74
+
75
+ ```python
76
+ import numpy as np
77
+ from spintensor import solve_tensor_constraints
78
+
79
+ # Define operations in [Rs, Rr] format
80
+ # Rs: spin-space matrix; Rr: real-space matrix
81
+ n = 3 # dimension
82
+ r = 2 # tensor rank
83
+
84
+ # Spin reflection (det(Rs) = -1) in spin space, identity in real space
85
+ Rs = np.diag([1., 1., -1.]) # det = -1
86
+ Rr = np.eye(3) # det = +1
87
+
88
+ # T-odd tensor: sign_T = det(Rs)**1 = -1
89
+ A, nullspace, relations, components = solve_tensor_constraints(
90
+ [[Rs, Rr]], n, r, T_constraint=1, P_constraint=0
91
+ )
92
+
93
+ print(f"Independent components: {nullspace.shape[1]}")
94
+ for rel in relations:
95
+ print(f" {rel}")
96
+ ```
97
+
98
+ ## Input Formats
99
+
100
+ All transformation formats are supported. The `[Rs, Rr]` format is the primary API for the new per-operation sign convention:
101
+
102
+ ### Format 1: `[Rs, Rr]` (recommended)
103
+
104
+ ```python
105
+ # Each entry is [spin_matrix, real_space_matrix]
106
+ transformations = [
107
+ [Rs1, Rr1], # sign_T = det(Rs1)**T_constraint, sign_P = det(Rr1)**P_constraint
108
+ [Rs2, Rr2],
109
+ ]
110
+ ```
111
+
112
+ With `spin_axes` set, `Rs` is also applied to the specified tensor axes.
113
+
114
+ ### Format 2: `[Tflag, Rr]` (explicit anti-unitary flag)
115
+
116
+ ```python
117
+ # Tflag=True means the operation is anti-unitary (contributes sign_T=-1 when T_constraint=1)
118
+ transformations = [
119
+ [False, Rr_unitary], # sign_T = +1
120
+ [True, Rr_antiunitary], # sign_T = -1
121
+ ]
122
+ ```
123
+
124
+ ### Format 3: `Rr` only (no spin component)
125
+
126
+ ```python
127
+ # Single numpy array: treated as Rs = identity (det=+1, no T sign)
128
+ transformations = [Rr1, Rr2] # sign_T = +1 always
129
+ ```
130
+
131
+ ### Format 4: Legacy `(R, s_T, s_P)` tuple
132
+
133
+ ```python
134
+ # Explicit parity values (backward compatible)
135
+ transformations = [(R, s_T, s_P)]
136
+ ```
137
+
138
+ ## API Reference
139
+
140
+ ### Main Function
141
+
142
+ #### `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)`
143
+
144
+ Complete solver for tensor constraints.
145
+
146
+ **Parameters:**
147
+ - `transformations`: List of transformations in any supported format
148
+ - `n`: int, dimension of the tensor space
149
+ - `r`: int, order (rank) of the tensor
150
+ - `symmetries`: list of tuples, optional index permutations for symmetric constraints (T_perm = T)
151
+ - `antisymmetries`: list of tuples, optional index permutations for antisymmetric constraints (T_perm = -T)
152
+ - `tol`: float, tolerance for numerical operations
153
+ - `spin_axes`: optional tuple of axis indices for spin axes (used with [Rs, Rr] format)
154
+ - `T_constraint`: int, exponent for time-reversal sign. `sign_T = det(Rs)**T_constraint`. Use `1` for T-odd tensors (default `0`)
155
+ - `P_constraint`: int, exponent for parity sign. `sign_P = det(Rr)**P_constraint`. Use `1` for P-odd/axial tensors (default `0`)
156
+ - `det_tol`: float, tolerance for determinant comparison to ±1
157
+
158
+ **Returns:**
159
+ - `constraint_matrix`: numpy array, full constraint matrix
160
+ - `nullspace_basis`: numpy array, columns are basis vectors
161
+ - `latex_relations`: list of strings, formatted LaTeX relations
162
+ - `tensor_components`: nested list of component expressions
163
+
164
+ ### Convenience Functions
165
+
166
+ #### `solve_qmd(transformations, n=3, tol=1e-10)`
167
+
168
+ Solve for QMD (quadrupole moment derivative) tensors: T-odd, rank-3, with last-two-index symmetry.
169
+
170
+ #### `solve_imd(transformations, n=3, tol=1e-10)`
171
+
172
+ Solve for IMD tensors: T-odd, rank-3, with both last-two and first-two index symmetry.
173
+
174
+ #### `solve_bcd(transformations, n=3, tol=1e-10, use_cyclic_constraint=True)`
175
+
176
+ Solve for BCD (Berry curvature dipole) tensors: T-even, rank-3, with last-two-index symmetry and optional cyclic sum constraint.
177
+
178
+ ### Core Functions
179
+
180
+ #### `build_constraint_matrix(transformations, n, r, ...)`
181
+
182
+ Build the full constraint matrix from transformations and symmetries.
183
+
184
+ #### `compute_nullspace_svd(A, tol=1e-10)`
185
+
186
+ Compute nullspace of matrix A using SVD.
187
+
188
+ #### `format_latex_relations(nullspace, n, r, tol=1e-10)`
189
+
190
+ Format nullspace basis vectors as readable LaTeX relations.
191
+
192
+ ## Examples
193
+
194
+ ### Example 1: AHE Conductivity (T-odd, polar, rank-2)
195
+
196
+ ```python
197
+ import numpy as np
198
+ from spintensor import solve_tensor_constraints
199
+
200
+ # Operations in [Rs, Rr] format
201
+ # T-odd tensor: sign_T = det(Rs)**1
202
+
203
+ ops = [
204
+ [np.diag([1., 1., 1.]), np.diag([1., 1., 1.])], # identity
205
+ [np.diag([1., 1., -1.]), np.diag([1., 1.,-1.])], # z-mirror: det(Rs)=-1 → s_T=-1
206
+ ]
207
+
208
+ A, nullspace, relations, comps = solve_tensor_constraints(
209
+ ops, n=3, r=2, T_constraint=1, P_constraint=0
210
+ )
211
+
212
+ print(f"Independent components: {nullspace.shape[1]}")
213
+ ```
214
+
215
+ ### Example 2: QMD Tensor with Spin-Group Operations
216
+
217
+ ```python
218
+ import numpy as np
219
+ from spintensor import solve_qmd
220
+
221
+ # Operations in [Rs, Rr] format
222
+ # Mirror op: det(Rs) = -1 → T-odd sign applies
223
+ s = np.sqrt(3) / 2
224
+ ops = [
225
+ [np.eye(3), np.eye(3)],
226
+ [np.array([[-0.5, s, 0], [s, 0.5, 0], [0, 0, 1]]),
227
+ np.array([[-0.5, s, 0], [s, 0.5, 0], [0, 0, 1]])],
228
+ # ... more operations
229
+ ]
230
+
231
+ A, nullspace, relations, comps = solve_qmd(ops)
232
+ ```
233
+
234
+ ### Example 3: P-odd (Axial) Tensor
235
+
236
+ ```python
237
+ import numpy as np
238
+ from spintensor import solve_tensor_constraints
239
+
240
+ # P_constraint=1: sign_P = det(Rr)**1
241
+ # For a reflection with det(Rr)=-1, this adds a -1 sign factor
242
+ R_reflect = np.diag([1., 1., -1.])
243
+
244
+ A, nullspace, relations, comps = solve_tensor_constraints(
245
+ [[np.eye(3), R_reflect]], n=3, r=2,
246
+ T_constraint=0, P_constraint=1
247
+ )
248
+ ```
249
+
250
+ ### Example 4: Legacy Format (Backward Compatible)
251
+
252
+ ```python
253
+ import numpy as np
254
+ from spintensor import solve_tensor_constraints
255
+
256
+ R_z = np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]])
257
+
258
+ # Legacy tuple format: (R, s_T, s_P) — explicit parity values
259
+ transformations = [(R_z, 1.0, 1.0)]
260
+ A, nullspace, relations, comps = solve_tensor_constraints(
261
+ transformations, n=3, r=2, symmetries=[(1, 0)]
262
+ )
263
+ ```
264
+
265
+ ## Mathematical Background
266
+
267
+ ### Operation-Dependent Sign Logic
268
+
269
+ For each operation `(Rs, Rr)`, the transformation matrix acting on the flattened tensor is:
270
+
271
+ ```
272
+ M = sign_T · sign_P · (Rr ⊗ Rr ⊗ ... ⊗ Rr)
273
+ ```
274
+
275
+ where:
276
+
277
+ ```
278
+ sign_T = det(Rs) ** T_constraint
279
+ sign_P = det(Rr) ** P_constraint
280
+ ```
281
+
282
+ The constraint for a symmetry-invariant tensor is `(M - I) · T = 0`.
283
+
284
+ **Physical interpretation:**
285
+ - `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`.
286
+ - `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`.
287
+ - These factors are **per-operation** — each operation in the symmetry group can independently flip or not flip each parity sign.
288
+
289
+ ### Index Symmetries
290
+
291
+ Index permutation symmetries impose additional constraints:
292
+ ```
293
+ (P_perm - I) · T = 0 (symmetric)
294
+ (P_perm + I) · T = 0 (antisymmetric)
295
+ ```
296
+
297
+ ### Nullspace Computation
298
+
299
+ The solution space consists of all tensors satisfying the constraints. This is the nullspace of the combined constraint matrix A, computed via SVD:
300
+
301
+ ```
302
+ A = U · Σ · Vᵀ
303
+ ```
304
+
305
+ 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.
306
+
307
+ ## Output Format
308
+
309
+ Relations are output in LaTeX format with automatic index notation:
310
+ - For n ≤ 4: uses letters (x, y, z, w)
311
+ - For n > 4: uses numbers (1, 2, 3, ...)
312
+
313
+ Example output:
314
+ ```
315
+ \sigma_{xxy} = \sigma_{xyx} = \sigma_{yxx} = -\sigma_{yyy}
316
+ \sigma_{xyz} = \sigma_{xzy} = -\sigma_{yxz} = -\sigma_{yzx}
317
+ ```
318
+
319
+ ## Requirements
320
+
321
+ - Python ≥ 3.7
322
+ - NumPy ≥ 1.19.0
323
+
324
+ ## License
325
+
326
+ MIT License
327
+
328
+ ## Contributing
329
+
330
+ Contributions are welcome! Please feel free to submit a Pull Request.
331
+
332
+ ## Citation
333
+
334
+ If you use this library in your research, please cite:
335
+
336
+ ```bibtex
337
+ @software{spintensor,
338
+ title = {SpinTensor: Linear Constraints for Tensors Under Transformations},
339
+ author = {Connor1y},
340
+ year = {2026},
341
+ url = {https://github.com/Connor1y/spintensor}
342
+ }
343
+ ```
@@ -0,0 +1,317 @@
1
+ # SpinTensor
2
+
3
+ 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.
4
+
5
+ ## Overview
6
+
7
+ This library constructs linear constraints for order-r tensors in dimension n under spin-group operations `(Rs, Rr)` of the form:
8
+
9
+ ```
10
+ Tᵢ₁…ᵢᵣ = sign_T · sign_P · Rrᵢ₁ⱼ₁ … Rrᵢᵣⱼᵣ Tⱼ₁…ⱼᵣ
11
+ ```
12
+
13
+ where the **per-operation sign factors** are computed from matrix determinants:
14
+
15
+ ```
16
+ sign_T = det(Rs) ** T_constraint
17
+ sign_P = det(Rr) ** P_constraint
18
+ ```
19
+
20
+ - `Rs` is the **spin-space matrix**: `det(Rs) = -1` contributes an effective time-reversal sign for T-odd tensors (`T_constraint = 1`).
21
+ - `Rr` is the **real-space matrix** applied to every tensor axis: `det(Rr) = -1` contributes a parity sign for P-odd tensors (`P_constraint = 1`).
22
+ - The real-space action `Rr ⊗ Rr ⊗ ... ⊗ Rr` always drives the tensor transformation; `Rs` only contributes a sign.
23
+
24
+ The library builds constraint matrices, computes their nullspace using SVD (not row reduction), and outputs readable LaTeX relations with automatic index-to-symbol mapping.
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pip install spintensor
30
+ ```
31
+
32
+ Or install in development mode:
33
+
34
+ ```bash
35
+ pip install -e .
36
+ ```
37
+
38
+ ## Features
39
+
40
+ - **Operation-Dependent Sign Logic**: Per-operation sign factors `sign_T = det(Rs)**T_constraint` and `sign_P = det(Rr)**P_constraint` (not global fixed values)
41
+ - **Kronecker Product Transformations**: Efficiently build transformation matrices using Kronecker products of the real-space matrix `Rr`
42
+ - **T-parity and P-parity**: Support for time reversal and spatial parity symmetries
43
+ - **Index Permutation Symmetries**: Handle symmetric, antisymmetric, and general permutation symmetries
44
+ - **SVD-based Nullspace**: Numerically stable nullspace computation using Singular Value Decomposition
45
+ - **LaTeX Output**: Automatic generation of readable constraint relations with smart index notation
46
+
47
+ ## Quick Start
48
+
49
+ ```python
50
+ import numpy as np
51
+ from spintensor import solve_tensor_constraints
52
+
53
+ # Define operations in [Rs, Rr] format
54
+ # Rs: spin-space matrix; Rr: real-space matrix
55
+ n = 3 # dimension
56
+ r = 2 # tensor rank
57
+
58
+ # Spin reflection (det(Rs) = -1) in spin space, identity in real space
59
+ Rs = np.diag([1., 1., -1.]) # det = -1
60
+ Rr = np.eye(3) # det = +1
61
+
62
+ # T-odd tensor: sign_T = det(Rs)**1 = -1
63
+ A, nullspace, relations, components = solve_tensor_constraints(
64
+ [[Rs, Rr]], n, r, T_constraint=1, P_constraint=0
65
+ )
66
+
67
+ print(f"Independent components: {nullspace.shape[1]}")
68
+ for rel in relations:
69
+ print(f" {rel}")
70
+ ```
71
+
72
+ ## Input Formats
73
+
74
+ All transformation formats are supported. The `[Rs, Rr]` format is the primary API for the new per-operation sign convention:
75
+
76
+ ### Format 1: `[Rs, Rr]` (recommended)
77
+
78
+ ```python
79
+ # Each entry is [spin_matrix, real_space_matrix]
80
+ transformations = [
81
+ [Rs1, Rr1], # sign_T = det(Rs1)**T_constraint, sign_P = det(Rr1)**P_constraint
82
+ [Rs2, Rr2],
83
+ ]
84
+ ```
85
+
86
+ With `spin_axes` set, `Rs` is also applied to the specified tensor axes.
87
+
88
+ ### Format 2: `[Tflag, Rr]` (explicit anti-unitary flag)
89
+
90
+ ```python
91
+ # Tflag=True means the operation is anti-unitary (contributes sign_T=-1 when T_constraint=1)
92
+ transformations = [
93
+ [False, Rr_unitary], # sign_T = +1
94
+ [True, Rr_antiunitary], # sign_T = -1
95
+ ]
96
+ ```
97
+
98
+ ### Format 3: `Rr` only (no spin component)
99
+
100
+ ```python
101
+ # Single numpy array: treated as Rs = identity (det=+1, no T sign)
102
+ transformations = [Rr1, Rr2] # sign_T = +1 always
103
+ ```
104
+
105
+ ### Format 4: Legacy `(R, s_T, s_P)` tuple
106
+
107
+ ```python
108
+ # Explicit parity values (backward compatible)
109
+ transformations = [(R, s_T, s_P)]
110
+ ```
111
+
112
+ ## API Reference
113
+
114
+ ### Main Function
115
+
116
+ #### `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)`
117
+
118
+ Complete solver for tensor constraints.
119
+
120
+ **Parameters:**
121
+ - `transformations`: List of transformations in any supported format
122
+ - `n`: int, dimension of the tensor space
123
+ - `r`: int, order (rank) of the tensor
124
+ - `symmetries`: list of tuples, optional index permutations for symmetric constraints (T_perm = T)
125
+ - `antisymmetries`: list of tuples, optional index permutations for antisymmetric constraints (T_perm = -T)
126
+ - `tol`: float, tolerance for numerical operations
127
+ - `spin_axes`: optional tuple of axis indices for spin axes (used with [Rs, Rr] format)
128
+ - `T_constraint`: int, exponent for time-reversal sign. `sign_T = det(Rs)**T_constraint`. Use `1` for T-odd tensors (default `0`)
129
+ - `P_constraint`: int, exponent for parity sign. `sign_P = det(Rr)**P_constraint`. Use `1` for P-odd/axial tensors (default `0`)
130
+ - `det_tol`: float, tolerance for determinant comparison to ±1
131
+
132
+ **Returns:**
133
+ - `constraint_matrix`: numpy array, full constraint matrix
134
+ - `nullspace_basis`: numpy array, columns are basis vectors
135
+ - `latex_relations`: list of strings, formatted LaTeX relations
136
+ - `tensor_components`: nested list of component expressions
137
+
138
+ ### Convenience Functions
139
+
140
+ #### `solve_qmd(transformations, n=3, tol=1e-10)`
141
+
142
+ Solve for QMD (quadrupole moment derivative) tensors: T-odd, rank-3, with last-two-index symmetry.
143
+
144
+ #### `solve_imd(transformations, n=3, tol=1e-10)`
145
+
146
+ Solve for IMD tensors: T-odd, rank-3, with both last-two and first-two index symmetry.
147
+
148
+ #### `solve_bcd(transformations, n=3, tol=1e-10, use_cyclic_constraint=True)`
149
+
150
+ Solve for BCD (Berry curvature dipole) tensors: T-even, rank-3, with last-two-index symmetry and optional cyclic sum constraint.
151
+
152
+ ### Core Functions
153
+
154
+ #### `build_constraint_matrix(transformations, n, r, ...)`
155
+
156
+ Build the full constraint matrix from transformations and symmetries.
157
+
158
+ #### `compute_nullspace_svd(A, tol=1e-10)`
159
+
160
+ Compute nullspace of matrix A using SVD.
161
+
162
+ #### `format_latex_relations(nullspace, n, r, tol=1e-10)`
163
+
164
+ Format nullspace basis vectors as readable LaTeX relations.
165
+
166
+ ## Examples
167
+
168
+ ### Example 1: AHE Conductivity (T-odd, polar, rank-2)
169
+
170
+ ```python
171
+ import numpy as np
172
+ from spintensor import solve_tensor_constraints
173
+
174
+ # Operations in [Rs, Rr] format
175
+ # T-odd tensor: sign_T = det(Rs)**1
176
+
177
+ ops = [
178
+ [np.diag([1., 1., 1.]), np.diag([1., 1., 1.])], # identity
179
+ [np.diag([1., 1., -1.]), np.diag([1., 1.,-1.])], # z-mirror: det(Rs)=-1 → s_T=-1
180
+ ]
181
+
182
+ A, nullspace, relations, comps = solve_tensor_constraints(
183
+ ops, n=3, r=2, T_constraint=1, P_constraint=0
184
+ )
185
+
186
+ print(f"Independent components: {nullspace.shape[1]}")
187
+ ```
188
+
189
+ ### Example 2: QMD Tensor with Spin-Group Operations
190
+
191
+ ```python
192
+ import numpy as np
193
+ from spintensor import solve_qmd
194
+
195
+ # Operations in [Rs, Rr] format
196
+ # Mirror op: det(Rs) = -1 → T-odd sign applies
197
+ s = np.sqrt(3) / 2
198
+ ops = [
199
+ [np.eye(3), np.eye(3)],
200
+ [np.array([[-0.5, s, 0], [s, 0.5, 0], [0, 0, 1]]),
201
+ np.array([[-0.5, s, 0], [s, 0.5, 0], [0, 0, 1]])],
202
+ # ... more operations
203
+ ]
204
+
205
+ A, nullspace, relations, comps = solve_qmd(ops)
206
+ ```
207
+
208
+ ### Example 3: P-odd (Axial) Tensor
209
+
210
+ ```python
211
+ import numpy as np
212
+ from spintensor import solve_tensor_constraints
213
+
214
+ # P_constraint=1: sign_P = det(Rr)**1
215
+ # For a reflection with det(Rr)=-1, this adds a -1 sign factor
216
+ R_reflect = np.diag([1., 1., -1.])
217
+
218
+ A, nullspace, relations, comps = solve_tensor_constraints(
219
+ [[np.eye(3), R_reflect]], n=3, r=2,
220
+ T_constraint=0, P_constraint=1
221
+ )
222
+ ```
223
+
224
+ ### Example 4: Legacy Format (Backward Compatible)
225
+
226
+ ```python
227
+ import numpy as np
228
+ from spintensor import solve_tensor_constraints
229
+
230
+ R_z = np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]])
231
+
232
+ # Legacy tuple format: (R, s_T, s_P) — explicit parity values
233
+ transformations = [(R_z, 1.0, 1.0)]
234
+ A, nullspace, relations, comps = solve_tensor_constraints(
235
+ transformations, n=3, r=2, symmetries=[(1, 0)]
236
+ )
237
+ ```
238
+
239
+ ## Mathematical Background
240
+
241
+ ### Operation-Dependent Sign Logic
242
+
243
+ For each operation `(Rs, Rr)`, the transformation matrix acting on the flattened tensor is:
244
+
245
+ ```
246
+ M = sign_T · sign_P · (Rr ⊗ Rr ⊗ ... ⊗ Rr)
247
+ ```
248
+
249
+ where:
250
+
251
+ ```
252
+ sign_T = det(Rs) ** T_constraint
253
+ sign_P = det(Rr) ** P_constraint
254
+ ```
255
+
256
+ The constraint for a symmetry-invariant tensor is `(M - I) · T = 0`.
257
+
258
+ **Physical interpretation:**
259
+ - `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`.
260
+ - `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`.
261
+ - These factors are **per-operation** — each operation in the symmetry group can independently flip or not flip each parity sign.
262
+
263
+ ### Index Symmetries
264
+
265
+ Index permutation symmetries impose additional constraints:
266
+ ```
267
+ (P_perm - I) · T = 0 (symmetric)
268
+ (P_perm + I) · T = 0 (antisymmetric)
269
+ ```
270
+
271
+ ### Nullspace Computation
272
+
273
+ The solution space consists of all tensors satisfying the constraints. This is the nullspace of the combined constraint matrix A, computed via SVD:
274
+
275
+ ```
276
+ A = U · Σ · Vᵀ
277
+ ```
278
+
279
+ 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.
280
+
281
+ ## Output Format
282
+
283
+ Relations are output in LaTeX format with automatic index notation:
284
+ - For n ≤ 4: uses letters (x, y, z, w)
285
+ - For n > 4: uses numbers (1, 2, 3, ...)
286
+
287
+ Example output:
288
+ ```
289
+ \sigma_{xxy} = \sigma_{xyx} = \sigma_{yxx} = -\sigma_{yyy}
290
+ \sigma_{xyz} = \sigma_{xzy} = -\sigma_{yxz} = -\sigma_{yzx}
291
+ ```
292
+
293
+ ## Requirements
294
+
295
+ - Python ≥ 3.7
296
+ - NumPy ≥ 1.19.0
297
+
298
+ ## License
299
+
300
+ MIT License
301
+
302
+ ## Contributing
303
+
304
+ Contributions are welcome! Please feel free to submit a Pull Request.
305
+
306
+ ## Citation
307
+
308
+ If you use this library in your research, please cite:
309
+
310
+ ```bibtex
311
+ @software{spintensor,
312
+ title = {SpinTensor: Linear Constraints for Tensors Under Transformations},
313
+ author = {Connor1y},
314
+ year = {2026},
315
+ url = {https://github.com/Connor1y/spintensor}
316
+ }
317
+ ```