Source code for tlquantum.tt_gates

import tensorly as tl
tl.set_backend('pytorch')
from torch import randn, cos, sin, float32, complex64, exp
from torch.nn import Module, ModuleList, ParameterList, Parameter
from tensorly.tt_matrix import TTMatrix
from copy import deepcopy
from itertools import chain

from .tt_operators import identity
from .tt_precontraction import qubits_contract, _get_contrsets
from .tt_sum import tt_matrix_sum


# Author: Taylor Lee Patti <taylorpatti@g.harvard.edu>
# Author: Jean Kossaifi <jkossaifi@nvidia.com>

# License: BSD 3 clause


[docs]class Unitary(Module): """A unitary for all qubits in a TTCircuit, using tensor ring tensors with PyTorch Autograd support. Can be defined with arbitrary gates or used as a base-class for set circuit types. Parameters ---------- gates : list of TT gate classes, each qubit in the unitary to be involved in one gate. nqubits : int, number of qubits ncontraq : int, number of qubits to do pre-contraction over (simplifying contraciton path/using fewer indices) contrsets : list of lists of ints, the indices of qubit cores to merge in the pre-contraction path. device : string, device on which to run the computation. Returns ------- Unitary """ def __init__(self, gates, nqubits, ncontraq, contrsets=None, dtype=complex64, device=None): super().__init__() if contrsets is None: contrsets = _get_contrsets(nqubits, ncontraq) self.nqubits, self.ncontraq, self.contrsets, self.dtype, self.device = nqubits, ncontraq, contrsets, dtype, device self._set_gates(gates) def _set_gates(self, gates): """Sets the gate class instances as a PyTorch ModuleList for Unitary. """ self.gates = ModuleList(gates)
[docs] def forward(self): """Prepares the tensors of Unitary for forward contraction by calling the gate instances' forward method and doing qubit-wise (horizonal) pre-contraction. Returns ------- List of pre-contracted gate tensors for general forward pass. """ temp = [gate.forward() for gate in self.gates] if isinstance(temp[0], list): temp = temp[0] return qubits_contract(temp, self.ncontraq, contrsets=self.contrsets)
[docs]class BinaryGatesUnitary(Unitary): """A Unitary sub-class that generates a layer of a single two-qubit gates accross all qubits in a TTCircuit. Parameters ---------- nqubits : int, number of qubits ncontraq : int, number of qubits to do pre-contraction over (simplifying contraciton path/using fewer indices) q2gate : tuple of two gate instances, one for each qubit in gate. contrsets : list of lists of ints, the indices of qubit cores to merge in the pre-contraction path. device : string, device on which to run the computation. Returns ------- BinaryGatesUnitary """ def __init__(self, nqubits, ncontraq, q2gate, parity, contrsets=None, random_initialization=True): dtype, device = q2gate[0].dtype, q2gate[0].device super().__init__([], nqubits, ncontraq, contrsets=contrsets, dtype=dtype, device=device) self._set_gates(build_binary_gates_unitary(self.nqubits, q2gate, parity, dtype=dtype, random_initialization=random_initialization))
[docs]class UnaryGatesUnitary(Unitary): """A Unitary sub-class that generates a layer of unitary, single-qubit rotations. Parameters ---------- nqubits : int, number of qubits ncontraq : int, number of qubits to do pre-contraction over (simplifying contraciton path/using fewer indices) contrsets : list of lists of ints, the indices of qubit cores to merge in the pre-contraction path. device : string, device on which to run the computation. Returns ------- UnaryGatesUnitary """ def __init__(self, nqubits, ncontraq, axis='y', contrsets=None, dtype=complex64, device=None, random=False): super().__init__([], nqubits, ncontraq, contrsets=contrsets, dtype=dtype, device=device) if axis == 'y': self._set_gates([RotY(dtype=dtype, device=device, random=random) for i in range(self.nqubits)]) elif axis == 'x': self._set_gates([RotX(dtype=dtype, device=device, random=random) for i in range(self.nqubits)]) elif axis == 'z': self._set_gates([RotZ(dtype=dtype, device=device, random=random) for i in range(self.nqubits)]) else: raise IndexError('UnaryGatesUnitary has no rotation axis {}.\n' 'UnaryGatesUnitary has 3 rotation axes: x, y, and z. The y-axis is default.'.format(index))
class InvolutoryGeneratorUnitary(Unitary): """A Unitary sub-class that generates a unitary layer with a generator that is involutory (its own inverse). Parameters ---------- nqubits : int, number of qubits ncontraq : int, number of qubits to do pre-contraction over (simplifying contraciton path/using fewer indices) involutory_generator : list of tensors, involutory operator to use as generator contrsets : list of lists of ints, the indices of qubit cores to merge in the pre-contraction path. Returns ------- UnaryGatesUnitary """ def __init__(self, nqubits, ncontraq, involutory_generator, contrsets=None): dtype, device = involutory_generator[0].dtype, involutory_generator[0].device super().__init__([], nqubits, ncontraq, contrsets=contrsets, dtype=dtype, device=device) self._set_gates([InvolutoryGenerator(involutory_generator, nqubits, dtype=dtype, device=device)]) def build_binary_gates_unitary(nqubits, q2gate, parity, random_initialization=True, dtype=complex64): """Generate a layer of two-qubit gates. Parameters ---------- nqubits : int, number of qubits q2gate : tt-tensor, 2-core, 2-qubit gates to use in layer parity : int, if even, apply first q2gate core to even qubits, if odd, to odd qubits. Returns ------- Layer of two-qubit gates as list of tt-tensors """ def clone_gates(gate0, gate1, random_initialization): clone0, clone1 = deepcopy(gate0), deepcopy(gate1) if random_initialization: clone0.reinitialize(), clone1.reinitialize() return [clone0, clone1] q2gate0, q2gate1 = q2gate[0].type(dtype), q2gate[1].type(dtype) layer, device = [], q2gate0.device for i in range(nqubits//2 - 1): layer += clone_gates(q2gate0, q2gate1, random_initialization) if nqubits%2 == 0: temp = clone_gates(q2gate0, q2gate1, random_initialization) if parity%2 == 0: return layer+temp return [temp[1]]+layer+[temp[0]] temp = clone_gates(q2gate0, q2gate1, random_initialization) if parity%2 == 0: return layer+temp+[IDENTITY(dtype=dtype, device=device)] return [IDENTITY(dtype=dtype, device=device)]+layer+temp class InvolutoryGenerator(Module): """Qubit rotations about the involutory generator. Parameters ---------- nqubits : int, number of qubits. involutory_generator : list of tensors, involutory operator to use as generator. device : string, device on which to run the computation. Returns ------- InvolutoryGenerator """ def __init__(self, involutory_generator, nqubits, dtype=complex64, device=None): super().__init__() self.theta = Parameter(randn(1, device=device)) self.iden, self.involutory_generator = [identity(dtype=dtype, device=self.theta.device) for i in range(nqubits)], involutory_generator def forward(self): """Prepares the RotY gate for forward contraction by calling the forward method and preparing the tt-factorized form of rotation matrix depending on theta (which is typically updated every epoch through backprop via PyTorch Autograd). Returns ------- Gate tensor for general forward pass. """ temp_iden, temp_involutory_generator = [self.iden[0]*cos(self.theta)] + self.iden[1::], [self.involutory_generator[0]*1j*sin(self.theta)] + self.involutory_generator[1::] return tt_matrix_sum(temp_iden, temp_involutory_generator).factors
[docs]class RotY(Module): """Qubit rotations about the Y-axis with randomly initiated theta. Parameters ---------- device : string, device on which to run the computation. Returns ------- RotY """ def __init__(self, dtype=complex64, device=None, random=False): super().__init__() self.device, self.random = device, random self.theta = Parameter(randn(1, device=self.device)) self.iden, self.epy = identity(dtype=dtype, device=self.device), exp_pauli_y(dtype=dtype, device=self.device)
[docs] def forward(self): """Prepares the RotY gate for forward contraction by calling the forward method and preparing the tt-factorized form of rotation matrix depending on theta (which is typically updated every epoch through backprop via PyTorch Autograd). Returns ------- Gate tensor for general forward pass. """ if self.random == True: self.theta = Parameter(randn(1, device=self.device)) return self.iden*cos(self.theta/2)+self.epy*sin(self.theta/2)
[docs]class RotX(Module): """Qubit rotations about the X-axis with randomly initiated theta. Parameters ---------- device : string, device on which to run the computation. Returns ------- RotX """ def __init__(self, dtype=complex64, device=None, random=False): super().__init__() self.device, self.random = device, random self.theta = Parameter(randn(1, device=self.device)) self.iden, self.epx = identity(dtype=dtype, device=self.device), exp_pauli_x(dtype=dtype, device=self.device)
[docs] def forward(self): """Prepares the RotX gate for forward contraction by calling the forward method and preparing the tt-factorized form of rotation matrix depending on theta (which is typically updated every epoch through backprop via PyTorch Autograd). Returns ------- Gate tensor for general forward pass. """ if self.random == True: self.theta = Parameter(randn(1, device=self.device)) return self.iden*cos(self.theta/2)+self.epx*sin(self.theta/2)
[docs]class RotZ(Module): """Qubit rotations about the Z-axis with randomly initiated theta. Parameters ---------- device : string, device on which to run the computation. Returns ------- RotZ """ def __init__(self, dtype=complex64, device=None, random=False): super().__init__() self.device, self.random = device, random self.theta, self.dtype = Parameter(randn(1, device=self.device)), dtype self.iden, self.epz = identity(dtype=dtype, device=self.device), exp_pauli_z(dtype=dtype, device=self.device)
[docs] def forward(self): """Prepares the RotZ gate for forward contraction by calling the forward method and preparing the tt-factorized form of rotation matrix depending on theta (which is typically updated every epoch through backprop via PyTorch Autograd). Returns ------- Gate tensor for general forward pass. """ if self.random == True: self.theta = Parameter(randn(1, device=self.device)) return self.iden*cos(self.theta/2)+self.epz*sin(self.theta/2)
[docs]class IDENTITY(Module): """Identity gate (does not change the state of the qubit on which it acts). Parameters ---------- device : string, device on which to run the computation. Returns ------- IDENTITY """ def __init__(self, dtype=complex64, device=None): super().__init__() self.core, self.dtype, self.device = identity(dtype=dtype, device=device), dtype, device
[docs] def forward(self): """Prepares the left qubit of the IDENTITY gate for forward contraction by calling the forward method and preparing the tt-factorized form of matrix representation. Returns ------- Gate tensor for general forward pass. """ return self.core
class GPI2(Module): """Qubit rotation according to the GPI2 gates of the IonQ native architecture. Parameters ---------- device : string, device on which to run the computation. Returns ------- GPI2 """ def __init__(self, dtype=complex64, device=None): super().__init__() self.dtype, self.device, self.phi = dtype, device, Parameter(randn(1, device=device)) def forward(self): """Prepares the GPI2 gate for forward contraction by calling the forward method and preparing the tt-factorized form of rotation matrix depending on theta (which is typically updated every epoch through backprop via PyTorch Autograd). Returns ------- Gate tensor for general forward pass. """ return tl.tensor([[[[1],[-1j*exp(-1j*self.phi)]],[[-1j*exp(1j*self.phi)],[1]]]], dtype=self.dtype, device=self.device)
[docs]def cnot(dtype=complex64, device=None): """Pair of CNOT class instances, one left (control) and one right (transformed). Parameters ---------- device : string, device on which to run the computation. Returns ------- (CNOTL, CNOTR) """ return CNOTL(dtype=dtype, device=device), CNOTR(dtype=dtype, device=device)
[docs]class CNOTL(Module): """Left (control-qubit) core of a CNOT gate. Parameters ---------- device : string, device on which to run the computation. Returns ------- Left core of CNOT gate. """ def __init__(self, dtype=complex64, device=None): super().__init__() core, self.dtype, self.device = tl.zeros((1,2,2,2), dtype=dtype, device=device), dtype, device core[0,0,0,0] = core[0,1,1,1] = 1. self.core = core
[docs] def forward(self): """Prepares the left qubit of the CNOT gate for forward contraction by calling the forward method and preparing the tt-factorized form of matrix representation. Returns ------- Gate tensor for general forward pass. """ return self.core
def reinitialize(self): pass
[docs]class CNOTR(Module): """Right (transformed qubit) core of a CNOT gate. Parameters ---------- device : string, device on which to run the computation. Returns ------- Right core of CNOT gate. """ def __init__(self, dtype=complex64, device=None): super().__init__() core, self.dtype, self.device = tl.zeros((2,2,2,1), dtype=dtype, device=device), dtype, device core[0,0,0,0] = core[0,1,1,0] = 1. core[1,0,1,0] = core[1,1,0,0] = 1. self.core = core
[docs] def forward(self): """Prepares the right qubit of the CNOT gate for forward contraction by calling the forward method and preparing the tt-factorized form of matrix representation. Returns ------- Gate tensor for general forward pass. """ return self.core
def reinitialize(self): pass
[docs]def cz(dtype=complex64, device=None): """Pair of CZ class instances, one left (control) and one right (transformed). Parameters ---------- device : string, device on which to run the computation. Returns ------- (CZL, CZR) """ return CZL(dtype=dtype, device=device), CZR(dtype=dtype, device=device)
[docs]class CZL(Module): """Left (control-qubit) core of a CZ gate. Parameters ---------- device : string, device on which to run the computation. Returns ------- Left core of CZ gate. """ def __init__(self, dtype=complex64, device=None): super().__init__() core, self.dtype, self.device = tl.zeros((1,2,2,2), dtype=dtype, device=device), dtype, device core[0,0,0,0] = core[0,1,1,1] = 1. self.core = core
[docs] def forward(self): """Prepares the left qubit of the CZ gate for forward contraction by calling the forward method and preparing the tt-factorized form of matrix representation. Returns ------- Gate tensor for general forward pass. """ return self.core
def reinitialize(self): pass
[docs]class CZR(Module): """Right (transformed qubit) core of a CZ gate. Parameters ---------- device : string, device on which to run the computation. Returns ------- Right core of CZ gate. """ def __init__(self, dtype=complex64, device=None): super().__init__() core, self.dtype, self.device = tl.zeros((2,2,2,1), dtype=dtype, device=device), dtype, device core[0,0,0,0] = core[0,1,1,0] = core[1,0,0,0] = 1. core[1,1,1,0] = -1. self.core = core
[docs] def forward(self): """Prepares the right qubit of the CZ gate for forward contraction by calling the forward method and preparing the tt-factorized form of matrix representation. Returns ------- Gate tensor for general forward pass. """ return self.core
def reinitialize(self): pass
[docs]def so4(state1, state2, dtype=complex64, device=None): """Pair of SO4 two-qubit rotation class instances, with rotations over different states. Parameters ---------- state1 : int, the first of 4 quantum states to undergo the 2-qubit rotations state2 : int, the second of 4 quantum states to undergo the 2-qubit rotations device : string, device on which to run the computation. Returns ------- (SO4L, SO4R) """ R = SO4LR(state1, state2, 0, dtype=dtype, device=device) return R, SO4LR(state1, state2, 1, theta=R.theta, dtype=dtype, device=device)
[docs]class SO4LR(Module): """Left or right core of the two-qubit SO4 rotations gate. Parameters ---------- state1 : int, the first of 4 quantum states to undergo the 2-qubit rotations state2 : int, the second of 4 quantum states to undergo the 2-qubit rotations position : int, if 0, then left core, if 1, then right core. device : string, device on which to run the computation. Returns ------- if position == 0 --> SO4L if position == 1 --> SO4R """ def __init__(self, state1, state2, position, theta=None, dtype=complex64, device=None): super().__init__() self.theta, self.position, self.dtype, self.device = Parameter(randn(1, device=device)), position, dtype, device if theta is not None: self.theta.data = theta.data ind1, ind2 = min(state1, state2), max(state1, state2) if (ind1, ind2) == (0,1): self.core_generator = _so4_01 elif (ind1, ind2) == (1,2): self.core_generator = _so4_12 elif (ind1, ind2) == (2,3): self.core_generator = _so4_23 else: raise IndexError('SO4 Rotation Gates have no state interaction pairs {}.\n' 'Valid state interactions pairs are (0,1), (1,2), and (2,3)'.format((state1, state2)))
[docs] def forward(self): """Prepares the left or right qubit of the SO4 two-qubit rotation gate for forward contraction by calling the forward method and preparing the tt-factorized form of matrix representation. Update is based on theta (which is typically updated every epoch through backprop via Pytorch Autograd). Returns ------- Gate tensor for general forward pass. """ return self.core_generator(self.theta, dtype=self.dtype, device=self.device)[self.position]
def reinitialize(self): self.theta.data = randn(1, device=self.device)
def _so4_01(theta, dtype=complex64, device=None): """Two-qubit SO4 gates in tt-tensor form with rotations along zeroth and first qubit states. Parameters ---------- theta : PyTorch parameter, angle about which to rotate qubit, optimizable with PyTorch Autograd device : string, device on which to run the computation. Returns ------- (SO4_01_L, SO4_01_R) """ core0, core1 = tl.zeros((1,2,2,2), dtype=dtype, device=device), tl.zeros((2,2,2,1), dtype=dtype, device=device) core0[0,0,0,0] = core1[0,0,0,0] = core1[0,1,1,0] = 1 core0[0,1,1,1] = 1 core1[1,0,0,0] = core1[1,1,1,0] = cos(theta) core1[1,0,1,0] = -sin(theta) core1[1,1,0,0] = sin(theta) return [core0, core1] def _so4_12(theta, dtype=complex64, device=None): ### Is rank 4, not rank 6, but rank 4 decomposition non-trivial. """Two-qubit SO4 gates in tt-tensor form with rotations along first and second qubit states. Parameters ---------- theta : PyTorch parameter, angle about which to rotate qubit, optimizable with PyTorch Autograd device : string, device on which to run the computation. Returns ------- (SO4_12_L, SO4_12_R) """ core1, core2 = tl.zeros((1,2,2,2), dtype=dtype, device=device), tl.zeros((2,2,2,1), dtype=dtype, device=device) core1[0,0,0,0] = core1[0,1,1,1] = core2[0,0,0,0] = core2[1,1,1,0] = 1 T03I = [core1, core2] core1, core2 = tl.zeros((1,2,2,2), dtype=dtype, device=device), tl.zeros((2,2,2,1), dtype=dtype, device=device) core1[0,1,1,0] = core1[0,0,0,1] = core2[0,0,0,0] = core2[1,1,1,0] = 1 T12I = [core1*cos(theta), core2] core1, core2 = tl.zeros((1,2,2,2), dtype=dtype, device=device), tl.zeros((2,2,2,1), dtype=dtype, device=device) core1[0,1,0,0] = core1[0,0,1,1] = core2[0,0,1,0] = 1 core2[1,1,0,0] = -1 R12I = [core1*sin(theta), core2] return [*tt_matrix_sum(TTMatrix(T03I), tt_matrix_sum(TTMatrix(T12I), TTMatrix(R12I)))] def _so4_23(theta, dtype=complex64, device=None): """Two-qubit SO4 gates in tt-tensor form with rotations along second and third qubit states. Parameters ---------- theta : PyTorch parameter, angle about which to rotate qubit, optimizable with PyTorch Autograd device : string, device on which to run the computation. Returns ------- (SO4_23_L, SO4_23_R) """ core0, core1 = tl.zeros((1,2,2,2), dtype=dtype, device=device), tl.zeros((2,2,2,1), dtype=dtype, device=device) core0[0,1,1,0] = core1[0,0,0,0] = core1[0,1,1,0] = 1 core0[0,0,0,1] = 1 core1[1,0,0,0] = core1[1,1,1,0] = cos(theta) core1[1,0,1,0] = -sin(theta) core1[1,1,0,0] = sin(theta) return [core0, core1] def o4_phases(phases=None, dtype=complex64, device=None): """Pair of O4 phase rotations class instances. Each of four phases is imparted to each of the 4 states of O4. Parameters ---------- phases : list of floats, the four phases to be imparted to the quantum states device : string, device on which to run the computation. Returns ------- (O4L, O4R) """ L = O4LR(0, phases=phases, dtype=dtype, device=device) phases = L.phases return [L, O4LR(1, phases=phases, dtype=dtype, device=device)]
[docs]class O4LR(Module): """Left and right core of the two-qubit O4 phase gate. Parameters ---------- phases : list of floats, the four phases to be imparted to the quantum states device : string, device on which to run the computation. Returns ------- Two-qubit unitary with general phase rotations for O4. """ def __init__(self, position, phases=None, dtype=complex64, device=None): super().__init__() self.phases = [Parameter(randn(1, device=device)), Parameter(randn(1, device=device)), Parameter(randn(1, device=device)), Parameter(randn(1, device=device))] self.position, self.dtype, self.device = position, dtype, device if phases is not None: self.phases = [phases[0], phases[1], phases[2], phases[3]]
[docs] def forward(self): """Prepares the left or right qubit of the SO4 two-qubit rotation gate for forward contraction by calling the forward method and preparing the tt-factorized form of matrix representation. Update is based on theta (which is typically updated every epoch through backprop via Pytorch Autograd). Returns ------- Gate tensor for general forward pass. """ core1, core2 = tl.zeros((1,2,2,1), dtype=self.dtype, device=self.device), tl.zeros((1,2,2,1), dtype=self.dtype, device=self.device) core1[0,0,0,0] = 1 core2[0,0,0,0] = exp(1j*self.phases[0]) core2[0,1,1,0] = exp(1j*self.phases[1]) d0 = [core1, core2] core1, core2 = tl.zeros((1,2,2,1), dtype=self.dtype, device=self.device), tl.zeros((1,2,2,1), dtype=self.dtype, device=self.device) core1[0,1,1,0] = 1 core2[0,0,0,0] = exp(1j*self.phases[2]) core2[0,1,1,0] = exp(1j*self.phases[3]) d1 = [core1, core2] return tt_matrix_sum(d0, d1)[self.position]
def reinitialize(self): for phase in self.phases: phase.data = randn(1, device=self.device)
def ms(dtype=complex64, device=None): """Pair of MS class instances, as per the IonQ native gate architecture. Parameters ---------- device : string, device on which to run the computation. Returns ------- (MSL, MSR) """ return MSL(dtype=dtype, device=device), MSR(dtype=dtype, device=device) class MSL(Module): """Left core of a MS gate. Parameters ---------- device : string, device on which to run the computation. Returns ------- Left core of MS gate. """ def __init__(self, dtype=complex64, device=None): super().__init__() self.dtype, self.device = dtype, device core, self.dtype, self.device = tl.zeros((1,2,2,3), dtype=dtype, device=device), dtype, device core[0,0,0,0] = core[0,1,1,0] = core[0,0,1,1] = core[0,1,0,2] = 1 self.core = core def forward(self): """Prepares the left qubit of the MS gate for forward contraction by calling the forward method and preparing the tt-factorized form of matrix representation. Returns ------- Gate tensor for general forward pass. """ return self.core def reinitialize(self): pass class MSR(Module): """Right core of a MS gate. Parameters ---------- device : string, device on which to run the computation. Returns ------- Right core of MS gate. """ def __init__(self, theta=None, phi0=None, phi1=None, dtype=complex64, device=None): super().__init__() self.theta, self.phi0, self.phi1, self.dtype, self.device = Parameter(randn(1, device=device)), Parameter(randn(1, device=device)), Parameter(randn(1, device=device)), dtype, device if theta is not None: self.theta.data = theta.data if phi0 is not None: self.phi0.data = phi0.data if phi1 is not None: self.phi1.data = phi1.data core, self.dtype, self.device = tl.zeros((3,2,2,1), dtype=dtype, device=device), dtype, device c, s = cos(self.theta), -1j*sin(self.theta) core[0,0,0,0] = core[0,1,1,0] = c core[1,0,1,0] = s*exp(-1j*(self.phi0+self.phi1)) core[1,1,0,0] = s*exp(-1j*(self.phi0-self.phi1)) core[2,0,1,0] = s*exp(1j*(self.phi0-self.phi1)) core[2,1,0,0] = s*exp(1j*(self.phi0+self.phi1)) self.core = core def forward(self): """Prepares the right qubit of the MS gate for forward contraction by calling the forward method and preparing the tt-factorized form of matrix representation. Returns ------- Gate tensor for general forward pass. """ return self.core def reinitialize(self): self.theta.data = randn(1, device=self.device) self.phi0.data = randn(1, device=self.device) self.phi1.data = randn(1, device=self.device) def exp_pauli_y(dtype=complex64, device=None): """Matrix for sin(theta) component of Y-axis rotation in tt-tensor form. Parameters ---------- device : string, device on which to run the computation. Returns ------- tt-tensor core, sin(theta) Y-rotation component. """ return tl.tensor([[[[0],[-1]],[[1],[0]]]], dtype=dtype, device=device) def exp_pauli_x(dtype=complex64, device=None): """Matrix for sin(theta) component of X-axis rotation in tt-tensor form. Parameters ---------- device : string, device on which to run the computation. Returns ------- tt-tensor core, sin(theta) X-rotation component. """ return tl.tensor([[[[0],[-1j]],[[-1j],[0]]]], dtype=dtype, device=device) def exp_pauli_z(dtype=complex64, device=None): """Matrix for sin(theta) component of Z-axis rotation in tt-tensor form. Parameters ---------- device : string, device on which to run the computation. Returns ------- tt-tensor core, sin(theta) X-rotation component. """ return tl.tensor([[[[-1j],[0.]],[[0],[1j]]]], dtype=dtype, device=device)