"""Hamiltonian classe implementation for large systems.
Copyright © 2019-2023 HQS Quantum Simulations GmbH. All Rights Reserved.
"""
from typing import Optional, Callable, Type
from .abstractHamiltonian import Hamiltonian
import numpy as np
from warnings import warn
[docs]
class HamiltonianLinearOperator(Hamiltonian):
r"""Hamiltonian implementation via directly providing the linear operator."""
[docs]
def __init__(
self,
linearOp: Callable,
dim: int,
dtype: Type,
total_volume: float,
velocity_times_hbar_operator: Optional[tuple[Callable, Callable, Callable]] = None,
disDict: Optional[dict] = None,
) -> None:
r"""Initialization of the Hamiltonian class based on a linear operator.
IMPORTANT: the linear operator provided should have the following signature:
linearOp(x: np.ndarray, res: np.ndarray) -> np.ndarray, where x and res are the input and
output arrays. The linear operator sohuld support both shapes (dim, ) or (dim, 1) for
the input and output arrays.
Args:
linearOp (Callable): Linear operator associated with the application of the
Hamiltonian.
dim (int): Total size fo the system.
dtype (Type): dtype of the system.
total_volume (float): total volume of the system.
velocity_times_hbar_operator (Optional[tuple[Callable, Callable, Callable]]): velocity
operator times ℏ in the x, y and z direction.
disDict (Optional[dict]): dictionary specifying the disorder.
"""
self.is_complex = True if dtype is complex else False
self.total_volume = total_volume
# since we have no control over how the matrix is constructed, we can't use these flags
# TODO: is there a way to make use of them in specific cases?
self.is_spin_matrix = False
self.is_BCS = False
# no difference between dim and realDim for now since we have no control over how the
# linear operator implements bcs (only case where this is needed)
# TODO: this might need fine-tuning, see above.
self.realDim = dim
self.dim = self.realDim
if velocity_times_hbar_operator is None:
# raise a warning to inform the user that conductivity calculations won't be available
# (or better, they will return nonsense)
message = "The velocity operator for the system has not been provided. "
message += "Conductivity calculations will return meaningless results."
warn(message, RuntimeWarning, stacklevel=2)
self.velocity_operator = velocity_times_hbar_operator
# disorder parsing done automatically
if disDict is None:
disDict = {}
self.parseDisDict(disDict)
self.scrambleW()
# scaling factors. These enter in the dot product directly -- they do not rescale the
# Hamiltonian itself.
self._set_scaling_and_cheby()
self.linOp: Callable = linearOp
[docs]
def dot(self, v: np.ndarray, out: np.ndarray) -> np.ndarray:
r"""Calculate the scalar product of H.
Args:
v (np.ndarray): vector to dot the Hamiltonian into.
out (np.ndarray): preallocated output array.
Returns:
np.ndarray: Dot product of H with v
"""
self.linOp(v, out)
out[:] = out + self.disLocPot.reshape(v.shape) * v
return out
[docs]
def generateSelector(self, what: str = "all") -> np.ndarray:
"""Generate selector given a certain input configuration.
Args:
what (str): input configuration.
Returns:
np.ndarray: array composed of 1's and 0's selecting the correct sublattice.
Raises:
ValueError: if the argument 'what' is invalid.
"""
# FIXME: this ONLY provides the "all" selector for now. A more specific approach should be
# implemented for the general case, probably passing the additional selectors in the init,
# since we have no info about the building of the Hamiltonian within this class.
vec = np.ones(self.dim, dtype=bool)
if what != "all":
raise ValueError(f"Invalid value {what!r} for argument 'what'.")
return vec