From 18ae3f3175eb0f391e85f09cc4b5d2b84a148abc Mon Sep 17 00:00:00 2001 From: bartandrews Date: Fri, 8 Nov 2024 13:40:38 +0100 Subject: [PATCH] closed-form expressions for gates --- python/ffsim/tenpy/circuits/gates.py | 110 ++++++++++++++++----------- 1 file changed, 66 insertions(+), 44 deletions(-) diff --git a/python/ffsim/tenpy/circuits/gates.py b/python/ffsim/tenpy/circuits/gates.py index d4b0b202d..c76cfcf34 100644 --- a/python/ffsim/tenpy/circuits/gates.py +++ b/python/ffsim/tenpy/circuits/gates.py @@ -12,7 +12,6 @@ import math import numpy as np -import scipy as sp import tenpy.linalg.np_conserved as npc from tenpy.algorithms.tebd import TEBDEngine from tenpy.linalg.charges import LegPipe @@ -26,7 +25,6 @@ # ruff: noqa: N803, N806 # define sites -shfs_nosym = SpinHalfFermionSite(cons_N=None, cons_Sz=None) shfs = SpinHalfFermionSite(cons_N="N", cons_Sz="Sz") shfsc = LegPipe([shfs.leg, shfs.leg]) @@ -91,39 +89,53 @@ def givens_rotation( beta = -beta phi = beta - np.pi / 2 - # define operators - Id = shfs_nosym.get_op("Id").to_ndarray() - JW = shfs_nosym.get_op("JW").to_ndarray() - # alpha sector / up spins if spin in [Spin.ALPHA, Spin.ALPHA_AND_BETA]: - Cdu = shfs_nosym.get_op("Cdu").to_ndarray() - Cu = shfs_nosym.get_op("Cu").to_ndarray() - JWu = shfs_nosym.get_op("JWu").to_ndarray() - Nu = shfs_nosym.get_op("Nu").to_ndarray() - # - Ggate_a = ( - np.kron(sp.linalg.expm(1j * phi * Nu), Id) - @ sp.linalg.expm( - theta * (np.kron(Cdu @ JW, Cu @ JWu) - np.kron(Cu @ JW, Cdu @ JWu)) - ) - @ np.kron(sp.linalg.expm(-1j * phi * Nu), Id) - ) + # # Using TeNPy SpinHalfFermionSite(cons_N=None, cons_Sz=None) operators + # Ggate_a = ( + # np.kron(sp.linalg.expm(1j * phi * Nu), Id) + # @ sp.linalg.expm( + # theta * (np.kron(Cdu @ JW, Cu @ JWu) - np.kron(Cu @ JW, Cdu @ JWu)) + # ) + # @ np.kron(sp.linalg.expm(-1j * phi * Nu), Id) + # ) + Ggate_a = np.eye(16, dtype=complex) + c = math.cos(theta) + for i in [1, 3, 4, 6, 9, 11, 12, 14]: + Ggate_a[i, i] = c + s = -cmath.exp(-1j * phi) * math.sin(theta) + Ggate_a[1, 4] = -s + Ggate_a[3, 6] = -s + Ggate_a[9, 12] = s + Ggate_a[11, 14] = s + Ggate_a[4, 1] = np.conj(s) + Ggate_a[6, 3] = np.conj(s) + Ggate_a[12, 9] = -np.conj(s) + Ggate_a[14, 11] = -np.conj(s) # beta sector / down spins if spin in [Spin.BETA, Spin.ALPHA_AND_BETA]: - Cdd = shfs_nosym.get_op("Cdd").to_ndarray() - Cd = shfs_nosym.get_op("Cd").to_ndarray() - JWd = shfs_nosym.get_op("JWd").to_ndarray() - Nd = shfs_nosym.get_op("Nd").to_ndarray() - # - Ggate_b = ( - np.kron(sp.linalg.expm(1j * phi * Nd), Id) - @ sp.linalg.expm( - theta * (np.kron(Cdd @ JW, Cd @ JWd) - np.kron(Cd @ JW, Cdd @ JWd)) - ) - @ np.kron(sp.linalg.expm(-1j * phi * Nd), Id) - ) + # # Using TeNPy SpinHalfFermionSite(cons_N=None, cons_Sz=None) operators + # Ggate_b = ( + # np.kron(sp.linalg.expm(1j * phi * Nd), Id) + # @ sp.linalg.expm( + # theta * (np.kron(Cdd @ JW, Cd @ JWd) - np.kron(Cd @ JW, Cdd @ JWd)) + # ) + # @ np.kron(sp.linalg.expm(-1j * phi * Nd), Id) + # ) + Ggate_b = np.eye(16, dtype=complex) + c = math.cos(theta) + for i in [2, 3, 6, 7, 8, 9, 12, 13]: + Ggate_b[i, i] = c + s = -cmath.exp(-1j * phi) * math.sin(theta) + Ggate_b[2, 8] = -s + Ggate_b[3, 9] = s + Ggate_b[6, 12] = -s + Ggate_b[7, 13] = s + Ggate_b[8, 2] = np.conj(s) + Ggate_b[9, 3] = -np.conj(s) + Ggate_b[12, 6] = np.conj(s) + Ggate_b[13, 7] = -np.conj(s) # define total gate if spin is Spin.ALPHA: @@ -163,13 +175,19 @@ def num_interaction(theta: float, spin: Spin) -> np.ndarray: # alpha sector / up spins if spin in [Spin.ALPHA, Spin.ALPHA_AND_BETA]: - Nu = shfs_nosym.get_op("Nu").to_ndarray() - Ngate_a = sp.linalg.expm(1j * theta * Nu) + # # Using TeNPy SpinHalfFermionSite(cons_N=None, cons_Sz=None) operators + # Ngate_a = sp.linalg.expm(1j * theta * Nu) + Ngate_a = np.eye(4, dtype=complex) + for i in [1, 3]: + Ngate_a[i, i] = np.exp(1j * theta) # beta sector / down spins if spin in [Spin.BETA, Spin.ALPHA_AND_BETA]: - Nd = shfs_nosym.get_op("Nd").to_ndarray() - Ngate_b = sp.linalg.expm(1j * theta * Nd) + # # Using TeNPy SpinHalfFermionSite(cons_N=None, cons_Sz=None) operators + # Ngate_b = sp.linalg.expm(1j * theta * Nd) + Ngate_b = np.eye(4, dtype=complex) + for i in [2, 3]: + Ngate_b[i, i] = np.exp(1j * theta) # define total gate if spin is Spin.ALPHA: @@ -201,12 +219,10 @@ def on_site_interaction(theta: float) -> np.ndarray: The on-site interaction gate in the TeNPy (N, Sz)-symmetry-conserved basis. """ - # define operators - Nu = shfs_nosym.get_op("Nu").to_ndarray() - Nd = shfs_nosym.get_op("Nd").to_ndarray() - - # define total gate - OSgate = sp.linalg.expm(1j * theta * Nu @ Nd) + # # Using TeNPy SpinHalfFermionSite(cons_N=None, cons_Sz=None) operators + # OSgate = sp.linalg.expm(1j * theta * Nu @ Nd) + OSgate = np.eye(4, dtype=complex) + OSgate[3, 3] = np.exp(1j * theta) # convert to (N, Sz)-symmetry-conserved basis OSgate_sym = sym_cons_basis(OSgate) @@ -237,13 +253,19 @@ def num_num_interaction(theta: float, spin: Spin) -> np.ndarray: # alpha sector / up spins if spin in [Spin.ALPHA, Spin.ALPHA_AND_BETA]: - Nu = shfs_nosym.get_op("Nu").to_ndarray() - NNgate_a = sp.linalg.expm(1j * theta * np.kron(Nu, Nu)) + # # Using TeNPy SpinHalfFermionSite(cons_N=None, cons_Sz=None) operators + # NNgate_a = sp.linalg.expm(1j * theta * np.kron(Nu, Nu)) + NNgate_a = np.eye(16, dtype=complex) + for i in [5, 7, 13, 15]: + NNgate_a[i, i] = np.exp(1j * theta) # beta sector / down spins if spin in [Spin.BETA, Spin.ALPHA_AND_BETA]: - Nd = shfs_nosym.get_op("Nd").to_ndarray() - NNgate_b = sp.linalg.expm(1j * theta * np.kron(Nd, Nd)) + # # Using TeNPy SpinHalfFermionSite(cons_N=None, cons_Sz=None) operators + # NNgate_b = sp.linalg.expm(1j * theta * np.kron(Nd, Nd)) + NNgate_b = np.eye(16, dtype=complex) + for i in [10, 11, 14, 15]: + NNgate_b[i, i] = np.exp(1j * theta) # define total gate if spin is Spin.ALPHA: