Introducing qubit phase

In the last two sections we covered the bit-flip and the Hadamard gate. These allow us to to make the single-qubit quantum states \{|0\rangle, |1\rangle, |+\rangle, |-\rangle\} , and have introduced us to quantum superpositions. However, a general single-qubit quantum state has even richer qualities. As we have already mentioned, a single-qubit quantum state can be written as |\psi\rangle=\alpha |0\rangle + \beta |1\rangle , where \alpha and \beta are complex numbers with the probability constraint |\alpha|^2+|\beta|^2=1 . Furthermore, the global phase of a quantum state is not detectable; therefore, |\psi\rangle is the same as e^{j\gamma}|\psi\rangle .

An alternative representation of a single-qubit state that incorporates both of these constraints can be written as

\begin{split}\vert\psi\rangle = \sqrt{p}\vert0\rangle + e^{j\phi} \sqrt{1-p} \vert1\rangle,\end{split}

where 0 \leq p \leq 1 is the probability of the bit being in the 0 state, and 0\leq \phi < 2\pi is the quantum phase. The set of quantum gates, generated by \{H,T\} , makes it possible to reach all different values of p and \phi . In the later sections we will show how this can be done in principle, and introduce the advanced gates in IBM Quantum Experience to give finer control. First, however, we would like to develop an intuition for quantum phase by examining the T gate. The T gate applies a phase of \pi/4 , and has a matrix representation of

\begin{split}T =\begin{pmatrix} 1 & 0 \\ 0 & e^{j\pi/4} \end{pmatrix}.\end{split}

If we start with a system initially in the |+\rangle (which is done using the Hadamard), then apply multiples of the T gate and measure in the x-basis, we can map out this phase. These experiments are defined by the following eight scores:

OpenQasm Input

//Quantum Phase exp 0
OPENQASM 2.0;
include "qelib1.inc";

// Register declarations
qreg q[1];
creg c[1];

// Quantum Circuit
h q;
barrier q;
// None
barrier q;
h q;
measure q -> c;

OpenQasm Input

//Quantum Phase exp 1
OPENQASM 2.0;
include "qelib1.inc";

// Register declarations
qreg q[1];
creg c[1];

// Quantum Circuit
h q;
barrier q;
t q;
barrier q;
h q;
sdg q;
measure q -> c;

OpenQasm Input

//Quantum Phase exp 2
OPENQASM 2.0;
include "qelib1.inc";

// Register declarations
qreg q[1];
creg c[1];

// Quantum Circuit
h q;
barrier q;
t q;
t q;
barrier q;
h q;
measure q -> c;

OpenQasm Input

//Quantum Phase exp 3
OPENQASM 2.0;
include "qelib1.inc";

// Register declarations
qreg q[1];
creg c[1];

// Quantum Circuit
h q;
barrier q;
t q;
t q;
t q;
barrier q;
h q;
measure q -> c;

OpenQasm Input

//Quantum Phase exp 4
OPENQASM 2.0;
include "qelib1.inc";

// Register declarations
qreg q[1];
creg c[1];

// Quantum Circuit
h q;
barrier q;
t q;
t q;
t q;
t q;
barrier q;
h q;
measure q -> c;

OpenQasm Input

//Quantum Phase exp 5
OPENQASM 2.0;
include "qelib1.inc";

// Register declarations
qreg q[1];
creg c[1];

// Quantum Circuit
h q;
barrier q;
t q;
t q;
t q;
t q;
t q;
barrier q;
h q;
measure q -> c;

OpenQasm Input

//Quantum Phase exp 6
OPENQASM 2.0;
include "qelib1.inc";

// Register declarations
qreg q[1];
creg c[1];

// Quantum Circuit
h q;
barrier q;
t q;
t q;
t q;
t q;
t q;
t q;
barrier q;
h q;
measure q -> c;

OpenQasm Input

//Quantum Phase exp 7
OPENQASM 2.0;
include "qelib1.inc";

// Register declarations
qreg q[1];
creg c[1];

// Quantum Circuit
h q;
barrier q;
t q;
t q;
t q;
t q;
t q;
t q;
t q;
barrier q;
h q;
measure q -> c;

Qiskit example

# quantum_phase.py
import numpy as np
from qiskit import QuantumCircuit, execute, Aer

# Build the circuits
circuits = []
pre = QuantumCircuit(1, 1)
pre.h(0)
pre.barrier()
middle = QuantumCircuit(1, 1)
meas_x = QuantumCircuit(1, 1)
meas_x.barrier()
meas_x.h(0)
meas_x.measure(0, 0)
exp_vector = range(0,8)
for exp_index in exp_vector:
    circuits.append(pre + middle + meas_x)
    middle.t(0)

# Execute the circuits
shots = 1024
job = execute(circuits, backend = Aer.get_backend('qasm_simulator'),
              shots=shots, seed_simulator=8)
result = job.result()

# Print the result
for exp_index in exp_vector:
    data = result.get_counts(circuits[exp_index])
    try:
        p0 = data['0']/shots
    except KeyError:
        p0 = 0
    try:
        p1 = data['1']/shots
    except KeyError:
        p1 = 0
    print('exp {}: [{}, {}] X length = {}'.format(exp_index, p0, p1, p0-p1))
exp 0: [1.0, 0] X length = 1.0
exp 1: [0.857421875, 0.142578125] X length = 0.71484375
exp 2: [0.494140625, 0.505859375] X length = -0.01171875
exp 3: [0.134765625, 0.865234375] X length = -0.73046875
exp 4: [0, 1.0] X length = -1.0
exp 5: [0.14453125, 0.85546875] X length = -0.7109375
exp 6: [0.494140625, 0.505859375] X length = -0.01171875
exp 7: [0.8427734375, 0.1572265625] X length = 0.685546875

Here, Qiskit gives us a nice advantage, as we can simply loop over the different circuits.

The results are summarized in the following table, where X length is the result of probability 0 minus probability 1. You can think of it as the length of the x measurement.

Experiment

Phase angle

Gates

Prob 0

Prob 1

X length

0

0

1

0

1

1

\pi/4

T

0.8535533

0.1464466

0.7071067

2

\pi/2

T^2

0.5

0.5

0

3

3\pi/4

T^3

0.1464466

0.8535533

-0.707106

4

\pi

T^4

0

1

-1

5

5\pi/4

T^5

0.1464466

0.8535533

-0.707106

6

3\pi/2

T^6

0.5

0.5

0

7

7\pi/4

T^7

0.8535533

0.1464466

0.7071067

Note: To get these values, you might need to set the number of shots to be much larger than 1024.

You have probably noticed that there are additional gates: Y , Z , S , S^\dagger , T^\dagger , and a CNOT (that we will touch on later) available in the Composer. All of these gates can be built from the H , T , and X .

\begin{split}S =\begin{pmatrix} 1 & 0 \\ 0 & j \end{pmatrix} := T^2,\end{split}
\begin{split}Z =\begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix} := T^4,\end{split}
\begin{split}S^\dagger =\begin{pmatrix} 1 & 0 \\ 0 & -j \end{pmatrix} := T^6,\end{split}
\begin{split}T^\dagger =\begin{pmatrix} 1 & 0 \\ 0 & e^{-j\pi/4} \end{pmatrix} := T^7\end{split}

and

\begin{split}Y =\begin{pmatrix} 0 & -j \\ j & 0 \end{pmatrix} := XZ\end{split}

The coloring denotes the group properties. All the green gates form a group known as the Pauli group, and can be made by \{X, Z\} . The blue set forms a group called the Clifford group, and can be made by \{H, S\} (Note the Pauli group can be made using these.) The red gates are the non-Clifford gates.

Now that we have a good understanding of the standard gates, we can define a third basis, the circular (or Y ) basis: |\circlearrowright\rangle = \frac{1}{\sqrt{2}}(|0\rangle+j|1\rangle) |\circlearrowleft\rangle = \frac{1}{\sqrt{2}}(|0\rangle-j|1\rangle) . To make the |\circlearrowright\rangle  state from the |0 \rangle state, use a H gate followed by an S gate. Try to figure out how to get the |\circlearrowleft\rangle  on your own.

To measure in this basis, we must rotate the computation basis ( Z ) to the circular basis ( Y ). To do this, use an S^\dagger followed by H  before your measurement. See below for an example score (the other seven would be similar to before) and a Qiskit example, to map out the quantum phase experiment above projected into the circular basis.

OpenQasm Input

//Quantum Phase exp 0
OPENQASM 2.0;
include "qelib1.inc";

// Register declarations
qreg q[1];
creg c[1];

// Quantum Circuit
h q;
barrier q;
// None
barrier q;
sdg q;
h q;
measure q -> c;

Qiskit example

# quantum_phase_meas_y.py
import numpy as np
from qiskit import QuantumCircuit, execute, Aer

# Build the circuit
circuits = []
pre = QuantumCircuit(1, 1)
pre.h(0)
pre.barrier()
middle = QuantumCircuit(1, 1)
meas_y = QuantumCircuit(1, 1)
meas_y.barrier()
meas_y.s(0).inverse()
meas_y.h(0)
meas_y.measure(0, 0)
exp_vector = range(0,8)
for exp_index in exp_vector:
    circuits.append(pre + middle + meas_y)
    middle.t(0)

# Execute the circuits
shots = 1024
backend = Aer.get_backend('qasm_simulator')
job = execute(circuits, backend, shots=shots, seed_simulator=8)
result = job.result()

# Print the result
for exp_index in exp_vector:
    data = result.get_counts(circuits[exp_index])
    try:
        p0 = data['0']/shots
    except KeyError:
        p0 = 0
    try:
        p1 = data['1']/shots
    except KeyError:
        p1 = 0
    print('exp {}: [{}, {}] Y length = {}'.format(exp_index, p0, p1, p0-p1))
exp 0: [0.51171875, 0.48828125] Y length = 0.0234375
exp 1: [0.1552734375, 0.8447265625] Y length = -0.689453125
exp 2: [0, 1.0] Y length = -1.0
exp 3: [0.134765625, 0.865234375] Y length = -0.73046875
exp 4: [0.4951171875, 0.5048828125] Y length = -0.009765625
exp 5: [0.8603515625, 0.1396484375] Y length = 0.720703125
exp 6: [1.0, 0] Y length = 1.0
exp 7: [0.8427734375, 0.1572265625] Y length = 0.685546875

Experiment

Phase angle

Gates

Prob 0

Prob 1

Y length

0

0

0.5

0.5

0

1

\pi/4

T

0.8535533

0.1464466

0.7071067

2

\pi/2

T^2

1.0

0

1

3

3\pi/4

T^3

0.8535533

0.1464466

0.7071067

4

\pi

T^4

0.5

0.5

0

5

5\pi/4

T^5

0.1464466

0.8535533

-0.707107

6

3\pi/2

T^6

0

1

-1

7

7\pi/4

T^7

0.1464466

0.8535533

-0.707106