inv¶
Invert a diagonal matrix tensor.
inv
¶
Invert a diagonal matrix tensor.
Takes a diagonal matrix tensor and returns its inverse by inverting each diagonal element. For charge conservation, the input tensor must have opposite index directions.
Supports both Abelian groups (U1Group, Z2Group, etc.) and non-Abelian groups (SU2Group, ProductGroup with SU2Group). For non-Abelian tensors, blocks carry a trailing outer-multiplicity (OM) dimension and an intertwiner (intw) field; both are handled correctly and preserved in the output.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tensor
|
Tensor
|
Input diagonal matrix tensor with exactly 2 indices. If labeled "Diagonal", the diagonal structure check is skipped. |
required |
Returns:
| Type | Description |
|---|---|
Tensor
|
Inverted diagonal matrix with the same structure as input, including the intertwiner field for non-Abelian tensors. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If tensor does not have exactly 2 indices, or if tensor is not diagonal (when label != "Diagonal"). |
ZeroDivisionError
|
If any diagonal element is zero (within machine epsilon). |
Examples:
>>> from nicole import Tensor, Index, Sector, Direction, U1Group, diag
>>> from nicole.decomp import svd
>>> import torch
>>> # Create a diagonal tensor from SVD
>>> T = Tensor.random([idx_i, idx_j], itags=["i", "j"])
>>> U, S_blocks, Vh = svd(T, axis=0)
>>> S_diag = diag(S_blocks, U.indices[1])
>>>
>>> # Invert the diagonal matrix
>>> S_inv = inv(S_diag)
>>>
>>> # Verify: S @ S_inv should give identity
>>> from nicole import contract
>>> result = contract(S_diag, S_inv)
>>> # Manual diagonal tensor (Abelian)
>>> idx = Index(Direction.IN, U1Group(), (Sector(0, 2),))
>>> D = Tensor(
... indices=(idx.flip(), idx),
... itags=("i", "j"),
... data={(0, 0): torch.diag(torch.tensor([2.0, 4.0]))},
... label="Diagonal"
... )
>>> D_inv = inv(D)
>>> D_inv.data[(0, 0)]
array([[0.5 , 0. ],
[0. , 0.25]])
>>> # SU(2) diagonal tensor (non-Abelian)
>>> from nicole import SU2Group
>>> group = SU2Group()
>>> idx = Index(Direction.IN, group, (Sector(1, 2),))
>>> S_blocks_su2 = {(1, 1): torch.tensor([2.0, 0.5])}
>>> S_diag_su2 = diag(S_blocks_su2, idx)
>>> S_inv_su2 = inv(S_diag_su2)
>>> # S_inv_su2.intw is preserved with same weights as S_diag_su2
Notes
The function inverts each diagonal matrix block independently by computing 1/x for each diagonal element. Off-diagonal elements are assumed to be zero (only checked if label != "Diagonal").
For non-Abelian (SU(2)) tensors, blocks have shape (n, n, 1) with a trailing OM dimension. The diagonal is extracted from block[:, :, 0], and the output block is reconstructed with the same trailing dimension. The intertwiner (Bridge) weights encode the irrep normalisation √(irrep_dim) and are unchanged by inversion; new Bridge objects are built with the transposed index directions.
For numerical stability, elements with absolute value below machine epsilon for float64 will raise ZeroDivisionError.
Description¶
Takes a diagonal matrix tensor and returns its inverse by inverting each diagonal element. The function handles diagonal tensors created by diag() or manually constructed diagonal matrices.
For charge conservation, the output tensor has transposed index structure (swapped and flipped indices) compared to the input.
Usage¶
from nicole import decomp, diag, inv, contract
# Create diagonal tensor from SVD
U, S_blocks, Vh = decomp(T, axes=0, mode="SVD")
S_diag = diag(S_blocks, U.indices[1])
# Invert the diagonal matrix
S_inv = inv(S_diag)
# Verify: S @ S_inv should give identity (approximately)
result = contract(S_diag, S_inv)
Manual Diagonal Tensor¶
import torch
from nicole import Tensor, Index, Sector, Direction, U1Group, inv
group = U1Group()
idx = Index(Direction.IN, group, sectors=(Sector(0, 2),))
# Create manual diagonal tensor
D = Tensor(
indices=(idx.flip(), idx),
itags=("i", "j"),
data={(0, 0): torch.diag(torch.tensor([2.0, 4.0]))},
label="Diagonal"
)
# Invert it
D_inv = inv(D)
# D_inv.data[(0, 0)] = [[0.5, 0], [0, 0.25]]
See Also¶
Notes¶
- Input tensor must have exactly 2 indices
- Each block must be a square diagonal matrix
- Diagonal elements must be non-zero (raises ZeroDivisionError otherwise)
- If tensor label is "Diagonal", diagonal structure check is skipped for efficiency
- Output tensor has transposed index structure for charge conservation