eig¶
Eigenvalue decomposition of square matrix tensors.
eig
¶
eig(
T: Tensor,
itag: Optional[str] = None,
order: Literal["ascend", "descend"] = "ascend",
trunc: Optional[Dict[str, Union[int, float]]] = None,
is_hermitian: bool = False,
) -> Tuple[Tensor, MutableMapping[BlockKey, torch.Tensor]]
Perform eigenvalue decomposition of a square matrix tensor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
T
|
Tensor
|
Square matrix tensor to be decomposed. Must have exactly 2 indices with matching charge structure (opposite directions). |
required |
itag
|
Optional[str]
|
Index tag for the bond dimension. If None, uses default tag "_bond_eig". |
None
|
order
|
Literal['ascend', 'descend']
|
Sorting order for eigenvalues. Either "ascend" for ascending order (smallest to largest) or "descend" for descending order (largest to smallest). Default is "ascend". For real eigenvalues, sorts by value (e.g., -5 < -3 < 1 < 2). For complex eigenvalues, sorts by real part. Sorting is applied per block and affects both truncation modes. |
'ascend'
|
trunc
|
Optional[Dict[str, Union[int, float]]]
|
Truncation specification as a dict. If None, no truncation. Supported keys:
|
None
|
is_hermitian
|
bool
|
If True, asserts that T is Hermitian and uses |
False
|
Returns:
| Type | Description |
|---|---|
tuple[Tensor, MutableMapping[BlockKey, Tensor]]
|
Pair
The decomposition satisfies: T @ U = U @ diag(D) for each block |
Raises:
| Type | Description |
|---|---|
ValueError
|
If T is not a square matrix, or if indices are not compatible, or if trunc format is invalid or contains unsupported modes. |
Notes
The eigenvalues are returned as 1D arrays for memory efficiency. Eigenvalues can be complex even for real matrices.
Sorting behavior:
- For real eigenvalues: sorts by actual value (e.g., -5 < -3 < 1 < 2)
- For complex eigenvalues: sorts by real part
- Use order="ascend" to get smallest/most negative eigenvalues first (e.g., ground states)
- Use order="descend" to get largest/most positive eigenvalues first
For "nkeep" mode, truncation respects the order parameter: with order="descend", keeps the n largest eigenvalues; with order="ascend", keeps the n smallest. For "thresh" mode, truncation is also order-aware: with order="descend", keeps eigenvalues >= threshold (most positive); with order="ascend", keeps eigenvalues <= threshold (most negative). Threshold filtering is applied per block.
When both modes are specified, "thresh" is applied first (per-block filtering), then "nkeep" is applied globally to the remaining eigenvalues.
The eigenvectors are stored in columns of U, normalized such that U is unitary (or as close as the eigendecomposition provides).
Examples:
>>> # No truncation, ascending order (default - smallest eigenvalues first)
>>> U, D_blocks = eig(T)
>>>
>>> # Descending order (largest eigenvalues first)
>>> U, D_blocks = eig(T, order="descend")
>>>
>>> # Keep 5 smallest (most negative) eigenvalues - useful for ground states
>>> U, D_blocks = eig(T, order="ascend", trunc={"nkeep": 5})
>>>
>>> # Keep 5 largest (most positive) eigenvalues
>>> U, D_blocks = eig(T, order="descend", trunc={"nkeep": 5})
>>>
>>> # Keep eigenvalues >= 0.1 (positive eigenvalues above threshold)
>>> U, D_blocks = eig(T, order="descend", trunc={"thresh": 0.1})
>>>
>>> # Keep eigenvalues <= -0.5 (negative eigenvalues below threshold)
>>> U, D_blocks = eig(T, order="ascend", trunc={"thresh": -0.5})
>>>
>>> # Apply both: keep eigenvalues >= 0.1, then keep top 5
>>> U, D_blocks = eig(T, order="descend", trunc={"thresh": 0.1, "nkeep": 5})
Description¶
Performs block-wise eigenvalue decomposition of a square matrix tensor, returning:
- U: Tensor containing eigenvectors as columns
- D: Dictionary mapping block keys to 1D eigenvalue arrays
The decomposition satisfies: T @ U = U @ diag(D) for each block.
Eigenvalues can be sorted in ascending or descending order, and truncation can be applied to keep only the most important eigenvalues (useful for finding ground states or dominant modes).
Parameters¶
T¶
Square matrix tensor to be decomposed. Must have exactly 2 indices with matching charge structure (opposite directions).
itag¶
Index tag for the bond dimension. If None, uses default tag "_bond_eig".
order¶
Sorting order for eigenvalues:
"ascend": Ascending order (smallest to largest) - default- For real eigenvalues: e.g., -5 < -3 < 1 < 2
- For complex eigenvalues: sorts by real part
- Use for finding ground states (most negative eigenvalues)
"descend": Descending order (largest to smallest)- Use for finding dominant modes (most positive eigenvalues)
is_hermitian¶
If True, asserts that T is Hermitian (real symmetric or complex Hermitian) and uses torch.linalg.eigh for each block instead of the general torch.linalg.eig. This guarantees:
- Real eigenvalues even for complex Hermitian inputs
- Orthonormal eigenvectors (U is exactly unitary), including in the presence of degeneracies
- Better numerical stability and performance
Default is False, which uses the general eigensolver and may return complex eigenvalues.
Tip
Always set is_hermitian=True when diagonalising Hamiltonians or density matrices — it is both faster and numerically more reliable.
trunc¶
Optional truncation specification as a dictionary:
"nkeep": Keep at most n eigenvalues globally- With
order="descend": keeps the n largest (most positive) - With
order="ascend": keeps the n smallest (most negative) "thresh": Keep eigenvalues relative to threshold per block- With
order="descend": keeps eigenvalues ≥ threshold - With
order="ascend": keeps eigenvalues ≤ threshold - Both can be specified: thresh applied first, then nkeep
Returns¶
tuple[Tensor, MutableMapping[BlockKey, torch.Tensor]]: Pair (U, D) where:
- U has indices
(row_index, bond_index)containing eigenvectors as columns - D is a dictionary mapping block keys to 1D arrays of eigenvalues
Import¶
(Not exported in public API)
Usage Examples¶
from nicole.decomp import eig
# No truncation, ascending order (default - smallest eigenvalues first)
U, D_blocks = eig(T)
# Descending order (largest eigenvalues first)
U, D_blocks = eig(T, order="descend")
# Keep 5 smallest (most negative) eigenvalues - useful for ground states
U, D_blocks = eig(T, order="ascend", trunc={"nkeep": 5})
# Keep 5 largest (most positive) eigenvalues
U, D_blocks = eig(T, order="descend", trunc={"nkeep": 5})
# Keep eigenvalues >= 0.1 (positive eigenvalues above threshold)
U, D_blocks = eig(T, order="descend", trunc={"thresh": 0.1})
# Keep eigenvalues <= -0.5 (negative eigenvalues below threshold)
U, D_blocks = eig(T, order="ascend", trunc={"thresh": -0.5})
# Apply both: keep eigenvalues >= 0.1, then keep top 5
U, D_blocks = eig(T, order="descend", trunc={"thresh": 0.1, "nkeep": 5})
# Hermitian eigensolver — real eigenvalues, orthonormal eigenvectors
U, D_blocks = eig(T, is_hermitian=True)
# Hermitian + keep 5 lowest eigenvalues (e.g. ground state and low-lying excitations)
U, D_blocks = eig(T, is_hermitian=True, order="ascend", trunc={"nkeep": 5})
See Also¶
Notes¶
- Eigenvalues are returned as 1D arrays for memory efficiency
- Eigenvalues can be complex even for real matrices
- Use
order="ascend"to find ground states (smallest/most negative eigenvalues) - Use
order="descend"to find dominant modes (largest/most positive eigenvalues) - For complex eigenvalues, sorting is by real part only
- When both thresh and nkeep specified: thresh is applied per-block first, then nkeep globally
- Use
is_hermitian=Truefor Hamiltonians and density matrices: eigenvalues are guaranteed real and eigenvectors are exactly orthonormal - Without
is_hermitian=True, eigenvalues may be complex and eigenvectors are only column-normalised