Source code for ed_lgt.modeling.plaquette_term

"""
:class:`PlaquetteTerm` computes plaquette terms on a D>=2 lattice model, 
providing methods for their calculation and visualization. 
Plaquette terms are used to compute properties relevant to lattice gauge theories.
"""

import numpy as np
from math import prod
from scipy.sparse import isspmatrix, csr_matrix
from .lattice_geometry import get_plaquette_neighbors
from .lattice_mappings import zig_zag
from .qmb_operations import four_body_op
from .qmb_state import QMB_state
from .qmb_term import QMBTerm
from ed_lgt.tools import validate_parameters
from ed_lgt.symmetries import nbody_term
import logging

logger = logging.getLogger(__name__)

__all__ = ["PlaquetteTerm"]


[docs] class PlaquetteTerm(QMBTerm): def __init__(self, axes, op_list, op_names_list, print_plaq=True, **kwargs): """ This function introduce all the fundamental information to define a Plaquette Hamiltonian Term and possible eventual measures of it. Args: axes (list of str): list of 2 axes along which the Plaquette term should be applied op_list (list of 2 scipy.sparse.matrices): list of the two operators involved in the 2Body Term op_names_list (list of 2 str): list of the names of the two operators """ validate_parameters( axes=axes, op_list=op_list, op_names_list=op_names_list, print_plaq=print_plaq, ) # Preprocess arguments super().__init__(op_list=op_list, op_names_list=op_names_list, **kwargs) self.axes = axes self.print_plaq = print_plaq
[docs] def get_Hamiltonian(self, strength, add_dagger=False, mask=None): """ The function calculates the Plaquette Hamiltonian by summing up 4body terms for each lattice site, potentially with some sites excluded based on the mask. The result is scaled by the strength parameter before being returned. Eventually, it is possible to sum also the dagger part of the Hamiltonian. Args: strength (scalar): Coupling of the Hamiltonian term. add_dagger (bool, optional): If true, it add the hermitian conjugate of the resulting Hamiltonian. Defaults to False. mask (np.ndarray, optional): 2D array with bool variables specifying (if True) where to apply the local term. Defaults to None. Returns: scipy.sparse: Plaquette Hamiltonian term ready to be used for exact diagonalization/expectation values. """ # CHECK ON TYPES if not np.isscalar(strength): raise TypeError(f"strength must be SCALAR not a {type(strength)}") validate_parameters(add_dagger=add_dagger) # Define the Hamiltonian H_plaq = 0 for ii in range(prod(self.lvals)): # Compute the corresponding coords of the BL site of the Plaquette coords = zig_zag(self.lvals, ii) _, sites_list = get_plaquette_neighbors( coords, self.lvals, self.axes, self.has_obc ) if sites_list is None: continue # CHECK MASK CONDITION ON THE SITE if self.get_mask_conditions(coords, mask): # ADD THE TERM TO THE HAMILTONIAN if self.sector_configs is None: H_plaq += strength * four_body_op( op_list=self.op_list, op_sites_list=sites_list, **self.def_params, ) else: H_plaq += strength * nbody_term( self.sym_ops, np.array(sites_list), self.sector_configs ) if not isspmatrix(H_plaq): H_plaq = csr_matrix(H_plaq) if add_dagger: H_plaq += csr_matrix(H_plaq.conj().transpose()) return H_plaq
[docs] def get_expval(self, psi, get_imag=False, stag_label=None): """ The function calculates the expectation value (and it variance) of the Plaquette Hamiltonian and its average over all the lattice sites. Args: psi (numpy.ndarray): QMB state where the expectation value has to be computed get_imag(bool, optional): if true, it results the imaginary part of the expectation value, otherwise, the real part. Default to False. stag_label (str, optional): if odd/even, then the expectation value is performed only on that kind of sites. Defaults to None. Raises: TypeError: If the input arguments are of incorrect types or formats. """ # Check on parameters if not isinstance(psi, QMB_state): raise TypeError(f"psi must be instance of class:QMB_state not {type(psi)}") validate_parameters(stag_label=stag_label, get_imag=get_imag) # ADVERTISE OF THE CHOSEN PART OF THE PLAQUETTE YOU WANT TO COMPUTE if self.print_plaq: logger.info(f"----------------------------------------------------") if stag_label is None: logger.info(f"PLAQUETTE: {'_'.join(self.op_names_list)}") else: logger.info(f"PLAQUETTE: {'_'.join(self.op_names_list)}") logger.info(f"----------------------------------------------------") self.avg = 0.0 self.std = 0.0 counter = 0 for ii in range(prod(self.lvals)): # Compute the corresponding coords of the BL site of the Plaquette coords = zig_zag(self.lvals, ii) coords_list, sites_list = get_plaquette_neighbors( coords, self.lvals, self.axes, self.has_obc ) if sites_list is None: continue if self.get_staggered_conditions(coords, stag_label): if self.sector_configs is None: plaq = psi.expectation_value( four_body_op( op_list=self.op_list, op_sites_list=sites_list, **self.def_params, ) ) delta_plaq = ( psi.expectation_value( four_body_op( op_list=self.op_list, op_sites_list=sites_list, **self.def_params, ) ** 2, ) - plaq**2 ) else: plaq = psi.expectation_value( nbody_term( self.sym_ops, np.array(sites_list), self.sector_configs ) ) delta_plaq = ( psi.expectation_value( nbody_term( self.sym_ops, np.array(sites_list), self.sector_configs, ) ** 2 ) - plaq**2 ) # PRINT THE PLAQUETTE plaq_string = [f"{c}" for c in coords_list] if self.print_plaq: self.print_Plaquette(plaq_string, plaq) # Update the average and the variance counter += 1 self.avg += plaq self.std += delta_plaq self.avg = self.avg / counter self.std = np.sqrt(np.abs(self.std) / counter) if self.print_plaq: logger.info(f"{format(self.avg, '.10f')} +/- {format(self.std, '.10f')}")
[docs] def print_Plaquette(self, sites_list, value): if not isinstance(sites_list, list): raise TypeError(f"sites_list should be a LIST, not a {type(sites_list)}") if len(sites_list) != 4: raise ValueError(f"sites_list has 4 elements, not {str(len(sites_list))}") if not isinstance(value, float): raise TypeError(f"sites_list should be FLOAT, not a {type(value)}") if value > 0: value = format(value, ".10f") else: if np.abs(value) < 10 ** (-10): value = format(np.abs(value), ".10f") else: value = format(value, ".9f") logger.info(f"{sites_list[2]}------------{sites_list[3]}") logger.info(f" | |") logger.info(f" | {value} |") logger.info(f" | |") logger.info(f"{sites_list[0]}------------{sites_list[1]}") logger.info("")