Quantum gates

Common single-, two- and three-qubit gates used in quantum circuits, returned as TensorMaps on qubit spaces.

Conventions

Basis ordering

A qubit lives on a two-dimensional space with computational basis ordered as $\{|0⟩, |1⟩\}$.

Multi-qubit gates act on $V^{⊗n}$ with the first qubit as the leftmost tensor factor, so a controlled gate uses the first qubit(s) as control and the last as target.

Within a fused block, the index of $|b_1 b_2 … b_n⟩$ is $k = 1 + \sum_i b_i 2^{i-1}$, i.e. the first qubit runs fastest. Consequently block(gate, Trivial()) agrees element-for-element with the gate matrices as tabulated by e.g. Qiskit, identifying the first tensor factor with qubit 0.

Element types

The gates with complex matrix elements — pauli_y, phase_shift, s_gate, t_gate, rotation_x, rotation_z, u3, cy, cs, cphase, iswap, ecr, rotation_xx, rotation_yy, rotation_zz and rotation_zx — throw an ArgumentError when requested with a real eltype. All others are real-valued and honour any eltype, including exact ones such as Int.

Rotation angles

The parametrized gates take their rotation angle as a required theta keyword, e.g. rotation_x(; theta = π / 2). The universal single-qubit gate u3 takes the three angles theta, phi and lambda.

Symmetry sectors

SymmetryPhysical meaningSector labelRepresentable gates
Trivialnoneall gates, full $2^n × 2^n$ matrix
Z2Irrepexcitation-number paritycharge $n \bmod 2$ per qubitonly gates that conserve the number of $1$'s modulo 2
U1Irrepexcitation-number conservationcharge $∈ \{0, 1\}$ per qubitonly gates that conserve the number of $1$'s
U(1) charge = excitation number

Under U1Irrep the two sectors of a qubit carry charge $0$ ($|0⟩$) and $1$ ($|1⟩$), i.e. the conserved quantity is the number of excited qubits. Only number-conserving gates are representable in this symmetry: pauli_z, proj_0, proj_1, s_gate, t_gate, phase_shift, rotation_z, cz, cs, cphase, swap, iswap, rotation_zz and fredkin. Gates that flip qubits (X, Y, H, CNOT, Toffoli, …) throw an ArgumentError when requested with U1Irrep.

Z₂ charge = excitation parity

The $ℤ₂$ symmetry implemented here is the parity of the excitation number, which is diagonal in the computational basis — unlike the $ℤ₂$ of SpinOperators, which is the spin flip generated by $e^{iπS^x}$ and requires a change of basis. It is a weaker requirement than U1Irrep, so everything in the list above remains representable, and in addition rotation_xx and rotation_yy become available: $X ⊗ X$ and $Y ⊗ Y$ flip both qubits and hence preserve the total parity.

Gate combinators

controlled turns any gate into its controlled version $|0⟩⟨0| ⊗ I + |1⟩⟨1| ⊗ G$, inheriting the element type and the symmetry of G, and stacking arbitrarily: controlled(controlled(pauli_x())) is the toffoli gate. Together with the adjoint G' and the integer powers G^n of TensorKit, this covers the usual gate modifiers — inverse, power and control — where a gate controlled on $|0⟩$ follows from swapping the two projectors. The gates that are not provided in controlled form, such as the controlled rotations, are therefore one-liners:

crx = controlled(rotation_x(; theta = π / 2))

Gate overview

FunctionAlias(es)SitesSupported symmetries
qubit_spaceTrivial, Z2Irrep, U1Irrep
pauli_xX1Trivial
pauli_yY1Trivial
pauli_zZ1Trivial, Z2Irrep, U1Irrep
proj_0P01Trivial, Z2Irrep, U1Irrep
proj_1P11Trivial, Z2Irrep, U1Irrep
hadamardH1Trivial
s_gateS1Trivial, Z2Irrep, U1Irrep
t_gateT1Trivial, Z2Irrep, U1Irrep
phase_shiftP1Trivial, Z2Irrep, U1Irrep
rotation_xRx1Trivial
rotation_yRy1Trivial
rotation_zRz1Trivial, Z2Irrep, U1Irrep
u3U1Trivial
cnotCNOT, CX2Trivial
cyCY2Trivial
czCZ2Trivial, Z2Irrep, U1Irrep
chCH2Trivial
csCS2Trivial, Z2Irrep, U1Irrep
cphaseCP2Trivial, Z2Irrep, U1Irrep
swapSWAP2Trivial, Z2Irrep, U1Irrep
iswapISWAP2Trivial, Z2Irrep, U1Irrep
dcxDCX2Trivial
ecrECR2Trivial
rotation_xxRxx2Trivial, Z2Irrep
rotation_yyRyy2Trivial, Z2Irrep
rotation_zzRzz2Trivial, Z2Irrep, U1Irrep
rotation_zxRzx2Trivial
toffoliTOFFOLI, CCX3Trivial
fredkinFREDKIN, CSWAP3Trivial, Z2Irrep, U1Irrep

The adjoint gates $S^†$ and $T^†$ are obtained as s_gate()' and t_gate()'.

API

TensorKitTensors.QuantumGates.basis_transformMethod
basis_transform(symmetry::Type{<:Sector})

Return the unitary basis transformation that maps the computational basis $\{|0⟩, |1⟩\}$ of qubit_space(Trivial) onto the basis of qubit_space(symmetry), as a TensorMap from qubit_space(Trivial) to desymmetrize(qubit_space(symmetry)), as required by symmetrize.

SymmetryTransformation
Trivialidentity
Z2Irrepidentity
U1Irrepidentity

Both Z2Irrep and U1Irrep use the (parity of the) excitation number as their charge, which is diagonal in the computational basis, and order their sectors as $0, 1$, such that the transformation is the identity in all cases. It is returned with integer scalar type, such that it promotes to any scalar type without loss of precision.

source
TensorKitTensors.QuantumGates.chMethod
ch([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
CH([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The controlled-Hadamard gate $|0⟩⟨0| ⊗ I + |1⟩⟨1| ⊗ H$: applies hadamard to the second qubit if the first is $|1⟩$.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.cnotMethod
cnot([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
CNOT([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
CX([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The controlled-NOT gate $|0⟩⟨0| ⊗ I + |1⟩⟨1| ⊗ X$: applies pauli_x to the second qubit if the first is $|1⟩$.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.controlledMethod
controlled(G::AbstractTensorMap)

Return the controlled version $|0⟩⟨0| ⊗ I + |1⟩⟨1| ⊗ G$ of the gate G, which applies G to the qubits of G if an additional leading control qubit is in the state $|1⟩$.

The element type and the symmetry are inherited from G. Since a controlled gate conserves whatever G conserves, this is compatible with every symmetry that G itself supports. Controls can be stacked, e.g. controlled(controlled(pauli_x())) is the toffoli gate, and using proj_1 as the leading projector instead gives a gate controlled on $|0⟩$.

Examples

The controlled x-rotation, which is not provided as a gate of its own:

julia> using TensorKit, TensorKitTensors.QuantumGates;

julia> crx = controlled(rotation_x(; theta = π / 2));

julia> crx ≈ proj_0() ⊗ id(qubit_space()) + proj_1() ⊗ rotation_x(; theta = π / 2)
true
source
TensorKitTensors.QuantumGates.cphaseMethod
cphase([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)
CP([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)

The controlled phase-shift gate $\mathrm{diag}(1, 1, 1, e^{iθ})$, with required rotation angle theta: applies phase_shift to the second qubit if the first is $|1⟩$.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.csMethod
cs([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])
CS([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])

The controlled-$S$ gate $\mathrm{diag}(1, 1, 1, i)$, i.e. cphase(; theta=π/2).

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.cyMethod
cy([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])
CY([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])

The controlled-Y gate $|0⟩⟨0| ⊗ I + |1⟩⟨1| ⊗ Y$: applies pauli_y to the second qubit if the first is $|1⟩$.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.czMethod
cz([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
CZ([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The controlled-Z gate $\mathrm{diag}(1, 1, 1, -1)$, i.e. cphase(; theta=π).

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.dcxMethod
dcx([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
DCX([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The double-CNOT gate: two back-to-back CNOTs with alternating control and target.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.ecrMethod
ecr([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])
ECR([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])

The echoed cross-resonance gate $\mathrm{ECR} = \tfrac{1}{√2}(X ⊗ I - Y ⊗ X)$.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.fredkinMethod
fredkin([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
FREDKIN([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
CSWAP([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The Fredkin (CSWAP) gate $|0⟩⟨0| ⊗ I ⊗ I + |1⟩⟨1| ⊗ \mathrm{SWAP}$: swaps the last two qubits if the first is $|1⟩$.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.hadamardMethod
hadamard([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
H([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The Hadamard gate $H = \tfrac{1}{√2}(X + Z)$.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.iswapMethod
iswap([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])
ISWAP([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])

The iSWAP gate, swapping two qubits with an extra factor $i$ on the $|01⟩ ↔ |10⟩$ amplitudes.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.pauli_xMethod
pauli_x([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
X([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The Pauli-X (NOT) gate $\begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}$.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.pauli_yMethod
pauli_y([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])
Y([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])

The Pauli-Y gate $\begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix}$.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.pauli_zMethod
pauli_z([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
Z([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The Pauli-Z gate $\begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}$.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.phase_shiftMethod
phase_shift([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)
P([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)

The phase-shift gate $\mathrm{diag}(1, e^{iθ}) = |0⟩⟨0| + e^{iθ} |1⟩⟨1|$, with required rotation angle theta.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.proj_0Method
proj_0([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
P0([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The projector onto $|0⟩$, $|0⟩⟨0| = \tfrac{1}{2}(I + Z)$.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.proj_1Method
proj_1([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
P1([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The projector onto $|1⟩$, $|1⟩⟨1| = \tfrac{1}{2}(I - Z)$.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.qubit_spaceFunction
qubit_space([symmetry::Type{<:Sector}])

Return the local Hilbert space of a single qubit with basis $|0⟩, |1⟩$.

SymmetrySpace
TrivialComplexSpace(2)
Z2IrrepZ2Space(0 => 1, 1 => 1) (charge = number of excitations mod 2)
U1IrrepU1Space(0 => 1, 1 => 1) (charge = number of excitations)
source
TensorKitTensors.QuantumGates.rotation_xMethod
rotation_x([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)
Rx([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)

The x-rotation gate $e^{-iθX/2} = \cos\tfrac{θ}{2}\,I - i\sin\tfrac{θ}{2}\,X$, with required rotation angle theta.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.rotation_xxMethod
rotation_xx([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)
Rxx([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)

The XX-rotation (Ising coupling) gate $e^{-iθ\, X ⊗ X / 2} = \cos\tfrac{θ}{2}\,I ⊗ I - i\sin\tfrac{θ}{2}\,X ⊗ X$, with required rotation angle theta.

Supported symmetries: Trivial, Z2Irrep.

source
TensorKitTensors.QuantumGates.rotation_yMethod
rotation_y([eltype::Type{<:Number}], [symmetry::Type{<:Sector}]; theta)
Ry([eltype::Type{<:Number}], [symmetry::Type{<:Sector}]; theta)

The y-rotation gate $e^{-iθY/2} = \cos\tfrac{θ}{2}\,I - i\sin\tfrac{θ}{2}\,Y$, with required rotation angle theta. Unlike the other rotations, this one is real-valued.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.rotation_yyMethod
rotation_yy([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)
Ryy([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)

The YY-rotation gate $e^{-iθ\, Y ⊗ Y / 2} = \cos\tfrac{θ}{2}\,I ⊗ I - i\sin\tfrac{θ}{2}\,Y ⊗ Y$, with required rotation angle theta.

Supported symmetries: Trivial, Z2Irrep.

source
TensorKitTensors.QuantumGates.rotation_zMethod
rotation_z([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)
Rz([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)

The z-rotation gate $e^{-iθZ/2} = \cos\tfrac{θ}{2}\,I - i\sin\tfrac{θ}{2}\,Z$, with required rotation angle theta.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.rotation_zxMethod
rotation_zx([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)
Rzx([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)

The ZX-rotation gate $e^{-iθ\, Z ⊗ X / 2} = \cos\tfrac{θ}{2}\,I ⊗ I - i\sin\tfrac{θ}{2}\,Z ⊗ X$, with required rotation angle theta.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.rotation_zzMethod
rotation_zz([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)
Rzz([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta)

The ZZ-rotation gate $e^{-iθ\, Z ⊗ Z / 2} = \cos\tfrac{θ}{2}\,I ⊗ I - i\sin\tfrac{θ}{2}\,Z ⊗ Z$, with required rotation angle theta.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.s_gateMethod
s_gate([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])
S([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])

The phase gate $S = √Z = \mathrm{diag}(1, i)$, i.e. phase_shift(; theta=π/2). Its adjoint $S^†$ is s_gate()'.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.swapMethod
swap([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
SWAP([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The gate that swaps two qubits, $|ab⟩ ↦ |ba⟩$.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.t_gateMethod
t_gate([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])
T([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}])

The $T$ (π/8) gate $T = √S = \mathrm{diag}(1, e^{iπ/4})$, i.e. phase_shift(; theta=π/4). Its adjoint $T^†$ is t_gate()'.

Supported symmetries: Trivial, Z2Irrep, U1Irrep.

source
TensorKitTensors.QuantumGates.toffoliMethod
toffoli([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
TOFFOLI([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])
CCX([eltype::Type{<:Number}], [symmetry::Type{<:Sector}])

The Toffoli (CCX) gate $|0⟩⟨0| ⊗ I ⊗ I + |1⟩⟨1| ⊗ \mathrm{CNOT}$: applies pauli_x to the third qubit if the first two are both $|1⟩$.

Supported symmetries: Trivial.

source
TensorKitTensors.QuantumGates.u3Method
u3([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta, phi, lambda)
U([eltype::Type{<:Complex}], [symmetry::Type{<:Sector}]; theta, phi, lambda)

The universal single-qubit gate

\[U(θ, φ, λ) = \begin{pmatrix} \cos\tfrac{θ}{2} & -e^{iλ}\sin\tfrac{θ}{2} \\ e^{iφ}\sin\tfrac{θ}{2} & e^{i(φ+λ)}\cos\tfrac{θ}{2} \end{pmatrix} = e^{i(φ+λ)/2}\, R_z(φ)\, R_y(θ)\, R_z(λ),\]

with required angles theta, phi and lambda. Every single-qubit gate is a special case of it, e.g. u3(; theta = 0, phi = 0, lambda = θ) is phase_shift and u3(; theta = π, phi = 0, lambda = π) is pauli_x.

Supported symmetries: Trivial.

source