Source code for qepsilon.operator_basis.tight_binding

"""
This module deals with tight binding operators and related operations.
"""

import torch as th
from qepsilon.utilities import compose

[docs] class TightBinding(th.nn.Module): """ This class deals with tight binding operators and related operations. """
[docs] def __init__(self, n_sites: int, pbc: bool = True): super().__init__() """ Initialize the tight binding operator class. Args: n_sites: the number of sites. """ self.ns = n_sites self.pbc = pbc ## A list of possible operators. No matrix needed to be stored since there won't be any kronecker product. Values are meaningless. self.register_buffer("L", None) self.register_buffer("R", None) self.register_buffer("X", th.zeros(2,2, dtype=th.cfloat)) self.register_buffer("N", None)
[docs] def get_composite_ops(self, name_sequence: str): r""" Returns a composite tight binding operator as a matrix. Args: name_sequence (str): A string of tight binding operator names, one per site. Allowed characters are: - "X": identity operator on the site - "L": hopping to the left (from site i to site i-1) - "R": hopping to the right (from site i to site i+1) - "N": number operator on the site The string must have length equal to the number of sites, and contain at most one non-"X" character. Examples: (1) "XXLXX": :math:`| 2\rangle\langle 3 |`, the particle on the third site hops to the left. (2) "XXRXX": :math:`| 4\rangle\langle 3 |`, the particle on the third site hops to the right. (3) "XXNXX": :math:`| 3\rangle\langle 3 |`, number operator for the third site. (4) "XXXXX": Identity operator for all sites (sum of projectors onto each site). Returns: torch.Tensor: The operator matrix of shape (n_sites, n_sites). """ ## assert there are only "X", "L", "R", "N" in the name_sequence, otherwise raise ValueError if not all(c in ["X", "L", "R", "N"] for c in name_sequence): raise ValueError("Only X, L, R, N are allowed in the name_sequence") ## assert the length of the name_sequence is n_sites if len(name_sequence) != self.ns: raise ValueError("The length of the name_sequence must be n_sites") ## find the position of the non-X character non_X_pos = [i for i, c in enumerate(name_sequence) if c != "X"] ## assert the non-X character is zero or one if len(non_X_pos) == 0: return th.eye(self.ns, dtype=th.cfloat, device=self.X.device) elif len(non_X_pos) == 1: op = name_sequence[non_X_pos[0]] else: raise ValueError("There must be exactly zero or one non-X character in the name_sequence") ## get the position of the site to be acted on idx = non_X_pos[0] op = name_sequence[idx] op_matrix = th.zeros(self.ns, self.ns, dtype=th.cfloat, device=self.X.device) if self.pbc is False: if op == "L": op_matrix[idx, idx-1] = 1 elif op == "R": op_matrix[idx, idx+1] = 1 elif op == "N": op_matrix[idx, idx] = 1 else: if op == "L": op_matrix[idx, (idx-1)%self.ns] = 1 elif op == "R": op_matrix[idx, (idx+1)%self.ns] = 1 elif op == "N": op_matrix[idx, idx] = 1 return op_matrix