Tutorial 3: Guide to Gates

Contents

Introduction

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.

Imports and Definitions

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

Symbols and Notation

A quantum circuit is created using the QCircuit constructor and can be drawn with the 'draw' method:

qc = QCircuit(2)  # 2 qubits
qc.draw()

png

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()

png

Repeated Gates

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()

png

Controlled Gates

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()

png

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()

png

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()

png

Since swapping the two controls of a CCX gates makes no difference, the symbol does not distinguish between them.

Anti-Controlled Gates

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()

png

Angle Parameters

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()

png

Custom Gates

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()

png

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()

png

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()

png

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()

png

Parameterized Custom Gates

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()

png

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]])

Global Phase

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})\)


Summary of Gates

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

Alphabetical List of Gates

CCU

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()

png

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.

CCX (aka Toffoli) Gate

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()

png

API:
   ccx(c1: int, c2: int, t: int)
      c1 : the first control qubit
      c2 : the second control qubit
      t  : the target qubit

CH Gate

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()

png

API:
   ch(c: int, t: int)
      c : the control qubit
      t : the target qubit

CP Gate

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()

png

   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

CRX Gate

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()

png

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

CRY Gate

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()

png

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

CRZ Gate

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()

png

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

CS Gate

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()

png

API:
   cs(c: int, t: int)
      c : the control qubits
      t : the target qubit

CSWAP (aka Fredkin) Gate

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()

png

API:
   cswap(c: int, t1: int, t2: int)
      c  : the control qubits
      t1 : the first target qubit
      t2 : the second target qubit

CT Gate

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()

png

API:
   ct(c: int, t: int)
      c : the control qubit
      t : the target qubit

CU

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()

png

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.

CX (aka CNOT) Gate

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()

png

API:
   cx(c: int, t: int)
      c : the control qubit
      t : the target qubit

CY Gate

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()

png

API:
   cy(c: int, t: int)
      c : the control qubit
      t : the target qubit

CZ Gate

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()

png

API:
   cz(c: int, t: int)
      c : the control qubit
      t : the target qubit

H Gate

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()

png

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} \]

I (aka ID) Gate

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()

png

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} \]

P Gate

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()

png

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*} \]

RX Gate

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()

png

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)\).

RY Gate

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()

png

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)\).

RZ Gate

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()

png

   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)\).

S Gate

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()

png

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} \]

Sdg Gate

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()

png

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} \]

SWAP Gate

The SWAP gate swaps the state of two qubits.

qc = QCircuit(2)
qc.swap(0, 1)
qc.draw()

png

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} \]

SX (aka V, SQRTX) Gate

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()

png

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.

T Gate

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()

png

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} \]

Tdg Gate

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()

png

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} \]

U Gate

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()

png

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.

X (aka NOT) Gate

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()

png

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} \]

Y Gate

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()

png

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} \]

Z Gate

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()

png

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} \]

Non-Unitary Operations

This section covers circuit elements that are not considered to be quantum gates because they are not reversible unitary operations.

Measure

The 'measure' operation performs a quantum measurement on one or more qubits.

qc = QCircuit(2)
qc.measure(0, 1)
qc.draw()

png

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.

Reset

The 'reset' operation resets a qubit to the \(\ket{0}\) state.

qc = QCircuit(1)
qc.reset(0)
qc.draw()

png

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

Other Symbols

Barrier

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()

png

API:
   barrier(label: str)
     label: Optional short label for the barrier