Home | Algorithms | Commercialization | Data Science | Information Theories | Quantum Theories | Lab | Linear Algebra |
<< Quantum Logic Gates | Square Root of Quantum Gates >> |
$\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}$
First created in August 2018
In this page, these conventions are followed:
$q_0\otimes q_1\otimes\ldots\otimes q_{n-1}.$
# Preamble
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 = 1024
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
From the $cX$ definition, the non-control qubit is the LSD. i.e. In $cU\Ket{ij}, i$ is the control and $j$ is to be acted on, or "qc.cx(q[0], q[1])" based on our convention.
$cX= \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 \end{bmatrix} .$
If we switch the two, $c'X$ is to take $j$ as the control and act on $i$, $c'X= \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0 \end{bmatrix} ,~~$ equivalent to "qc.cx(q[1], q[0])".
One interesting fact is that $c'X=(H\otimes H)~cX~(H\otimes H).$ This means if $cX$ is applied to a Hardama basis, it is the control qubit that will be flipped.
Here $cX_{01}:=cX$ and $cX_{10}:=c'X.$
$(H\otimes H)~cX_{01}~(H\otimes H)=cX_{10}.$
Proof: $(H\otimes H)~cX_{01}~(H\otimes H) =\Rsr2 \begin{bmatrix} H&H\\ H&-H \end{bmatrix} \begin{bmatrix} I&0\\ 0&X \end{bmatrix} \Rsr2 \begin{bmatrix} H&H\\ H&-H \end{bmatrix}\\ ={1\over2} \begin{bmatrix} H&H\\ H&-H \end{bmatrix} \begin{bmatrix} IH&IH\\ XH&-XH \end{bmatrix} ={1\over2} \begin{bmatrix} HIH+HXH&HIH-HXH\\ HIH-HXH&HIH+HXH \end{bmatrix}\\ ={1\over2} \begin{bmatrix} I+Z&I-Z\\ I-Z&I+Z \end{bmatrix} =\begin{bmatrix} 1&0&0&0\\ 0&0&0&1\\ 0&0&1&0\\ 0&1&0&0\\ \end{bmatrix} =cX_{10} .$
Note: $H^2=I$, $HXH=Z$ and $HZH=X$.
# (HH)cX01(HH)
qbNum = 2
q = QuantumRegister(qbNum)
c = ClassicalRegister(qbNum)
qc = QuantumCircuit(q, c)
qc.h(q)
qc.cx(q[0], q[1])
qc.h(q)
job = execute(qc, backend = 'local_statevector_simulator', shots=shots)
print_vec(job.result().get_statevector(qc))
circuit_drawer(qc)
# The above is equivalent to ...
# cX10
qbNum = 2
q = QuantumRegister(qbNum)
c = ClassicalRegister(qbNum)
qc = QuantumCircuit(q, c)
#qc.x(q[1])
qc.cx(q[1], q[0])
job = execute(qc, backend = 'local_statevector_simulator', shots=shots)
print_vec(job.result().get_statevector(qc))
circuit_drawer(qc)
The $SWAP$ gate swaps two qubits, not the two basis vectors of a single qubit (as in $X$).
Let $\Ket\psi=\alpha\Ket0+\beta\Ket1=[\alpha,\beta]^T,~~ X\Ket\psi=\beta\Ket0+\alpha\Ket1=[\beta,\alpha]^T.$
Let $\Ket\phi=\alpha\Ket{00}+\beta\Ket{01}+\gamma\Ket{10}+\delta\Ket{11} =[\alpha,\beta,\gamma,\delta]^T,~~ SWAP\Ket\phi=\alpha\Ket{00}+\gamma\Ket{01}+\beta\Ket{10}+\delta\Ket{11} =[\alpha,\gamma,\beta,\delta]^T.$
Or in an unentangled form: $\Ket\phi=(a\Ket0+b\Ket1)(c\Ket0+d\Ket1),$
$SWAP\Ket\phi =SWAP(ac\Ket{00}+ad\Ket{01}+bc\Ket{10}+bd\Ket{11} =(ac\Ket{00}+bc\Ket{01}+ad\Ket{10}+bd\Ket{11}\\ =(c\Ket0+d\Ket1)(a\Ket0+b\Ket1) .$
$SWAP= \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1 \end{bmatrix} .~~~ SWAP^2=I,~~~ SWAP^\dagger=SWAP,~~~$so $SWAP$ is unitary.
A SWAP gate is equivalent to
$cX~c'X~cX =\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 \end{bmatrix} =\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1 \end{bmatrix} =SWAP .$
# cX01 cX10 cX01
qbNum = 2
q = QuantumRegister(qbNum)
c = ClassicalRegister(qbNum)
# Prepare a 2-qubit state
# with q_0=(pi/2,pi/4)
# and q_1=(pi/4,3pi/2)
prep = QuantumCircuit(q, c)
prep.h(q[0])
prep.t(q[0])
prep.h(q[1])
prep.t(q[1])
prep.h(q[1])
job = execute(prep, backend = 'local_statevector_simulator', shots=shots)
print_vec(job.result().get_statevector(prep))
# Equivalent to SWAP
swap = QuantumCircuit(q, c)
swap.cx(q[0], q[1])
swap.cx(q[1], q[0])
swap.cx(q[0], q[1])
qc = prep + swap
job = execute(qc, backend = 'local_statevector_simulator', shots=shots)
print_vec(job.result().get_statevector(qc))
circuit_drawer(swap)
<< Quantum Logic Gates | Top | Square Root of Quantum Gates >> |