The first part of this tutorial discusses some general features of gates, including the circuit notataion, symbols, controlled gates, parameterized gates and the creation of custom gates.
The second part is an alphabetical list of gates of the supported gates with detailed descriptions.
The following imports and definition are used for the examples in this tutorial:
import cmath
from math import pi
import numpy as np
from tinyqsim import gates
from tinyqsim.qcircuit import QCircuit
PI = '\u03C0' # Unicode PI
PHI = '\u03d5' # Unicode PHI
A quantum circuit is created using the QCircuit constructor and can be drawn with the 'draw' method:
qc = QCircuit(2) # 2 qubits
qc.draw()
The horizontal lines represent the qubits of the quantum circuit. So far, this is just an empty circuit with two qubits, q0 and q1. TinyQsim uses the Big-Endian qubit convention, so q0 is the most-significant qubit.
An instance of a quantum gate can be added to the circuit by calling the corresponding QCircuit method. Gates are assigned to particular qubits by supplying the qubit numbers as arguments.
The simplest case is for one-qubit gates assigned to single qubits. For example:
qc.x(0)
qc.y(1)
qc.draw()
It is also possible to add instances of a single-qubit gate to a list of qubits with a single command, as shown in the following example. This is supported for single-qubit gates with the current exception of the U gate. One use is to add Hadamard gates to all the qubits to create a multi-qubit superposition.
qc = QCircuit(3)
qc.h(range(3))
qc.x([0,2])
qc.z([]) # No effect
qc.draw()
Gates can have a controlled variant. The control enables the operation of the gate. It is drawn as a dark dot in the gate symbol.
The controlled version CU of a gate U applies the gate if the control is \(\ket{1}\). For example, for a one-qubit gate defined by the unitary matrix \(U\):
\[CU = \ket{0}\bra{0} \otimes I + \ket{1}\bra{1} \otimes U \]Since the control input may be in a superposition of \(\ket{0}\) and \(\ket{1}\), the result is the superposition of the results for the gate applied to the two cases.
TinyQsim provides controlled versions of many of the common gates. For example, CX is a controlled version of the X gate. Controls are denoted by a solid dot in the symbol,. It is possible for a gate to have multiple controls, such as the CCX gate.
The following example shows a circuit with two Controlled-NOT (CX) gates. The controls are indicated by dark dots.
qc = QCircuit(2) # 2 qubits
qc.cx(0, 1)
qc.cx(1, 0)
qc.draw()
Controls qubits always occur first in the argument list, so in this example:
Most basic gates operate on a single qubit, possibly with an additional control qubit. The API is then largely self-explanatory. For more complex cases, refer to the QCircuit API documentation for details.
The gates in a quantum circuit are often applied to non-consecutive qubits. For example:
qc = QCircuit(3)
qc.cx(0, 2)
qc.draw()
The vertical line passes over q1 without a dot, as q1 plays no role. If there were a dot on q1, it would indicate a gate with two controls, which would make it a CCX (controlled-controlled-NOT) gate. For example:
qc = QCircuit(3)
qc.ccx(0, 1, 2) # CCX with 3 arguments
qc.draw()
Since swapping the two controls of a CCX gates makes no difference, the symbol does not distinguish between them.
Anti-controlled gates are ones where the control is inverted, so that it disables the operation instead of enabling it. These are sometimes drawn like a controlled gate but with a hollow (white) control dot instead of a solid (dark) one.
TinyQsim does not have specific support for them, but the same effect can be created by sandwiching a control between two X gates, as shown here:
u = np.eye(2) # Dummy gate
qc = QCircuit(2)
qc.x(0)
qc.cu(u, 'U', 0, 1)
qc.x(0)
qc.draw()
One-qubit gates implement rotations of the state vector on the Bloch sphere. Some of these are fixed-angle rotations, such as X, Y, Z, S, T, etc. Others allow a user-specified rotation angle.
The P, CP, RX and RY gates have two parameters for the angle. The first is the angle in radians and the second is a label for the circuit symbol that shows the angle in a convenient form, such as a multiple of \(\pi\).
The following examples show how to specify the label using a simple ASCII 'pi' or a Unicode \(\pi\).
PI = '\u03C0' # PI unicode character
qc = QCircuit(1)
qc.p(pi / 3, 'pi/3', 0) # ASCII 'pi/3'
qc.p(pi / 3, f'{PI}/3', 0) # Unicode PI/3
qc.draw()
Custom gates can be defined using the U gate which takes a unitary matrix as an argument. The following example shows a circuit that uses two instances of a custom gate 'U1'.
u1 = np.array([[1, 0, 0, 0], # Define a unitary matrix
[0, 0, 1, 0],
[0, 1, 0, 0],
[0, 0, 0, 1]])
qc = QCircuit(3)
qc.u(u1, 'U1', 0, 1)
qc.u(u1, 'U1', 2, 1)
qc.draw()
The gate symbol is generated automatically and labelled with the string 'U1' given as the second argument.
The numbers '0' and '1' in the symbol show the assignment of the qubit arguments to the qubits, as the symbol does not distinguish them.
There are also CU and CCU variants for controlled-U and controlled-controlled-U gates. For example:
u2 = np.array([[0, 1], # Define a unitary matrix
[1, 0]])
qc = QCircuit(3)
qc.cu(u2, 'U2', 0, 1)
qc.ccu(u2, 'U2', 0, 1, 2)
qc.draw()
The first instance is a controlled-U2 gate, where U2 is the 1-qubit operation defined by the matrix.
The second instance is a controlled-controlled-U2 gate.
The 2x2 matrix in this case only defines the operation that is to be controlled but not the controls themselves. These gates could have been defined as a 'U' gate with a larger matrix that included the control actions. However, this would have been more complicated and the circuit symbols would not have shown which qubits were controls.
When a custom gate has 2 or more target qubits, the rectangular symbol may span another qubit that is not involved. For example:
u3 = np.eye(4) # Dummy custom 2-qubit gate matrix
qc = QCircuit(3)
qc.u(u3, 'U3', 0, 2)
qc.draw()
In this case, the dotted line on qubit q1 indicates that it just passes through without playing a role.
Another special situation is when there is a control between two target qubits. In this case, the dot symbol for the control may lie inside the gate rectangle, as shown here:
mygate = np.eye(4) # Dummy custom 2-qubit gate matrix
qc = QCircuit(3)
qc.cu(mygate, 'U1', 1, 0, 2)
qc.draw()
A parameterized gate can be defined as a function that returns a unitary matrix.
For example, suppose that we wish to create the following custom parameterized phase gate.
\[\text{RK}(k) =\begin{bmatrix}1 & 0 \\ 0 & e^{\large\frac{2\pi i}{2^k}}\end{bmatrix} \]One way to define it is:
def rk(k: int):
return np.array([[1, 0], [0, cmath.exp(1j * 2 * pi / 2 ** k)]])
Alternatively, we could define it in terms of the existing P (phase) gate, as follows:
def rk(k: int):
return gates.P(2 * pi / 2 ** k)
If, for example, we call this function with the argument 3 it returns a unitary matrix:
rk(3)
array([[1. +0.j , 0. +0.j ],
[0. +0.j , 0.70710678+0.70710678j]])
In either case, the gate can be added to the circuit like this:
qc = QCircuit(1)
qc.u(rk(3), 'RK', 0) # Add rk(3) to qubit 0
qc.draw()
Note that the unitary matrix definitions of the gates are defined in the tinyqsim 'gates' package. For example, the matrix of the CX gates is:
gates.CX
array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0]])
Some gates may appear to be equivalent, but actually differ in a subtle way.
For example, the RX(theta) gate performs a rotation by 'theta' radians about the X axis, whilst the X gate performs a rotation by \(\pi\) about the X axis. So it might seem that \(RX(\pi) = X\).
However, because of the way they are defined:
\[RX(\pi) = \begin{bmatrix} 0 & -i \\ -i & 0 \end{bmatrix}\quad\textrm{and}\quad X = \begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix} \]Hence \(X=i\,RX(\pi)\).
A global phase term has no effect on any experiment we can perform. Consider a quantum state with a global phase term \(e^{i\phi}\):
\(\ket{\psi} = e^{i\phi}(\alpha_0 \ket{0} + \alpha_1 \ket{1})\)
Then the probability of the measurement outcome \(\ket{0}\), for example, is:
\[\begin{align*} p(\ket{0}) &= (e^{i\phi}\alpha_0)^*\, (e^{i\phi}\alpha_0)\\ &=\alpha_0^*\,\alpha_0\\ &=|\alpha_0|^2 \end{align*} \]where \(^*\) denotes complex conjugation.
Consequently, the global phase term has no effect on the measurement outcome.
This extends to a multi-qubit system since:
\((e^{i\phi} \ket{\psi}) \otimes \ket{\chi} = e^{i\phi}(\ket{\psi} \otimes \ket{\chi})\)
| API | Description |
|---|---|
| qc.ccu(matrix, name, c1, c2, *t) | Controlled-controlled-U gate |
| qc.ccx(c1, c2, t) | Controlled-controlled-X (aka Toffoli) |
| qc.ch(c, t) | Controlled-H |
| qc.cp(phi, label, c, t) | Controlled-P |
| qc.crx(theta, label, c, t) | Controlled-RX |
| qc.cry(theta, label, c, t) | Controlled-RY |
| qc.crz(theta, label, c, t) | Controlled-RZ |
| qc.cs(c, t) | Controlled-S |
| qc.cswap(c, t1, t2) | Controlled SWAP (aka Fredkin) |
| qc.ct(c, t) | Controlled-T |
| qc.cu(matrix, label, c, *t) | Controlled-U |
| qc.cx(c, t) | Controlled-X (aka CNOT) |
| qc.cy(c, t) | Controlled-Y |
| qc.cz(c, t) | Controlled-Z |
| qc.h(t) | Hadamard |
| qc.i(t) | Identity (aka ID) |
| qc.p(phi, label, t) | Phase: 'phi' radians about Z axis |
| qc.rx(theta, label, t) | Rotation by 'theta' radians about X axis |
| qc.ry(theta, label, t) | Rotation by 'theta' radians about Y axis |
| qc.rz(theta, label, t) | Rotation by 'theta' radians about Z axis |
| qc.s(t) | pi/2 phase (S = sqrt(Z)) |
| qc.sdg(t) | -pi/2 phase (S-dagger) |
| qc.swap(t1, t2) | Swap 2 qubits |
| qc.sx(t) | Sqrt(X) (aka V, SQRTX) |
| qc.t(t) | pi/4 phase (T = sqrt(S)) |
| qc.tdg(t) | -pi/4 phase (T dagger) |
| qc.u(matrix, label, *t) | Use unitary matrix as a gate |
| qc.x(t) | Pauli X (aka NOT) |
| qc.y(t) | Pauli Y |
| qc.z(t) | Pauli Z |
The argument names are abbreviations for:
c Control qubit
t Target qubit
*t One or more target qubits
label Text label
phi Angle in radians
theta Angle in radians
The following are additional circuit elements that are strictly not gates because they are not reversible unitary operations.
| API | Description |
|---|---|
| qc.barrier() | Insert barrier in circuit (not a gate) |
| qc.measure(*t) | Measurement operation (not a gate) |
| qc.reset(t) | Reset qubit to |
The CCU gate is a controlled-controlled custom unitary gate. See the U gate for further details.
It applies unitary matrix U to the target qubit if both the controls are \(\ket{1}\).
u = np.eye(2) # Dummy gate
qc = QCircuit(3)
qc.ccu(u, 'U', 0, 1, 2)
qc.draw()
API:
ccu(u: ndarray, name: str, c1: int, c2: int, *t: int)
u : unitary numpy matrix
name : Name of gate
c1 : the first control qubit
c2 : the second control qubit
*t : the target qubits
The unitary matrix is of size \(2^k \times 2^k\) for \(k\) target qubits.
The CCX gate is a controlled-controlled-X gate. See the X gate for further details.
It applies an X (NOT) operation to the target qubit if both the controls are \(\ket{1}\).
qc = QCircuit(3)
qc.ccx(0, 1, 2)
qc.draw()
API:
ccx(c1: int, c2: int, t: int)
c1 : the first control qubit
c2 : the second control qubit
t : the target qubit
The CH gate is a controlled version of the Hadamard (H) gate. See the H gate for further details.
qc = QCircuit(2)
qc.ch(0, 1)
qc.draw()
API:
ch(c: int, t: int)
c : the control qubit
t : the target qubit
The CP gate is a controlled version of the P gate. See the P gate for further details.
The first argument is the phase angle in radians. The second argument is the phase angle as a string that is used to label the circuit symbol. The phase angles are typically multiples of 'pi', so it is convenient to use the unicode 'pi' in the text string. See the P gate for further details.
qc = QCircuit(2)
qc.cp(pi / 2, f'{PI}/2', 0, 1)
qc.draw()
cp(phi: float, label: str, c: int, t: int)
phi : the phase angle in radians
label : Text annotation for the angle
c : the control qubit
t : the target qubit
The CRX gate is a controlled version of the RX gate. See the RX gate for further details.
qc = QCircuit(2)
qc.crx(pi / 3, f'{PI}/3', 0, 1)
qc.draw()
API:
crx(theta: float, label: str, c: int, t: int)
theta : the angle in radians
label : Text label for the angle
c : the control qubit
t : the target qubit
The CRY gate is a controlled version of the RY gate. See the YX gate for further details.
qc = QCircuit(2)
qc.cry(pi / 3, f'{PI}/3', 0, 1)
qc.draw()
API:
cry(theta: float, label: str, c: int, t: int)
theta : the angle in radians
label : Text label for the angle
c : the control qubit
t : the target qubit
The CRZ gate is a controlled version of the RZ gate. See the RZ gate for further details.
qc = QCircuit(2)
qc.crz(pi / 3, f'{PI}/3', 0, 1)
qc.draw()
API:
crz(theta: float, label: str, c: int, t: int)
theta : the angle in radians
label : Text label for the angle
c : the control qubit
t : the target qubit
The CS gate is a controlled version of the S gate. See the S gate for further details.
qc = QCircuit(2)
qc.cs(0, 1)
qc.draw()
API:
cs(c: int, t: int)
c : the control qubits
t : the target qubit
The CSWAP gate is a controlled version of the SWAP gate. See the SWAP gate for further details.
qc = QCircuit(3)
qc.cswap(0, 1, 2)
qc.draw()
API:
cswap(c: int, t1: int, t2: int)
c : the control qubits
t1 : the first target qubit
t2 : the second target qubit
The CT gate is a controlled version of the T gate. See the T gate for further details.
qc = QCircuit(2)
qc.ct(0, 1)
qc.draw()
API:
ct(c: int, t: int)
c : the control qubit
t : the target qubit
The CU gate is a controlled custom unitary gate. See the U gate for further details.
It applies unitary matrix U to the target qubit if the control is \(\ket{1}\).
u = np.eye(2) # Dummy gate
qc = QCircuit(2)
qc.cu(u, 'U', 0, 1)
qc.draw()
API:
cu(u: ndarray, name: str, c: int, *t: int)
u : unitary numpy matrix
name : Name of gate
c : the control qubit
*t : the target qubits
The unitary matrix is of size \(2^k \times 2^k\) for \(k\) target qubits.
The CX gate is a controlled version of the X gate. It is also known as the CNOT gate. It plays an important role in quantum algorithms.
qc = QCircuit(2)
qc.cx(0, 1)
qc.draw()
API:
cx(c: int, t: int)
c : the control qubit
t : the target qubit
The CY gate is a controlled version of the Y gate. See the Y gate for further details.
qc = QCircuit(2)
qc.cy(0, 1)
qc.draw()
API:
cy(c: int, t: int)
c : the control qubit
t : the target qubit
The CZ gate is a controlled version of the Z gate. See the Z gate for further details.
qc = QCircuit(2)
qc.cz(0, 1)
qc.draw()
API:
cz(c: int, t: int)
c : the control qubit
t : the target qubit
The Hadamard (H) gate is an important gate in quantum computing because it can create a superposition from a basis state. It can also be used to switch between the Z basis and the X basis.
qc = QCircuit(1)
qc.h(0)
qc.draw()
API:
h(t: int | list[int])
t : the target qubit (or list of qubits)
The H gate is described by the following matrix:
\[H = \frac{1}{\sqrt{2}}\begin{bmatrix}1 & 1 \\ 1 & -1 \end{bmatrix} \]The I gate is the identity gate. The physical implementation in a quantum computer is simply 'do nothing'. Although it has no effect, it can be useful when analysing circuits. It is usually just drawn as a line, but may occasionally be made explicit as follows:
qc = QCircuit(1)
qc.i(0)
qc.draw()
API:
i(t: int | list[int])
t : the target qubit (or list of qubits)
The I gate is described by the identity matrix:
\[I = \begin{bmatrix}1 & 0 \\ 0 & 1 \end{bmatrix} \]The phase gate P rotates the phase of a qubit around the Z axis in the Bloch sphere.
qc = QCircuit(1)
qc.p(pi / 2, f'{PI}/2', 0) # For phi = pi/2
qc.draw()
The P gate is described by the following matrix:
\[P(\phi) =\begin{bmatrix}1 & 0 \\ 0 & e^{i\phi} \end{bmatrix} \]API:
p(phi: float, label: str, t: int | list[int])
phi : the phase angle in radians
label : text label for the angle
t : the target qubit (or list of qubits)
The first argument is the phase angle in radians. The second argument is the phase angle as a string. The phase angles are typically multiples of \(\pi\), so it is convenient to use unicode \(\pi\) in the text string.
When the phase gate is applied to a qubit \(\alpha_0\ket{0} + \alpha_1\ket{1}\), the result is:
\[\begin{bmatrix}1 & 0 \\ 0 & e^{i\phi} \end{bmatrix}\begin{bmatrix}\alpha_0 \\ \alpha_1 \end{bmatrix}=\begin{bmatrix}\alpha_0 \\ \alpha_1 e^{i\phi}\end{bmatrix} \]Note that all the phase is applied to the \(\ket{1}\) state. It is not necessary to apply separate phases to the two basis states as only the relative phase matters. The global phase does not affect the measurement outcome.
The following are special cases of the phase gate that have their own names as they are frequently used:
\[\begin{align*} Z &= P(\pi)\\[0.3em] S &= P(\frac{\pi}{2})= \sqrt{Z}\\[0.3em] T &= P(\frac{\pi}{4})= \sqrt{S} \end{align*} \]The RX gate performs a rotation by 'theta' radians about the X axis of the Bloch Sphere.
qc = QCircuit(1)
qc.rx(pi / 4, f'{PI}/4', 0)
qc.draw()
API:
rx(theta: float, t: int | list[int])
theta : the angle in radians
label : text label for the angle
t : the target qubit (or list of qubits)
The RX gate is described by the following matrix:
\[RX(\theta) = \begin{bmatrix} \cos(\frac{\theta}{2}) & -i\sin(\frac{\theta}{2}) \\ -i \sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) \end{bmatrix} \]Note: RX(\(\pi\)) and X differ by a global phase of \(i\):
\[RX(\pi) = \begin{bmatrix} 0 & -i \\ -i & 0 \end{bmatrix}\quad\textrm{whereas}\quad X = \begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix} \]Hence \(X=i\,RX(\pi)\).
The RY gate performs a rotation by 'theta' radians about the Y axis of the Bloch Sphere.
qc = QCircuit(1)
qc.ry(pi / 4, f'{PI}/4', 0)
qc.draw()
API:
ry(theta: float, t: int | list[int])
theta : the angle in radians
label : text label for the angle
t : the target qubit (or list of qubits)
The RY gate is described by the following matrix:
\[RY(\theta) = \begin{bmatrix} \cos(\frac{\theta}{2}) & -\sin(\frac{\theta}{2}) \\ \sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) \end{bmatrix} \]Note: RY(\(\pi\)) and Y differ by a global phase:
\[RY(\pi) = \begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}\quad\textrm{whereas}\quad Y = \begin{bmatrix} 0 & -i \\ i & 0 \end{bmatrix} \]Hence \(Y=i\,RY(\pi)\).
The RZ gate performs a rotation by 'theta' radians about the Z axis of the Bloch Sphere.
qc = QCircuit(1)
qc.rz(pi / 4, f'{PI}/4', 0)
qc.draw()
rz(theta: float, t: int | list[int])
theta : the angle in radians
label : text label for the angle
t : the target qubit (or list of qubits)
The RZ gate is described by the following matrix:
\[RZ(\theta) = \begin{bmatrix} e^{-i\frac{\theta}{2}} & 0 \\ 0 & e^{i\frac{\theta}{2}} \end{bmatrix} \]Note: RZ(\(\pi\)) and Z differ by a global phase:
\[RZ(\pi) = \begin{bmatrix} -i & 0 \\ 0 & i \end{bmatrix}\quad\textrm{whereas}\quad Z = \begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix} \]Hence \(Z=i\,RZ(\pi)\).
The S gate performs a phase rotation by \(\pi/2\) radians. It can be thought of as the square-root of the Z gate. Applying it twice is equivalent to a Z gate.
\[S=\sqrt{Z} \]qc = QCircuit(1)
qc.s(0)
qc.draw()
API:
s(t: int | list[int])
t : the target qubit (or list of qubits)
The S gate is described by the following matrix:
\[S =\begin{bmatrix}1 & 0 \\ 0 & i \end{bmatrix} \]The Sdg (S-dagger) \(S^\dagger\) gate is the conjugate transpose of the S gate. It performs a phase rotation by \(-\pi/2\) radians.
qc = QCircuit(1)
qc.sdg(0)
qc.draw()
API:
sdg(t: int | list[int])
t : the target qubit (or list of qubits)
The Sdg gate is described by the following matrix:
\[Sdg =\begin{bmatrix}1 & 0 \\ 0 & -i \end{bmatrix} \]The SWAP gate swaps the state of two qubits.
qc = QCircuit(2)
qc.swap(0, 1)
qc.draw()
API:
swap(c: int, t1: int, t2: int)
t1 : the first target qubit
t2 i: the second target qubit (or list of qubits)
The SWAP gate is described by the following matrix:
\[SWAP =\begin{bmatrix}1&0&0&0 \\ 0&0&1&0 \\ 0&1&0&0 \\ 0&0&0&1 \end{bmatrix} \]The SX gate can be thought of as the square-root of the X gate. Applying it twice is equivalent to an X gate:
\[SX=\sqrt{X} \]qc = QCircuit(1)
qc.sx(0)
qc.draw()
API:
sx(t: int | list[int])
t : the target qubit (or list of qubits)
The SX gate is described by the following matrix:
\[SX =\frac{1}{\sqrt{2}}\begin{bmatrix}1+i & 1-i \\ 1-i & 1+i \end{bmatrix} \]Note that \(V^\dagger\) is the other square-root of X.
The T gate performs a phase rotation by \(\pi/4\) radians. It can be thought of as the square-root of the S gate. Applying it twice is equivalent to a S gate:
\[T = \sqrt{S} \]qc = QCircuit(1)
qc.t(0)
qc.draw()
API:
t(t1: int | list[int])
t1 : the target qubit (or list of qubits)
The T gate is described by the following matrix:
\[T =\begin{bmatrix}1 & 0 \\ 0 & e^{i\frac{\pi}{4}} \end{bmatrix} \]Somewhat confusingly, the T gate is sometimes known as the \(\pi/8\) gate. This because it can be written in a symmetrical form (up to global phase) as:
\[T =\begin{bmatrix} e^{i\frac{\pi}{8}}& 0 \\ 0 & e^{i\frac{\pi}{8}} \end{bmatrix} \]The Tdg (T-dagger) \(T^\dagger\) gate is the conjugate transpose of the T gate. It performs a phase rotation by \(-\pi/4\) radians.
qc = QCircuit(1)
qc.tdg(0)
qc.draw()
API:
tdg(t: int | list[int])
t : the target qubit (or list of qubits)
The Tdg gate is described by the following matrix:
\[Tdg =\begin{bmatrix}1 & 0 \\ 0 & e^{-i\frac{\pi}{4}} \end{bmatrix} \]The U gate takes a \(2^N \times 2^N\) unitary matrix and applies it as an N-qubit gate. The simplest case is a single-qubit gate, which has a 2x2 matrix.
u = np.eye(2) # Dummy gate
qc = QCircuit(1)
qc.u(u, 'U', 0)
qc.draw()
API:
u(u: ndarray, name: str, *t: int)
u : unitary numpy matrix
name : Name of gate
*t : the target qubits
The unitary matrix is of size \(2^k \times 2^k\) for \(k\) target qubits.
The X gate is the quantum NOT operator. It is a rotation by \(\pi\) about the X axis of the Bloch sphere.
qc = QCircuit(1)
qc.x(0)
qc.draw()
API:
x(t: int | list[int])
t : the target qubit (or list of qubits)
The X gate is described by the following matrix:
\[X =\begin{bmatrix}0 & 1 \\ 1 & 0 \end{bmatrix} \]The Y gate It is a rotation by \(\pi\) about the Y axis of the Bloch sphere.
qc = QCircuit(1)
qc.y(0)
qc.draw()
API:
y(t: int | list[int])
t : the target qubit (or list of qubits)
The Y gate is described by the following matrix:
\[Y = \begin{bmatrix}0 & -i \\ i & 0 \end{bmatrix} \]The Z gate It is a rotation by \(\pi\) about the Z axis of the Bloch sphere.
qc = QCircuit(1)
qc.z(0)
qc.draw()
API:
z(t: int | list[int])
t : the target qubit (or list of qubits)
The Z gate is described by the following matrix:
\[Z =\begin{bmatrix}1&0 \\ 0&-1 \end{bmatrix} \]This section covers circuit elements that are not considered to be quantum gates because they are not reversible unitary operations.
The 'measure' operation performs a quantum measurement on one or more qubits.
qc = QCircuit(2)
qc.measure(0, 1)
qc.draw()
API:
measure(t1, t2, ... : int)
t1, t2, ... : the qubits to be measured
If the argument list is left blank, then all qubits will be measured.
The 'reset' operation resets a qubit to the \(\ket{0}\) state.
qc = QCircuit(1)
qc.reset(0)
qc.draw()
It is equivalent to a measurement of the qubit, followed by an X operation conditional on the measurement result being 1.
API:
reset(t: int)
t : the target qubit
A barrier is drawn in the circuit as a vertical dotted line, like a fence separating sections of the circuit. Its main use is to prevent circuit optimizations crossing boundaries. This does not apply to TinyQsim since it currently does no circuit optimization. However, a barrier can still be useful for separating parts of the circuit for clarify, for example to separate initialization from processing. The barrier can have an optional short label, which can be useful in documentation for referring to a particular stage of the circuit.
qc = QCircuit(2)
qc.barrier('A')
qc.draw()
API:
barrier(label: str)
label: Optional short label for the barrier