'''
Allows one to parse physical operators created in the simulation.
'''
import numpy as np
[docs]
class Spectral:
'''
For the spectral statistics and its properties. Allows one to take a fraction of the data
and calculate the mean of the data.
'''
[docs]
@staticmethod
def diagonal_cutoff(Nh, nu, minimal_frac = 0.1):
'''
The diagonal cutoff for the spectral statistics
- Ns: system size
- Nh: Hilbert space dimension
- nu: number of eigenvalues - if it's less than 1, then it's a fraction of the Hilbert space dimension
- minimal_frac: minimal fraction of the Hilbert space dimension
Returns:
- The diagonal cutoff for the spectral statistics
'''
return min(int(minimal_frac * Nh), nu if nu >= 1 else int(nu * Nh))
[docs]
@staticmethod
def take_fraction(nu : float, data, middle = None):
'''
Take a fraction of the data for the spectral statistics.
- nu: number of eigenvalues - if it's less than 1, then it's a fraction of the Hilbert space dimension
- data: data to take the fraction from
- middle: middle of the data (if None, then it's the middle of the data)
Returns:
- The fraction of the data
'''
sizeData = len(data)
middle = sizeData // 2 if middle is None else middle
nu = Spectral.diagonal_cutoff(sizeData, nu)
return data[max(middle - nu // 2, 0) : min(middle + nu // 2, sizeData)]
[docs]
@staticmethod
def take_fraction_arr(nu : float, data, middle = None):
'''
Take a fraction of the data for the spectral statistics.
- nu: number of eigenvalues - if it's less than 1, then it's a fraction of the Hilbert space dimension
- data: data to take the fraction from
- middle: middle of the data (if None, then it's the middle of the data)
Returns:
- The fraction of the data
'''
sizeRep = data.shape[0]
sizeData = data.shape[-1]
middle = np.ones(sizeData) * sizeData // 2 if middle is None else middle
nu = Spectral.diagonal_cutoff(sizeData, nu)
out = np.array([data[i][max(middle[i] - nu // 2, 0) : min(middle[i] + nu // 2, sizeData)] for i in range(sizeRep)])
return out
[docs]
@staticmethod
def mean_fraction(nu : float, data, middle = None, axis = 0):
'''
Take a fraction of the data for the spectral statistics. Calculates the mean of the data.
- nu: number of eigenvalues - if it's less than 1, then it's a fraction of the Hilbert space dimension
- data: data to take the fraction from
- middle: middle of the data (if None, then it's the middle of the data)
- axis: axis to calculate the mean
Returns:
- The mean of the fraction of the data
'''
return np.mean(Spectral.take_fraction(nu, data, middle), axis = axis)
##########################
[docs]
class Operators:
'''
Operator class that contains the method to parse Operator names
both many-body and in single particle sector.
'''
OPERATOR_SEP = "/"
OPERATOR_SEP_CORR = "-"
OPERATOR_SEP_MULT = ","
OPERATOR_SEP_DIFF = "m"
OPERATOR_SEP_RANGE = ":"
OPERATOR_SEP_RANDOM = "r"
OPERATOR_SEP_DIV = "_"
OPERATOR_PI = "pi"
OPERATOR_SITE = "l"
OPERATOR_SITEU = "L"
OPERATOR_SITE_M_1 = True
# for Hilbert space dimension (if it's smaller, then for sure the value needs to be changed)
# to Full Hilbert space dimension
OPERATOR_ED_LIMIT = 16
##########################
[docs]
@staticmethod
def resolve_hilbert(Ns, local_hilbert = 2):
'''
Resolves the Hilbert space dimension based on the
inner limit -- OPERATOR_ED_LIMIT
'''
return local_hilbert**Ns if Ns <= Operators.OPERATOR_ED_LIMIT else Ns
##########################
[docs]
@staticmethod
def resolveSite(site : str, _dimension = 1):
"""
Parses and resolves a site identifier string into a numeric index or value.
This method handles special symbolic representations used in operator strings,
such as 'L' (system size), 'pi', and arithmetic operations like division or subtraction.
Parameters
----------
site : str
String representation of the site (e.g., "0", "L", "L_2", "L-1").
_dimension : int, default=1
The dimension or size of the system (L), used to resolve 'L' or 'l'.
Returns
-------
int or float
The resolved numeric value of the site or parameter.
Examples
--------
>>> Operators.resolveSite("0", 10)
0
>>> Operators.resolveSite("L", 10) # If OPERATOR_SITE_M_1 is True (default)
9
>>> Operators.resolveSite("L_2", 10) # L / 2
5
"""
if len(site) == 0:
return site
# check if site is L or l already - then return the dimension (L-1)
if site == Operators.OPERATOR_SITE or site == Operators.OPERATOR_SITEU:
return _dimension - (1 if Operators.OPERATOR_SITE_M_1 else 0)
# check if the site is PI
elif site == Operators.OPERATOR_PI:
return np.pi
# check if the site can be divided - then divide it
elif Operators.OPERATOR_SEP_DIV in site:
# contains L or l
_div = Operators.resolveSite(site.split(Operators.OPERATOR_SEP_DIV)[1], _dimension)
if Operators.OPERATOR_SITEU in site or Operators.OPERATOR_SITE in site:
return int(_dimension / _div)
# contains PI
elif Operators.OPERATOR_PI in site:
return np.pi / _div
# check if the site is a difference
elif Operators.OPERATOR_SEP_DIFF in site:
_diff = Operators.resolveSite(site.split(Operators.OPERATOR_SEP_DIFF)[1], _dimension)
return int(max(0.0, _dimension - _diff - (1 if Operators.OPERATOR_SITE_M_1 else 0)))
# simply return the site as a number
_siteInt = int(site)
if _siteInt < 0 or _siteInt >= _dimension:
raise Exception("The site: " + site + " is out of range. The dimension is: " + str(_dimension))
return int(site)
##########################
[docs]
@staticmethod
def resolve_operator(f_name, dimension):
"""
Resolves a full operator string by parsing the site component.
For an operator string like "Sz/L_2", this splits the string by the operator separator ('/'),
resolves the site part ("L_2" -> dimension/2), and reconstructs the string.
Parameters
----------
f_name : str
Operator name string.
dimension : int
System dimension/size.
Returns
-------
str
Resolved operator string (e.g., "Sz/5").
"""
if Operators.OPERATOR_SEP in f_name:
f_name_split = f_name.split(Operators.OPERATOR_SEP)
elem_part = f_name_split[-1]
return Operators.OPERATOR_SEP.join(f_name_split[:-1]) + Operators.OPERATOR_SEP + str(Operators.resolveSite(elem_part, dimension))
return f_name
##########################
[docs]
@staticmethod
def name2title(f_name):
"""Convert an encoded operator name into a LaTeX-style title."""
if Operators.OPERATOR_SEP in f_name:
f_name_split = f_name.split(Operators.OPERATOR_SEP)
elem_part = f_name_split[-1]
if Operators.OPERATOR_SEP_DIFF in elem_part:
elem_part= elem_part.replace("m", '-')
f_name_k = "${}^{{{}}}_{{{}}}$".format(f_name_split[0], elem_part, f_name)
return f_name_k