Source code for qmctorch.wavefunction.pooling.orbital_projector

import torch


[docs]class OrbitalProjector: def __init__(self, configs, mol, cuda=False): """Project the MO matrix in Slater Matrices Args: configs (list): configurations of the slater determinants mol (Molecule): Molecule object cuda (bool): use cuda or not """ self.configs = configs self.nconfs = len(configs[0]) self.nmo = mol.basis.nmo self.nup = mol.nup self.ndown = mol.ndown self.device = torch.device('cpu') if cuda: self.device = torch.device('cuda')
[docs] def get_projectors(self): """Get the projectors of the conf in the CI expansion Returns: torch.tensor, torch.tensor : projectors """ Pup = torch.zeros(self.nconfs, self.nmo, self.nup) Pdown = torch.zeros(self.nconfs, self.nmo, self.ndown) for ic, (cup, cdown) in enumerate( zip(self.configs[0], self.configs[1])): for _id, imo in enumerate(cup): Pup[ic][imo, _id] = 1. for _id, imo in enumerate(cdown): Pdown[ic][imo, _id] = 1. return Pup.unsqueeze(1).to(self.device), Pdown.unsqueeze(1).to(self.device)
[docs] def split_orbitals(self, mat): """Split the orbital matrix in multiple slater matrices Args: mat (torch.tensor): matrix to split Returns: torch.tensor: all slater matrices """ if not hasattr(self, 'Pup'): self.Pup, self.Pdown = self.get_projectors() if mat.ndim == 4: # case for multiple operators out_up = mat[..., :self.nup, :] @ self.Pup.unsqueeze(1) out_down = mat[..., self.nup:, :] @ self.Pdown.unsqueeze(1) else: # case for single operator out_up = mat[..., :self.nup, :] @ self.Pup out_down = mat[..., self.nup:, :] @ self.Pdown return out_up, out_down
[docs]class ExcitationMask: def __init__(self, unique_excitations, mol, max_orb, cuda=False): """Select the occupied MOs of Slater determinant using masks Args: unique_excitations (list): the list of unique excitations mol (Molecule): Molecule object max_orb (list): the max index of each orb for each spin cuda (bool): use cuda or not """ self.unique_excitations = unique_excitations self.num_unique_exc = len(unique_excitations[0]) self.nmo = mol.basis.nmo self.nup = mol.nup self.ndown = mol.ndown self.nelec = mol.nelec self.max_orb = max_orb self.device = torch.device('cpu') if cuda: self.device = torch.device('cuda')
[docs] def get_index_unique_single(self): """Computes the 1D index and permutation for the unique singles.""" ncol_up = self.max_orb[0]-self.nup ncol_down = self.max_orb[1]-self.ndown self.index_unique_single_up = [] self.index_unique_single_down = [] self.sign_unique_single_up = [] self.sign_unique_single_down = [] for exc_up, exc_down in zip(self.unique_excitations[0], self.unique_excitations[1]): if len(exc_up[0]) == 1: ielec, iorb = exc_up[0][0], exc_up[1][0] icol = iorb-self.nup self.index_unique_single_up.append( ielec*ncol_up + icol) npermut = self.nup-ielec-1 self.sign_unique_single_up.append((-1)**(npermut)) if len(exc_down[1]) == 1: ielec, iorb = exc_down[0][0], exc_down[1][0] icol = iorb-self.ndown self.index_unique_single_down.append( ielec*ncol_down + icol) npermut = self.ndown-ielec-1 self.sign_unique_single_down.append((-1)**(npermut)) self.sign_unique_single_up = torch.as_tensor( self.sign_unique_single_up).to(self.device) self.sign_unique_single_down = torch.as_tensor( self.sign_unique_single_down).to(self.device)
[docs] def get_index_unique_double(self): """Computes the 1D index of the double excitation matrices.""" ncol_up = self.max_orb[0]-self.nup ncol_down = self.max_orb[1]-self.ndown self.index_unique_double_up = [] self.index_unique_double_down = [] for exc_up, exc_down in zip(self.unique_excitations[0], self.unique_excitations[1]): if len(exc_up[0]) == 2: for ielec in exc_up[0]: for iorb in exc_up[1]: icol = iorb-self.nup self.index_unique_double_up.append( ielec*ncol_up + icol) if len(exc_down[1]) == 2: for ielec in exc_up[0]: for iorb in exc_up[1]: icol = iorb-self.ndown self.index_unique_double_down.append( ielec*ncol_down + icol)