Source code for edlgt.operators.bose_fermi_operators

"""Single-site bosonic and fermionic operator factories."""

import numpy as np
from scipy.sparse import csr_matrix, diags, identity

from edlgt.modeling import qmb_operator as qmb_op

__all__ = [
    "fermi_operators",
    "bose_operators",
]


[docs] def fermi_operators(has_spin, colors=False, fermionic=True): """Build single-site fermionic matter operators. Parameters ---------- has_spin : bool If ``True``, build two-component (up/down) matter operators. colors : bool, optional If ``True``, provide ``r/g`` aliases for the two matter components. fermionic : bool, optional If ``True``, include fermionic parity operators/sign strings. Returns ------- dict Dictionary of single-site matter operators. """ ops = {} # Define the MATTER FIELDS OPERATORS ops["psi"] = diags(np.array([1], dtype=float), 1, (2, 2)) ops["psi_dag"] = ops["psi"].transpose() if fermionic: ops["P_psi"] = diags(np.array([1, -1], dtype=float), 0, (2, 2)) else: ops["P_psi"] = identity(2, dtype=float) ops["N"] = ops["psi_dag"] * ops["psi"] ops["ID_psi"] = identity(2, dtype=float) ops["ID"] = identity(2, dtype=float) ops["psi_dag_P"] = ops["psi_dag"] @ ops["P_psi"] if has_spin: # up & down MATTER OPERATORS ops["psi_down"] = qmb_op(ops, ["psi", "ID"]) ops["psi_up"] = qmb_op(ops, ["P_psi", "psi"]) ops["N_down"] = qmb_op(ops, ["N", "ID"]) ops["N_up"] = qmb_op(ops, ["ID", "N"]) # other number operators ops["N_pair"] = ops["N_up"] * ops["N_down"] ops["N_tot"] = ops["N_up"] + ops["N_down"] ops["N_single"] = ops["N_tot"] - 2 * ops["N_pair"] ops["N_zero"] = identity(4, dtype=float) - ops["N_pair"] - ops["N_single"] # identity on the whole matter site ops["ID_psi"] = identity(4, dtype=float) ops["P_psi"] = qmb_op(ops, ["P_psi", "P_psi"]) for spin_label in ["up", "down"]: ops[f"psi_{spin_label}_dag"] = ops[f"psi_{spin_label}"].transpose() ops[f"psi_{spin_label}_dag_P"] = ( ops[f"psi_{spin_label}_dag"] @ ops["P_psi"] ) if colors: ops["psi_r"] = ops["psi_up"] ops["psi_g"] = ops["psi_down"] ops["N_r"] = ops["N_up"] ops["N_g"] = ops["N_down"] for color_label in ["r", "g"]: ops[f"psi_{color_label}_dag"] = ops[f"psi_{color_label}"].transpose() ops[f"psi_{color_label}_dag_P"] = ( ops[f"psi_{color_label}_dag"] @ ops["P_psi"] ) else: ops["N_zero"] = ops["ID"] - ops["N"] return ops
[docs] def bose_operators(n_max): """Build bosonic ladder and number operators with onsite cutoff ``n_max``. Parameters ---------- n_max : int Maximum onsite occupation number. Returns ------- dict Dictionary containing ``b``, ``b_dagger``, ``N``, and ``N2``. """ ops = {} entries = np.arange(1, n_max + 1, 1) entries = np.sqrt(entries) x_coords = np.arange(0, n_max, 1) y_coords = np.arange(1, n_max + 1, 1) ops["b"] = csr_matrix((entries, (x_coords, y_coords)), shape=(n_max + 1, n_max + 1)) ops["b_dagger"] = csr_matrix(ops["b"].conj().transpose()) ops["N"] = ops["b_dagger"] * ops["b"] ops["N2"] = ops["N"] ** 2 return ops