Home Algorithms Commercialization Data Science Information Theories Quantum Theories Lab Linear Algebra
<< Flip Bits PDF Hadamard on Multi-Qubits >>

$\require{cancel} \newcommand{\Ket}[1]{\left|{#1}\right\rangle} \newcommand{\Bra}[1]{\left\langle{#1}\right|} \newcommand{\Braket}[1]{\left\langle{#1}\right\rangle} \newcommand{\Rsr}[1]{\frac{1}{\sqrt{#1}}} \newcommand{\RSR}[1]{1/\sqrt{#1}} \newcommand{\Verti}{\rvert} \newcommand{\HAT}[1]{\hat{\,#1~}} \DeclareMathOperator{\Tr}{Tr}$

GHZ State

First created in July 2018

Generating GHZ

In [1]:
# ghz.py
import numpy as np
import math
import matplotlib.pyplot as plt

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute
from qiskit.tools.visualization import plot_histogram, plot_state, circuit_drawer

# Compute the Expectation Value from circuit qc
shots = 8192
def run_job(qc_run, shots=shots):
    job = execute(qc_run, backend = 'local_qasm_simulator', shots=shots)
    result = job.result()
    data = result.get_counts(qc_run)
    for i in range(8):
        dataIndex = str(bin(i+8))[-3:]
        try:
            p = data[dataIndex]/shots
            print("P%s=%.3f" % (dataIndex, p))
        except:
            p = 0

    plot_histogram(job.result().get_counts(qc_run))
    return job

def print_vec(vec):
    vecLen = len(vec)
    qbCount = int(math.log(vecLen, 2))

    vecRnd = np.around(vec, 3)
    jn = ''
    for i in range(vecLen):
        ket = str(bin(i+vecLen))[-qbCount:]
        if np.abs(vecRnd[i]) >= 0.001:
            print("%s%s|%s>" % (jn, vecRnd[i], ket), end='')
            jn = ' + '

    print("")
    return vecRnd
In [2]:
# Number of qubits - Feel free to change it.
qbNum = 3

# Define the Quantum and Classical Registers
q = QuantumRegister(qbNum)
c = ClassicalRegister(qbNum)

qc = QuantumCircuit(q, c)

# Preparation
for i in range(qbNum-1):
    qc.h(q[i])
# The last qubit with X
qc.x(q[qbNum-1])

# CNOTs
for i in range(qbNum-1):
    qc.cx(q[qbNum-i-2], q[qbNum-1])
    # We do the cX in reverse order just to make the circuit
    # look cool (when the final Hs align).
    # Doing it in forward order would give the same result.
    #qc.cx(q[i], q[qbNum-1])

# Finalise
for i in range(qbNum):
    qc.h(q[i])

# If you want to try out the XXX "contradiction"
# on the IBM Q Experience website

# Measure on XXX
#for i in range(qbNum):
#    qc.x(q[i])

# Measure on XYY
#qc.x(q[0])
#qc.y(q[1])
#qc.y(q[2])


# See the vector
job = execute(qc, backend = 'local_statevector_simulator', shots=shots)
print_vec(job.result().get_statevector(qc))

# Measure the qubits
qc.measure(q, c)
run_job(qc)

# Check the circuit (must be last or it will not show)
circuit_drawer(qc)
(0.707-0j)|000> + (-0.707+0j)|111>
P000=0.497
P111=0.503
Out[2]:

In the above if we remove the $X$ on the MSD $q$ (the lowest one), the $\Ket{11\ldots 1}$ coefficient will become positive.

Algorithm Explained

Note: Here we use $q_0$ as the MSD, so it is $q_0\otimes q_1\otimes q_2.$

Step 1 is $H\otimes H\otimes X.$

Step 2 is $I\otimes cX_{12}$ followed by $cX_{02}.$

$cX_{02}$ is a bit tricky. It is a 3-qubit gate: $\left\{\begin{matrix} I\otimes I~~\text{ if }q_0\text{ is }\Ket0\\ I\otimes X~~\text{ if }q_0\text{ is }\Ket1 \end{matrix}\right. .$

$\Ket0\Bra0\otimes I\otimes I+\Ket1\Bra1\otimes I\otimes X =\begin{bmatrix} [I_2\otimes I_2] & 0\\ 0 & [I_2\otimes X] \end{bmatrix} =\begin{bmatrix} [I_4] & 0\\ 0 & \begin{bmatrix}X&0\\0&X\end{bmatrix} \end{bmatrix} =\begin{bmatrix} 1&0&0&0&0&0&0&0&\\ 0&1&0&0&0&0&0&0&\\ 0&0&1&0&0&0&0&0&\\ 0&0&0&1&0&0&0&0&\\ 0&0&0&0&0&1&0&0\\ 0&0&0&0&1&0&0&0\\ 0&0&0&0&0&0&0&1\\ 0&0&0&0&0&0&1&0 \end{bmatrix} .$

Step 3 is $H\otimes H\otimes H.$

The whole process is $(H\otimes H\otimes H) ~(\Ket0\Bra0\otimes I\otimes I+\Ket1\Bra1\otimes I\otimes X) ~(I\otimes cX_{12}) ~(H\otimes H\otimes I) .$

$\scriptstyle={1\over4\sqrt2} \begin{bmatrix} 1&1&1&1&1&1&1&1\\ 1&-1&1&-1&1&-1&1&-1\\ 1&1&-1&-1&1&1&-1&-1\\ 1&-1&-1&1&1&-1&-1&1\\ 1&1&1&1&-1&-1&-1&-1\\ 1&-1&1&-1&-1&1&-1&1\\ 1&1&-1&-1&-1&-1&1&1\\ 1&-1&-1&1&-1&1&1&-1 \end{bmatrix} \begin{bmatrix} 1&0&0&0&0&0&0&0&\\ 0&1&0&0&0&0&0&0&\\ 0&0&1&0&0&0&0&0&\\ 0&0&0&1&0&0&0&0&\\ 0&0&0&0&0&1&0&0\\ 0&0&0&0&1&0&0&0\\ 0&0&0&0&0&0&0&1\\ 0&0&0&0&0&0&1&0 \end{bmatrix} \begin{bmatrix} 1&0&0&0&0&0&0&0\\ 0&1&0&0&0&0&0&0\\ 0&0&0&1&0&0&0&0\\ 0&0&1&0&0&0&0&0\\ 0&0&0&0&1&0&0&0\\ 0&0&0&0&0&1&0&0\\ 0&0&0&0&0&0&0&1\\ 0&0&0&0&0&0&1&0 \end{bmatrix} \begin{bmatrix} 0&1&0&1&0&1&0&1\\ 1&0&1&0&1&0&1&0\\ 0&1&0&-1&0&1&0&-1\\ 1&0&-1&0&1&0&-1&0\\ 0&1&0&1&0&-1&0&-1\\ 1&0&1&0&-1&0&-1&0\\ 0&1&0&-1&0&-1&0&1\\ 1&0&-1&0&-1&0&1&0 \end{bmatrix}$

$={1\over4\sqrt2} \begin{bmatrix} 1&1&1&1&1&1&1&1\\ 1&-1&1&-1&1&-1&1&-1\\ 1&1&-1&-1&1&1&-1&-1\\ 1&-1&-1&1&1&-1&-1&1\\ 1&1&1&1&-1&-1&-1&-1\\ 1&-1&1&-1&-1&1&-1&1\\ 1&1&-1&-1&-1&-1&1&1\\ 1&-1&-1&1&-1&1&1&-1 \end{bmatrix} \begin{bmatrix} 0&1&0&1&0&1&0&1\\ 1&0&1&0&1&0&1&0\\ 1&0&-1&0&1&0&-1&0\\ 0&1&0&-1&0&1&0&-1\\ 1&0&1&0&-1&0&-1&0\\ 0&1&0&1&0&-1&0&-1\\ 0&1&0&-1&0&-1&0&1\\ 1&0&-1&0&-1&0&1&0 \end{bmatrix} .$

$=\Rsr2 \begin{bmatrix} 1&1&0&0&0&0&0&0\\ 0&0&0&0&0&0&-1&1\\ 0&0&1&1&0&0&0&0\\ 0&0&0&0&-1&1&0&0\\ 0&0&0&0&1&1&0&0\\ 0&0&-1&1&0&0&0&0\\ 0&0&0&0&0&0&1&1\\ -1&1&0&0&0&0&0&0 \end{bmatrix} .$

This will send $\Ket{000}$ to $\Rsr2(\Ket{000}-\Ket{111})$.

On IBM Q Experience

On the IBM Q Experience site, there is an interesting case of "$XXX=-1$" being contradictary to "common logic".

When applying the $X$ and $Y$ gates on individual qubits in a 3-qubit GHZ State of $\xi=\Rsr2(\Ket{000}-\Ket{111})$, some surprising result is obtained:

$XYY\Ket\xi=\Ket\xi,~~ YXY\Ket\xi=\Ket\xi,~~ YYX\Ket\xi=\Ket\xi,~~\text{but}~~ XXX\Ket\xi=-\Ket\xi .$

Note: On the website it says $XXX=-1$ (and similarly about other $X$, $Y$ combinations), which is misleading readers into thinking that the operators are scaler of some sort. In fact, what it really means is that $\Ket\xi$ is an eigenvector of $XXX$ with eigenvalue of -1.


$XYY\Ket\xi\\ =X\otimes Y\otimes Y\Rsr2(\Ket{000}-\Ket{111})\\ =I\otimes Y\otimes Y\Rsr2(\Ket{100}-\Ket{011})\\ =I\otimes I\otimes Y\Rsr2~(i\Ket{110}-(-i)\Ket{001})\\ =I\otimes I\otimes I\Rsr2~(i^2\Ket{111}-(-i)^2\Ket{000})\\ =\Ket\xi .$

The same process can apply to $YXY$ and $YYX$.


$XXX\Ket\xi\\ =X\otimes X\otimes X\Rsr2(\Ket{000}-\Ket{111})\\ =I\otimes X\otimes X\Rsr2(\Ket{100}-\Ket{011})\\ =I\otimes I\otimes X\Rsr2(\Ket{110}-\Ket{001})\\ =I\otimes I\otimes I\Rsr2(\Ket{111}-\Ket{000})\\ =-\Ket\xi .$


A closer look would reveal that this case is trivial and can entirely be understood from the most traditional mathematics, if you interpret $X$ to be $-1$ and $Y$ to be $i$.

$XYY\sim(-1)ii=1,~~ YXY\sim i(-1)i=1,~~ YYX\sim ii(-1)=1,~~ XXX\sim(-1)(-1)(-1)=-1 .$

In [3]:
# Number of qubits
qbNum = 3

# Define the Quantum and Classical Registers
q = QuantumRegister(qbNum)
c = ClassicalRegister(qbNum)

qc = QuantumCircuit(q, c)

# Preparation
# GHZ
qc.h(q[0])
qc.cx(q[0], q[1])
qc.cx(q[0], q[2])

# Circuit building
# Phase shift one qubit, all will shift
qc.t(q[0])
qc.tdg(q[1])
qc.sdg(q[2])

# Finalisation / Measurement
# ...

# Histogram
#job = execute(qc, backend = 'local_qasm_simulator')
#plot_histogram(job.result().get_counts(qc))

# State Vector
job = execute(qc, backend = 'local_statevector_simulator', shots=shots)
print_vec(job.result().get_statevector(qc))

# Block Vector
#bloch = [x0-x1, y0-y1, z0-z1]
#plot_bloch_vector(bloch)

# Check the circuit (must be last or it will not show)
#circuit_drawer(qc)
(0.707+0j)|000> + -0.707j|111>
Out[3]:
array([0.707+0.j   , 0.   +0.j   , 0.   +0.j   , 0.   +0.j   ,
       0.   +0.j   , 0.   +0.j   , 0.   +0.j   , 0.   -0.707j])

 

<< Flip Bits Top Hadamard on Multi-Qubits >>