This article explains some of the most commonly used single qubit quantum gates for absolute beginners. More specifically, it is written for the programmers and software engineers who are just beginning to learn Quantum Computing.
(Note: This is a continuation of our first post on Quantum Computing. We highly recommend to browse through this first article before reading this one. This new post includes a quick (and informal) primer to quantum computing.)
Boolean Logic Gates
All classical computers are essentially built
from the (solid-state) logic gates like NOT
or OR
or NAND
, etc.
A microprocessor may include billions of such logic gate components.
Mathematically,
there are four different boolean functions that take one Boolean input (0
or 1
) and produce one Boolean output.
Here's a quick refresher.
f0(x) = 0, for x = 0, 1
f1(x) = 1
f2(x) = x
f3(x) = 1 - x (or, NOT x)
Notice that we generally use the integer numbers 0
and 1
for Boolean false
and true
, respectively,
and we tend to use arithmetic operations between bits rather than logical operations.
Hence, for example,
f3(0) = 1
f3(1) = 0
This f3
function, defined over a set of {0, 1}
,
is more or less equivalent to the following:
f3(false) = true
f3(true) = false
That is, f3
is the NOT
Boolean operator
although we use the arithmetic operation notations,
e.g., because it is often more convenient to do so.
For example,
a two-input one-output Boolean operator, XOR
,
is defined as follows.
XOR: true, true -> false
XOR: true, false -> true
XOR: false, true -> true
XOR: false, false -> false
This can be more compactly represented as, for instance,
XOR(x, y) = (x + y) % 2
Again, this function is valid only over an input set of {0, 1}
.
(Note: We will use this knowledge in later articles while discussing some quantum algorithms.)
The (Quickest) Quantum Computing Primer
A quantum bit, aka qubit, can be in one of the two 0
or 1
states just like
a classical bit.
A classical computer, conceptually speaking,
- Accepts a sequence of classical bits as input,
- Processes them using classical logic gates (according to the given instructions), and then
- Produces an output which is also a sequence of classical bits.
A quantum computer works more or less the same way.
It accepts an input of classical bits
and produces an output of 0
s and 1
s.
But, unlike in the traditional computing,
quantum computers process the data as qubits,
which can be more than just 0
s and 1
s.
A qubit, at any given moment,
can be in a "superposition" state of 0
and 1
.
That is, it can be both 0
and 1
at the same time,
with a certain relative composition of one vs the other.
(It's like a (non-existing) fruit that is 30% apple and 70% orange.)
That is quite strange, and almost unreal, you might say.
But, an even stranger thing is that nobody can see it,
e.g., a qubit in a state of 30% 0
and 70% 1
.
Quantum bits are like ghosts.
When we try to look at it (e.g, "measurement"),
it becomes just 0
or 1
.
If nobody can see a ghost, a qubit in a superposition state,
then does the ghost exist?
Well, the answer is yes. (It has (observable) implications in the real world although we cannot see the superposed quantum states.) We have built a body of knowledge for the last 100 years or so, through numerous experiments and what not, and we are absolutely certain at this point that that is how the nature works (at least, in the microscopic scale). Don't ask why. Sometimes, God works in mysterious ways. :)
The theory that describes this particular area of physical phenomena
is Quantum Mechanics
(which in fact has broader implications to the whole physics).
The 0
s and 1
s are mere abstractions of physical systems,
such as the energy states of an orbiting electron in an atom,
or the polarization (vertical or horizontal) of light (photons) etc.
Quantum computation uses this (microscopic) physical process
for computational purposes.
(This is truly revolutionary, if you ask me. ;))
There are many different types of qubits which are under development,
all using different physical systems for the 0-1
abstraction.
(Quantum systems can have more than two discrete states,
but we are primarily interested in two-state systems.)
Eventually, some will turn out to be more useful than others.
The future of quantum computers critically depends on
the success of this field (often known as the quantum hardware).
Another critical aspect that will determine the quantum computing's future is the research on quantum algorithms. Quantum computers require different ways of "programming", and there are only a handful of quantum algorithms currently known or discovered. This is one of the most important areas where programmers and software developers like you and me can really contribute. (Or, whoever is reading this.)
Quantum computing is a complete new frontier, and we do not know if it will be really "viable" in the long run. The first (trivial) quantum algorithm was invented in the 1990s (e.g., Deutsch-Jozsa algorithm), and yet the progress has been extremely slow. Unlike in the traditional classical computing, we do not even know how to go about creating a new algorithm. Most of the well-known quantum algorithms, like Shor's algorithm, were created by a stroke of genius.
Can we change that? Regardless of your classical programming experience, I invite you to look into quantum computing with an open and inquisitive mind, and with a sense of purpose.
Qubits (Quantum Bits)
Getting into quantum computing has a huge barrier to entrance, unfortunately. Most of the people working in the software field do not know much about physics, especially quantum physics. Furthermore, it requires a high level of math proficiency. Especially, in the field of advanced linear algebra (well beyond the NumPy level ;)).
We will try to present some tutorials on this blog that do not require heavy mathematics or theoretical physics. So that the software people like you and me can start working on quantum computing immediately. But, be warned, if you want to do anything really significant in this field, then you will eventually have to learn the fundamentals.
As stated, a qubit can be in
a superposition of two states, 0
and 1
.
We use the Dirac's "ket" notation to represent (column) vectors,
e.g., |0>
and |1>
.
According to quantum theory
(which perfectly describes the world as currently known to us),
a qubit (or, a binary quantum state)
can be represented as a linear combination of these two (classical) states,
with complex number coefficients.
|S> = a * |0> + b * |1>
In this example, a state represented by an arbitrary symbol |S>
is a superposition of the two "basis states", |0>
and |1>
,
with complex coefficients a
and b
.
(That is, a qubit state is mathematically
a vector in a 2-dimensional complex vector space.)
A complex number has a radius and a phase (an angle between 0 and 2*pi).
Hence this state includes 4 degrees of freedom (2 from a
and 2 from b
).
The global phase of the state is not important for describing the physics
and therefore the qubit state includes 3 degrees of freedom.
(Only the relative phase of a
and b
matters.)
Again, according to quantum theory,
when you make a measurement on a state |S>
, for instance,
you will end up with either |0>
with a probability proportional to |a|^2
or |1>
with a probability proportional to |b|^2
.
(Remember, you cannot "see" the quantum superposition states.
You can only see the classical states, through "observation" or "measurement".)
Because of this probabilistic meaning,
it is customary to normalize the state vector,
e.g., as |a|^2 + |b|^2 = 1
.
Therefore, a qubit ends up
being (roughly equivalent to) a unit vector with 2 degrees of freedom in a 3 dimensional space.
The state space of a qubit is therefore a sphere,
and it is knowns
as the "Bloch sphere"
after the person who came up with this concept.
(Note that you should not take this visual representation too literally.
For example, the two basis vectors |0>
and |1>
are "orthogonal"
(in the (complex) Hilbert space),
that is, their inner product is zero. On the other hand,
the Bloch sphere representation in real 3-D space obscures that fact.)
(Don't worry about what Hilbert space is, etc. for now.)
One important thing to remind yourself of, from your linear algebra class, is that these representations are dependent on the "basis", or the set of coordinates. The same single qubit can be represented in many different forms in different sets of basis.
(Note that a lot of formalisms that we use in quantum computing
originally came from the study of quantum spins with 2 states, namely, up and down.
|0>
and |1>
typically represent the up and down directions (of a spin), respectively,
e.g., along a magnetic field, which is commonly denoted as the z
axis.)
One Qubit Gates
Just as with classical computers made of logic gates, we build quantum computers using quantum gates.
As we described in the beginning,
there are only 4 possible distinct functions which take one classical bit
and returns one classical bit.
The identity function (f(x) = x
),
inverse (or, NOT) (f(x) = (x + 1) % 2
),
and two constant functions (either 0
or 1
).
On the contrary, a qubit has two (angular) degrees of freedom (with continuous values), and hence there are an infinite number of functions that take and return one qubit. Four vs infinity! The difference is like ... very big. :) Hence, one can imagine how powerful quantum computing can be compared to the traditional computing. At least, potentially. (And, we haven't even mentioned quantum entanglement and what not.)
In Qiskit,
an arbitrary quantum transformation of a qubit
(which is represented by a 2x2 (complex number) Unitary matrix
and which is graphically like a rotation of a state vector on the Bloch sphere)
is most generally represented by the U
operator, or the U
gate.
The U
gate is parameterized by three angles, e.g., theta
, phi
, and lambda
.
The U
gate is not, however, generally used in the quantum circuit design.
(A quantum circuit is, roughly speaking, a collection of connected quantum gates.)
Instead, a small set of predefined gates are predominantly used.
In particular, Pauli's sigma matrices (also known as Pauli's spin matrices,
due to the historical reasons) are widely used.
In fact, the identity matrix (two 1
s in the diagonal, and two 0
s in the off-diagonal)
and Pauli's 3 matrices form a "basis" for any 2x2 Hermitian matrix.
That is, any Hermitian matrix can be represented
as a linear combination of these 4 matrices
with 4 real number coefficients.
(What exactly Unitary matrices or Hermitian matrices are is not important for this article. But, note that a Unitary matrix and Hermitian matrix in a complex vector space are roughly comparable to a rotation matrix and symmetric matrix in a real vector space, respectively. According to Quantum mechanics, all physical operations must be represented by Unitary matrices. This is because of the time reversal symmetry in physical systems. Likewise, an "observable" is represented by a Hermitian matrix. Hermitian matrices have real eigenvalues that correspond to physical values.)
Now let's go through some of the important predefined gates. (If you are not familiar with Dirac's braket notation, you may want to look up some basics before you continue.)
The X
Gate
The X
gate is represented by Pauli's sigma-x matrix,
two 1
s off-diagonal and two 0
s along the diagonal.
It can also be represented as follows using the outer product notation:
X = |0><1| + |1><0|
If we apply X
to each of the basis vectors,
X|0> = |1>
X|1> = |0>
This is because |0>
and |1>
are orthogonal to each other
and they are normalized. That is,
<0|0> = 1
<1|1> = 1
<0|1> = 0
<1|0> = 0
(Note: <x|y>
represents an inner product between a bra <x|
(row vector)
and a ket |y>
(column vector).
These are vectors in complex vector space,
and the corresponding elements of <0|
and |0>
, for instance,
are complex conjugations of each other.)
Therefore, X
flips |0>
to |1>
and vice versa.
(Hence, it is comparable to the classical NOT gate.)
(In the Bloch Sphere representation,
it's like a rotation around the x
-axis for 180 degrees. And, hence the name.
But, as stated, this visual representation is not totally accurate.
Orthogonality in the real vector space implies that they are perpendicular.
|0>
to |1>
are not drawn in the perpendicular directions in the Bloch Sphere drawing.)
Here's a simple quantum circuit using a single X
gate, in Qiskit.
import qiskit as qi
def to_circuit():
circ = qi.QuantumCircuit(1, 1)
circ.x(0)
circ.measure(0, 0)
return circ
The to_circuit
function returns a quantum circuit comprising a single X
gate
and a classic bit register for measuring the output.
An earlier article,
Qiskit Demo (for Absolute Beginners),
describes the basics of using Qiskit with Python.
(Note: The gate names, etc., are not necessarily specific to Qiskit.)
The Y
Gate
The Y
gate is rather similar to the X
gate.
It is represented by Pauli's sigma-y matrix,
two 0
s along the diagonal, -j
at 0,1
,
and j
at 1,0
.
It can also be represented as follows:
Y = -j |0><1| + j |1><0|
(We use j
here instead of the mathematical imaginary sign i
since
many programming languages use j
, including Python.)
If we apply Y
to each basis vector,
Y|0> = j |1>
Y|1> = -j |0>
The Y
gate works in much the same way as X
in that it flips
|0>
to |1>
and |1>
to |0>
except that it adds a phase.
j
represents an addition of pi/2
.
Likewise, -j
signifies an extra phase -pi/2
.
(In the Bloch Sphere representation,
the Y
gate is like a rotation of a vector around the y
-axis for 180 degrees.)
Here's a similar quantum circuit example comprising a single Y
gate, in Qiskit.
import qiskit as qi
def to_circuit():
circ = qi.QuantumCircuit(1, 1)
circ.y(0)
circ.measure(0, 0)
return circ
The Z
Gate
The Z
gate is also similar to the X
and Y
gates in terms of its construction
(e.g., a rotation around the z
-axis in the Bloch sphere representation),
but because of the way this particular basis (|0>
and |1>
) is chosen,
Z
works rather differently than X
and Y
.
The Z
gate is represented by Pauli's sigma-z matrix,
two 0
s off-diagonal, and 1
at 0,0
and -1
at 1,1
along the diagonal.
It can also be represented as follows in the outer product form:
Z = |0><0| - |1><1|
If we apply Z
to each basis vector,
Z|0> = |0>
Z|1> = - |1>
Z
does not change |0>
.
But, in the case of |1>
, note -1
,
which indicates a phase shift of pi
.
Here's a quantum circuit comprising a single Z
gate:
import qiskit as qi
def to_circuit():
circ = qi.QuantumCircuit(1, 1)
circ.z(0)
circ.measure(0, 0)
return circ
We use the x()
, y()
, and z()
methods on a QuantumCircuit
to add additional X
, Y
, and Z
gates to the circuit, respectively.
The Hadamard Gate
Another important builtin single-qubit quantum gate is the Hadamard gate,
or the H
gate.
In the matrix form,
it has 1
and -1
along the diagonal and two 1
s in the off-diagonal positions,
with the normalization factor of 1/sqrt(2)
.
In the outer product form,
Z = 1/sqrt(2) * (|0><0| + |0><1| + |1><0| - |1><1|)
or
Z = |+><0| + |-><1|
where
|+> = 1/sqrt(2) * (|0> + |1>)
|-> = 1/sqrt(2) * (|0> - |1>)
Therefore,
H|0> = |+>
H|1> = |->
Note that a vector that is in a sharp state in the current basis
(e.g., |0>
or |1>
)
becomes a superposition of both components, with a possible phase shift
in one component.
The superposition is one of the most important ingredients of quantum computing,
and hence one can easily imagine the usefulness of the H
gate in quantum circuits
for different computing tasks.
(The astute readers, even if they have had no exposure to Dirac notations before,
might have noticed the relationship between the matrix forms and the outer product forms.
See, for example, the H
gate representations.)
A Qiskit code example using QuantumCircuit.h()
to
add an H
gate:
import qiskit as qi
def to_circuit():
circ = qi.QuantumCircuit(1, 1)
circ.h(0)
circ.measure(0, 0)
return circ
The S
/Sdg
, T
/Tdg
, and P
Gates
The X
, Y
, Z
, and H
gates are somewhat special in that
they are their own inverses.
That is, applying one of these operations twice becomes the identity, I
,
as in "doing nothing".
For example, XX|S>
yields |S>
for any state |S>
.
In general, this is not the case for an arbitrary Unitary matrix.
(Mathematically, a Unitary matrix is a matrix U
that satisfies U * Udg = I
,
where Udg
is the conjugate transpose of U
.)
There are a few more predefined single-qubit quantum gates
that are similar to the Z
gate.
- The
S
andSdg
gates (dg
for "dagger") are the rotation operations around thez
axis forpi/2
and-pi/2
, respectively. - The
T
andTdg
gates are rotations around thez
axis forpi/4
and-pi/4
, respectively. - The
P(phi)
gate (P
for phase) performs a rotation around thez
axis forphi
degrees (in radian).
In Qiskit,
they are also instance methods defined in the qiskit.QuantumCircuit
class,
e.g., s()
, sdg()
, t()
, tdg()
, and p(phi)
, etc.
Trying Out
As we have seen in the earlier post, Qiskit Demo (for Absolute Beginners), we can "run" these circuits in a simulator.
Here's a simple simulator code:
import qiskit as qi
def run(circ):
sim = qi.Aer.get_backend('aer_simulator')
result = qi.execute(circ, backend=sim).result()
counts = result.get_counts()
return counts
You can pass in one of the circuits to this run
function.
Here's an example code
that runs all 4 circuits one after another.
import xgate
import ygate
import zgate
import hgate
import sim
def _demo():
x = xgate.to_circuit()
y = ygate.to_circuit()
z = zgate.to_circuit()
h = hgate.to_circuit()
for c in (x, y, z, h):
print(c.draw())
counts = sim.run(c)
print(c.name, counts)
if __name__ == "__main__":
_demo()
The simulator, by default,
processes the specific input |0>
(e.g., the "up spin")
for 1024 times on the given circuit.
(The sample code is available
on a GitLab repository, Code and Tips - Python - Quantum - One Qubit.)
Now, the question is, what kind of outputs would you expect? These are "trivial" circuits, but it may still be a good practice to try and guess the output before you run each of these circuits.
OK, here's a sample output.
circuit-85 {'1': 1024}
circuit-86 {'1': 1024}
circuit-87 {'0': 1024}
circuit-88 {'1': 514, '0': 510}
Are they consistent with your expectations? :)