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
| Symmetry | Physical meaning | Sector label | Representable gates |
|---|---|---|---|
Trivial | none | — | all gates, full $2^n × 2^n$ matrix |
Z2Irrep | excitation-number parity | charge $n \bmod 2$ per qubit | only gates that conserve the number of $1$'s modulo 2 |
U1Irrep | excitation-number conservation | charge $∈ \{0, 1\}$ per qubit | only gates that conserve the number of $1$'s |
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.
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
| Function | Alias(es) | Sites | Supported symmetries |
|---|---|---|---|
qubit_space | — | — | Trivial, Z2Irrep, U1Irrep |
pauli_x | X | 1 | Trivial |
pauli_y | Y | 1 | Trivial |
pauli_z | Z | 1 | Trivial, Z2Irrep, U1Irrep |
proj_0 | P0 | 1 | Trivial, Z2Irrep, U1Irrep |
proj_1 | P1 | 1 | Trivial, Z2Irrep, U1Irrep |
hadamard | H | 1 | Trivial |
s_gate | S | 1 | Trivial, Z2Irrep, U1Irrep |
t_gate | T | 1 | Trivial, Z2Irrep, U1Irrep |
phase_shift | P | 1 | Trivial, Z2Irrep, U1Irrep |
rotation_x | Rx | 1 | Trivial |
rotation_y | Ry | 1 | Trivial |
rotation_z | Rz | 1 | Trivial, Z2Irrep, U1Irrep |
u3 | U | 1 | Trivial |
cnot | CNOT, CX | 2 | Trivial |
cy | CY | 2 | Trivial |
cz | CZ | 2 | Trivial, Z2Irrep, U1Irrep |
ch | CH | 2 | Trivial |
cs | CS | 2 | Trivial, Z2Irrep, U1Irrep |
cphase | CP | 2 | Trivial, Z2Irrep, U1Irrep |
swap | SWAP | 2 | Trivial, Z2Irrep, U1Irrep |
iswap | ISWAP | 2 | Trivial, Z2Irrep, U1Irrep |
dcx | DCX | 2 | Trivial |
ecr | ECR | 2 | Trivial |
rotation_xx | Rxx | 2 | Trivial, Z2Irrep |
rotation_yy | Ryy | 2 | Trivial, Z2Irrep |
rotation_zz | Rzz | 2 | Trivial, Z2Irrep, U1Irrep |
rotation_zx | Rzx | 2 | Trivial |
toffoli | TOFFOLI, CCX | 3 | Trivial |
fredkin | FREDKIN, CSWAP | 3 | Trivial, Z2Irrep, U1Irrep |
The adjoint gates $S^†$ and $T^†$ are obtained as s_gate()' and t_gate()'.
API
TensorKitTensors.QuantumGates.basis_transform — Method
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.
| Symmetry | Transformation |
|---|---|
Trivial | identity |
Z2Irrep | identity |
U1Irrep | identity |
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.
TensorKitTensors.QuantumGates.ch — Method
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.
TensorKitTensors.QuantumGates.cnot — Method
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.
TensorKitTensors.QuantumGates.controlled — Method
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)
trueTensorKitTensors.QuantumGates.cphase — Method
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.
TensorKitTensors.QuantumGates.cs — Method
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.
TensorKitTensors.QuantumGates.cy — Method
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.
TensorKitTensors.QuantumGates.cz — Method
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.
TensorKitTensors.QuantumGates.dcx — Method
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.
TensorKitTensors.QuantumGates.ecr — Method
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.
TensorKitTensors.QuantumGates.fredkin — Method
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.
TensorKitTensors.QuantumGates.hadamard — Method
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.
TensorKitTensors.QuantumGates.iswap — Method
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.
TensorKitTensors.QuantumGates.pauli_x — Method
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.
TensorKitTensors.QuantumGates.pauli_y — Method
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.
TensorKitTensors.QuantumGates.pauli_z — Method
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.
TensorKitTensors.QuantumGates.phase_shift — Method
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.
TensorKitTensors.QuantumGates.proj_0 — Method
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.
TensorKitTensors.QuantumGates.proj_1 — Method
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.
TensorKitTensors.QuantumGates.qubit_space — Function
qubit_space([symmetry::Type{<:Sector}])Return the local Hilbert space of a single qubit with basis $|0⟩, |1⟩$.
| Symmetry | Space |
|---|---|
Trivial | ComplexSpace(2) |
Z2Irrep | Z2Space(0 => 1, 1 => 1) (charge = number of excitations mod 2) |
U1Irrep | U1Space(0 => 1, 1 => 1) (charge = number of excitations) |
TensorKitTensors.QuantumGates.rotation_x — Method
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.
TensorKitTensors.QuantumGates.rotation_xx — Method
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.
TensorKitTensors.QuantumGates.rotation_y — Method
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.
TensorKitTensors.QuantumGates.rotation_yy — Method
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.
TensorKitTensors.QuantumGates.rotation_z — Method
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.
TensorKitTensors.QuantumGates.rotation_zx — Method
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.
TensorKitTensors.QuantumGates.rotation_zz — Method
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.
TensorKitTensors.QuantumGates.s_gate — Method
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.
TensorKitTensors.QuantumGates.swap — Method
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.
TensorKitTensors.QuantumGates.t_gate — Method
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.
TensorKitTensors.QuantumGates.toffoli — Method
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.
TensorKitTensors.QuantumGates.u3 — Method
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.