Skip to content

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:

  • "nkeep": Keep at most n eigenvalues globally. With order="descend", keeps the n largest (most positive) eigenvalues. With order="ascend", keeps the n smallest (most negative) eigenvalues.
  • "thresh": Keep eigenvalues relative to threshold t per block. With order="descend", keeps eigenvalues >= t. With order="ascend", keeps eigenvalues <= t.
Both can be specified together: thresh is applied first, then nkeep.

None
is_hermitian bool

If True, asserts that T is Hermitian and uses torch.linalg.eigh for every block, guaranteeing real eigenvalues and orthonormal eigenvectors even in the presence of degeneracies. Works for both real symmetric and complex Hermitian blocks. Default is False.

False

Returns:

Type Description
tuple[Tensor, MutableMapping[BlockKey, Tensor]]

Pair (U, D) where:

  • U has indices (row_index, bond_index) containing eigenvectors as columns
  • D is a Dict mapping block keys to 1D arrays of eigenvalues

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

from nicole.decomp import eig

(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

  • decomp: High-level decomposition
  • svd: Low-level SVD function
  • qr: Low-level QR function

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=True for 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