0% found this document useful (0 votes)
208 views23 pages

Qiskit: First Circuit

This document introduces quantum circuits in Qiskit. It shows how to create circuits with qubits, apply operations like X gates and measure qubits. Specifically, it demonstrates encoding binary numbers on qubits by flipping bits with X gates, then measuring the output. Encoding the numbers 128 and 20 is shown as examples.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
208 views23 pages

Qiskit: First Circuit

This document introduces quantum circuits in Qiskit. It shows how to create circuits with qubits, apply operations like X gates and measure qubits. Specifically, it demonstrates encoding binary numbers on qubits by flipping bits with X gates, then measuring the output. Encoding the numbers 128 and 20 is shown as examples.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 23

Qiskit

In [1]: from
qiskit
import
QuantumCircuit,
assemble,
Aer

from
qiskit.visualization
import
plot_histogram


First circuit
In a circuit, we typically need to do three jobs: First, encode the input, then do some actual
computation, and finally extract an output. For your first quantum circuit, we'll focus on the last of these
jobs. We start by creating a circuit with eight qubits and eight outputs.
In [2]: qc_output
=
QuantumCircuit(8)


his circuit, which we have called qc_output, is created by Qiskit using QuantumCircuit. The
QuantumCircuit takes the number of qubits in the quantum circuit as an argument.
The extraction of outputs in a quantum circuit is done using an operation called measure_all(). Each
measurement tells a specific qubit to give an output to a specific output bit. The command
qc_output.measure_all() adds a measurement to each qubit in the circuit qc_output, and also adds
some classical bits to write the output to.
In [3]: qc_output.measure_all()


In [63]: qc_output.draw(initial_state=True)














░
┌─┐






















Out[63]:


q_0:
|0>─░─┤M├─────────────────────












░
└╥┘┌─┐





















q_1:
|0>─░──╫─┤M├──────────────────












░

║
└╥┘┌─┐


















q_2:
|0>─░──╫──╫─┤M├───────────────












░

║

║
└╥┘┌─┐















q_3:
|0>─░──╫──╫──╫─┤M├────────────












░

║

║

║
└╥┘┌─┐












q_4:
|0>─░──╫──╫──╫──╫─┤M├─────────












░

║

║

║

║
└╥┘┌─┐









q_5:
|0>─░──╫──╫──╫──╫──╫─┤M├──────












░

║

║

║

║

║
└╥┘┌─┐






q_6:
|0>─░──╫──╫──╫──╫──╫──╫─┤M├───












░

║

║

║

║

║

║
└╥┘┌─┐



q_7:
|0>─░──╫──╫──╫──╫──╫──╫──╫─┤M├












░

║

║

║

║

║

║

║
└╥┘

meas:
0
8/════╩══╩══╩══╩══╩══╩══╩══╩═















0

1

2

3

4

5

6

7


In [5]: sim
=
Aer.get_backend('aer_simulator')


result
=
sim.run(qc_output).result()

counts
=
result.get_counts()

plot_histogram(counts)


Out[5]:
Example: Creating an Adder Circuit
Now let's look at how to encode a different binary string as an input. For this, we need what is known as
a NOT gate. This is the most basic operation that you can do in a computer. It simply flips the bit value:
0 becomes 1 and 1 becomes 0. For qubits, it is an operation called x that does the job of the NOT.
Below we create a new circuit dedicated to the job of encoding and call it qc_encode. For now, we only
specify the number of qubits.
In [6]: qc_encode
=
QuantumCircuit(8)

qc_encode.x(7)

qc_encode.draw()














Out[6]:
q_0:
─────













q_1:
─────













q_2:
─────













q_3:
─────













q_4:
─────













q_5:
─────













q_6:
─────






┌───┐

q_7:
┤
X
├






└───┘
In [7]: #€xtracting
results

qc_encode.measure_all()

qc_encode.draw()
















░
┌─┐






















Out[7]:



q_0:
──────░─┤M├─────────────────────















░
└╥┘┌─┐






















q_1:
──────░──╫─┤M├──────────────────















░

║
└╥┘┌─┐



















q_2:
──────░──╫──╫─┤M├───────────────















░

║

║
└╥┘┌─┐
















q_3:
──────░──╫──╫──╫─┤M├────────────















░

║

║

║
└╥┘┌─┐













q_4:
──────░──╫──╫──╫──╫─┤M├─────────















░

║

║

║

║
└╥┘┌─┐










q_5:
──────░──╫──╫──╫──╫──╫─┤M├──────















░

║

║

║

║

║
└╥┘┌─┐







q_6:
──────░──╫──╫──╫──╫──╫──╫─┤M├───









┌───┐
░

║

║

║

║

║

║
└╥┘┌─┐




q_7:
┤
X
├─░──╫──╫──╫──╫──╫──╫──╫─┤M├









└───┘
░

║

║

║

║

║

║

║
└╥┘

meas:
8/═════════╩══╩══╩══╩══╩══╩══╩══╩═


















0

1

2

3

4

5

6

7


In [8]: #look
at
the
results

sim
=
Aer.get_backend('aer_simulator')


result
=
sim.run(qc_encode).result()

counts
=
result.get_counts()

plot_histogram(counts)


Out[8]:

Now our computer outputs the string 10000000 instead.


The bit we flipped, which comes from qubit 7, lives on the far left of the string. This is because Qiskit
numbers the bits in a string from right to left. Some prefer to number their bits the other way around,
but Qiskit's system certainly has its advantages when we are using the bits to represent numbers.
Specifically, it means that qubit 7 is telling us about how many 27
s we have in our number. So by flipping this bit, we’ve now written the number 128 in our simple 8‑bit
computer.
Now try out writing another number for yourself. You could do your age, for example. Just use a search
engine to find out what the number looks like in binary (if it includes a ‘0b’, just ignore it), and then add
some 0s to the left side if you are younger than 128.
In [9]: qc_encode
=
QuantumCircuit(8)

qc_encode.x(1)

qc_encode.x(5)


qc_encode.draw()














Out[9]:
q_0:
─────






┌───┐

q_1:
┤
X
├






└───┘

q_2:
─────













q_3:
─────













q_4:
─────






┌───┐

q_5:
┤
X
├






└───┘

q_6:
─────













q_7:
─────













In quantum computers, the job of the XOR gate is done by the controlled‑NOT gate. Since that's quite a
long name, we usually just call it the CNOT. In Qiskit its name is cx, which is even shorter. 1 2 XOR 0 0 0
110101011
In circuit diagrams, it is drawn as in the image below.
In [10]: qc_cnot
=
QuantumCircuit(2)

qc_cnot.cx(0,1)

qc_cnot.draw()














Out[10]:
q_0:
──■──






┌─┴─┐

q_1:
┤
X
├






└───┘

his is applied to a pair of qubits. One acts as the control qubit (this is the one with the little dot). The
other acts as the target qubit (with the big circle that has a + inside it).
There are multiple ways to explain the effect of the CNOT. One is to say that it looks at its two input bits
to see whether they are the same or different. Next, it overwrites the target qubit with the answer. The
target becomes 0 if they are the same, and 1 if they are different.
Another way of explaining the CNOT is to say that it does a NOT on the target if the control is 1, and
does nothing otherwise. This explanation is just as valid as the previous one (in fact, it’s the one that
gives the gate its name).
Try the CNOT out for yourself by trying each of the possible inputs. For example, here's a circuit that
tests the CNOT with the input 01.
In [11]: qc
=
QuantumCircuit(2,2)

qc.x(0)

qc.cx(0,1)

qc.measure(0,0)

qc.measure(1,1)

qc.draw()







┌───┐




┌─┐




Out[11]:
q_0:
┤
X
├──■──┤M├───






└───┘┌─┴─┐└╥┘┌─┐

q_1:
─────┤
X
├─╫─┤M├











└───┘
║
└╥┘

c:
2/═══════════╩══╩═

















0

1


If you execute this circuit, you’ll find that the output is 11. We can think of this happening because of
either of the following reasons.
The
CNOT
calculates
whether
the
input
values
are
different
and
finds

that
they
are,
which
means
that
it
wants
to
output
1.
It
does
this
by

writing
over
the
state
of
qubit
1
(which,
remember,
is
on
the
left
of

the
bit
string),
turning
01
into
11.


The
CNOT
sees
that
qubit
0
is
in
state
1,
and
so
applies
a
NOT
to
qubit

1.
This
flips
the
0
of
qubit
1
into
a
1,
and
so
turns
01
into
11.


Here is a table showing all the possible inputs and corresponding outputs of the CNOT gate:
Q1 Q0 ‑> Q1 Q0 00 00 01 11 10 10 11 01 For our half adder, we don’t want to overwrite one of our inputs.
Instead, we want to write the result on a different pair of qubits. For this, we can use two CNOTs.
In [12]: qc_ha
=
QuantumCircuit(4,2)

#
encode
inputs
in
qubits
0
and
1

qc_ha.x(0)
#
For
a=0,
remove
this
line.
For
a=1,
leave
it.

qc_ha.x(1)
#
For
b=0,
remove
this
line.
For
b=1,
leave
it.

qc_ha.barrier()

#
use
cnots
to
write
the
XOR
of
the
inputs
on
qubit
2

qc_ha.cx(0,2)

qc_ha.cx(1,2)

qc_ha.barrier()

#
extract
outputs

qc_ha.measure(2,0)
#
extract
XOR
value

qc_ha.measure(3,1)


qc_ha.draw()







┌───┐
░











░








Out[12]:
q_0:
┤
X
├─░───■────────░───────






├───┤
░


│







░








q_1:
┤
X
├─░───┼────■───░───────






└───┘
░
┌─┴─┐┌─┴─┐
░
┌─┐




q_2:
──────░─┤
X
├┤
X
├─░─┤M├───












░
└───┘└───┘
░
└╥┘┌─┐

q_3:
──────░────────────░──╫─┤M├












░











░

║
└╥┘

c:
2/══════════════════════╩══╩═




























0

1


Representing Qubit States


In [13]: from
qiskit
import
QuantumCircuit,
assemble,
Aer

from
qiskit.visualization
import
plot_histogram,
plot_bloch_vector

from
math
import
sqrt,
pi


In [14]: #In
Qiskit,
we
use
the
QuantumCircuit
object
to
store
our
circuits,
this
is
essentially


qc
=
QuantumCircuit(1)
#
Create
a
quantum
circuit
with
one
qubit


In our quantum circuits, our qubits always start out in the state |0⟩. We can use the initialize() method to
transform this into any state. We give initialize() the vector we want in the form of a list, and tell it which
qubit(s) we want to initialize in this state:
In [15]: qc
=
QuantumCircuit(1)

#
Create
a
quantum
circuit
with
one
qubit

initial_state
=
[0,1]


#
Define
initial_state
as
|1>

qc.initialize(initial_state,
0)
#
Apply
initialisation
operation
to
the
0th
qubit

qc.draw()

#
Let's
view
our
circuit





┌─────────────────┐

Out[15]:
q:
┤
Initialize(0,1)
├




└─────────────────┘

In [16]: #We
can
then
use
one
of
Qiskit’s
simulators
to
view
the
resulting
state
of
our
qubit.


sim
=
Aer.get_backend('aer_simulator')

#
Tell
Qiskit
how
to
simulate
our
circuit


To get the results from our circuit, we use run to execute our circuit, giving the circuit and the backend
as arguments. We then use .result() to get the result of this:
In [17]: qc
=
QuantumCircuit(1)

#
Create
a
quantum
circuit
with
one
qubit

initial_state
=
[0,1]


#
Define
initial_state
as
|1>

qc.initialize(initial_state,
0)
#
Apply
initialisation
operation
to
the
0th
qubit

qc.save_statevector()


#
Tell
simulator
to
save
statevector

qobj
=
assemble(qc)




#
Create
a
Qobj
from
the
circuit
for
the
simulator
to
run

result
=
sim.run(qobj).result()
#
Do
the
simulation
and
return
the
result


In [18]: #From
result,
we
can
then
get
the
final
statevector
using
.get_statevector﴾﴿:


out_state
=
result.get_statevector()

print(out_state)
#
Display
the
output
state
vector


Statevector([0.+0.j,
1.+0.j],













dims=(2,))


Note: Python uses j to represent i in complex numbers. We see a vector with two complex elements:
0.+0.j = 0, and 1.+0.j = 1.
In [19]: #Let’s
now
measure
our
qubit
as
we
would
in
a
real
quantum
computer
and
see
the
result:


qc.measure_all()

qc.draw()










┌─────────────────┐
statevector

░
┌─┐

Out[19]:





q:
┤
Initialize(0,1)
├──────░───────░─┤M├









└─────────────────┘





░






░
└╥┘

meas:
1/════════════════════════════════════╩═













































0


In [21]: #This
time,
instead
of
the
statevector
we
will
get
the
counts
for
the
0
and
1
results
us

qobj
=
assemble(qc)

result
=
sim.run(qobj).result()

counts
=
result.get_counts()

plot_histogram(counts)


Out[21]:

We can see that we (unsurprisingly) have a 100% chance of measuring |1⟩. This time, let’s instead put
our qubit into a superposition and see what happens. We will use the state |q0⟩
from earlier in this section: |q0⟩=1√2|0⟩+i√2|1⟩
We need to add these amplitudes to a python list. To add a complex amplitude, Python uses j for the
imaginary unit (we normally call it "i " mathematically):
In [22]: initial_state
=
[1/sqrt(2),
1j/sqrt(2)]

#
Define
state
|q_0>


In [23]: #And
we
then
repeat
the
steps
for
initialising
the
qubit
as
before:


qc
=
QuantumCircuit(1)
#
Must
redefine
qc

qc.initialize(initial_state,
0)
#
Initialize
the
0th
qubit
in
the
state
`initial_state`

qc.save_statevector()
#
Save
statevector

qobj
=
assemble(qc)

state
=
sim.run(qobj).result().get_statevector()
#
Execute
the
circuit

print(state)










#
Print
the
result


Statevector([0.70710678+0.j







,
0.







+0.70710678j],













dims=(2,))


In [24]: qobj
=
assemble(qc)

results
=
sim.run(qobj).result().get_counts()

plot_histogram(results)


Out[24]:

The Rules of Measurement


Very Important Rule
There is a simple rule for measurement. To find the probability of measuring a state |ψ⟩ in the state |x⟩
we do: p(|x⟩)=|⟨x|ψ⟩|2
The symbols ⟨ and | tell us ⟨x| is a row vector and the symbols | and ⟩ tell us |ψ⟩ is a column vector. In
quantum mechanics we call the column vectors kets and the row vectors bras. Together they make up
bra‑ket notation. Any ket |a⟩ has a corresponding bra ⟨a|, and we convert between them using the
conjugate transpose.
Normalisation
The rule shows us that amplitudes are related to probabilities. If we want the probabilities to add up to 1
(which they should!), we need to ensure that the statevector is properly normalized. Specifically, we
need the magnitude of the state vector to be 1.

Single Qubit Gates


In [26]: from
qiskit
import
QuantumCircuit,
assemble,
Aer

from
math
import
pi,
sqrt

from
qiskit.visualization
import
plot_bloch_multivector,
plot_histogram

sim
=
Aer.get_backend('aer_simulator')

The Pauli Gates
You should be familiar with the Pauli matrices from the linear algebra section. If any of the maths here is
new to you, you should use the linear algebra section to bring yourself up to speed. We will see here
that the Pauli matrices can represent some very commonly used quantum gates. 1.1 The X‑Gate
In [27]: #
Let's
do
an
X­gate
on
a
|0>
qubit

qc
=
QuantumCircuit(1)

qc.x(0)

qc.draw()





┌───┐

Out[27]:
q:
┤
X
├




└───┘

In [28]: #Let's
see
the
result
of
the
above
circuit.
Note:
Here
we
use
plot_bloch_multivector﴾﴿
w

#
Let's
see
the
result

qc.save_statevector()

qobj
=
assemble(qc)

state
=
sim.run(qobj).result().get_statevector()

plot_bloch_multivector(state)


Out[28]:

In [29]: #The
Y
&
Z­gates

#Below
is
a
widget
that
displays
a
qubit’s
state
on
the
Bloch
sphere,
pressing
one
of
th

#
Run
the
code
in
this
cell
to
see
the
widget

from
qiskit_textbook.widgets
import
gate_demo

gate_demo(gates='pauli')


­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­

ModuleNotFoundError






















Traceback
(most
recent
call
last)

/var/folders/nd/vzx00q0j5615sxcrs0qldzh80000gn/T/ipykernel_2157/4291737448.py
in
<module
>







3








4
#
Run
the
code
in
this
cell
to
see
the
widget

­­­­>
5
from
qiskit_textbook.widgets
import
gate_demo







6
gate_demo(gates='pauli')


ModuleNotFoundError:
No
module
named
'qiskit_textbook'

In [30]: #In
Qiskit,
we
can
apply
the
Y
and
Z­gates
to
our
circuit
using:


qc.y(0)
#
Do
Y­gate
on
qubit
0

qc.z(0)
#
Do
Z­gate
on
qubit
0

qc.draw()





┌───┐
statevector
┌───┐┌───┐

Out[30]:
q:
┤
X
├──────░──────┤
Y
├┤
Z
├




└───┘





░





└───┘└───┘

The Hadamard Gate


The Hadamard gate (H‑gate) is a fundamental quantum gate. It allows us to move away from the poles
of the Bloch sphere and create a superposition of |0⟩ and |1⟩. It has the matrix:
In [31]: #This
can
be
thought
of
as
a
rotation
around
the
Bloch
vector
[1,0,1]
﴾the
line
between


#You
can
play
around
with
these
gates
using
the
widget
below:


#
Run
the
code
in
this
cell
to
see
the
widget

from
qiskit_textbook.widgets
import
gate_demo

gate_demo(gates='pauli+h')


­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­

ModuleNotFoundError






















Traceback
(most
recent
call
last)

/var/folders/nd/vzx00q0j5615sxcrs0qldzh80000gn/T/ipykernel_2157/1957695400.py
in
<module
>







4








5
#
Run
the
code
in
this
cell
to
see
the
widget

­­­­>
6
from
qiskit_textbook.widgets
import
gate_demo







7
gate_demo(gates='pauli+h')


ModuleNotFoundError:
No
module
named
'qiskit_textbook'

The P‑gate
The P‑gate (phase gate) is parametrised, that is, it needs a number (ϕ ) to tell it exactly what to do. The
P‑gate performs a rotation of ϕ around the Z‑axis direction. It has the matrix form:
In [33]: #You
can
use
the
widget
below
to
play
around
with
the
P­gate,
specify
ϕ


#using
the
slider:


#
Run
the
code
in
this
cell
to
see
the
widget

from
qiskit_textbook.widgets
import
gate_demo

gate_demo(gates='pauli+h+p')


­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­

ModuleNotFoundError






















Traceback
(most
recent
call
last)

/var/folders/nd/vzx00q0j5615sxcrs0qldzh80000gn/T/ipykernel_2157/3404144451.py
in
<module
>







4








5
#
Run
the
code
in
this
cell
to
see
the
widget

­­­­>
6
from
qiskit_textbook.widgets
import
gate_demo







7
gate_demo(gates='pauli+h+p')


ModuleNotFoundError:
No
module
named
'qiskit_textbook'
In [34]: #
In
Qiskit,
we
specify
a
P­gate
using
p﴾phi,
qubit﴿:


qc
=
QuantumCircuit(1)

qc.p(pi/4,
0)

qc.draw()





┌────────┐

Out[34]:
q:
┤
P(π/4)
├




└────────┘

The I, S and T‑gates


6.1 The I‑gate
First comes the I‑gate (aka ‘Id‑gate’ or ‘Identity gate’). This is simply a gate that does nothing. Its
matrix is the identity matrix:
In [35]: #
To
add
an
S­gate
in
Qiskit:


qc
=
QuantumCircuit(1)

qc.s(0)


#
Apply
S­gate
to
qubit
0

qc.sdg(0)
#
Apply
Sdg­gate
to
qubit
0

qc.draw()





┌───┐┌─────┐

Out[35]:
q:
┤
S
├┤
Sdg
├




└───┘└─────┘

The T‑gate
The T‑gate is a very commonly used gate, it is an P‑gate with ϕ=π/4 :
In [36]: qc
=
QuantumCircuit(1)

qc.t(0)


#
Apply
T­gate
to
qubit
0

qc.tdg(0)
#
Apply
Tdg­gate
to
qubit
0

qc.draw()





┌───┐┌─────┐

Out[36]:
q:
┤
T
├┤
Tdg
├




└───┘└─────┘

In [37]: #
Run
the
code
in
this
cell
to
see
the
widget

from
qiskit_textbook.widgets
import
gate_demo

gate_demo()


­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­

ModuleNotFoundError






















Traceback
(most
recent
call
last)

/var/folders/nd/vzx00q0j5615sxcrs0qldzh80000gn/T/ipykernel_2157/4127987965.py
in
<module
>







1
#
Run
the
code
in
this
cell
to
see
the
widget

­­­­>
2
from
qiskit_textbook.widgets
import
gate_demo







3
gate_demo()


ModuleNotFoundError:
No
module
named
'qiskit_textbook'

The U‑gate
As we saw earlier, the I, Z, S & T‑gates were all special cases of the more general P‑gate. In the same
way, the U‑gate is the most general of all single‑qubit quantum gates. It is a parametrised gate of the
form:
In [38]: #
Let's
have
U­gate
transform
a
|0>
to
|+>
state

qc
=
QuantumCircuit(1)

qc.u(pi/2,
0,
pi,
0)

qc.draw()





┌────────────┐

Out[38]:
q:
┤
U(π/2,0,π)
├




└────────────┘

In [39]: #
Let's
see
the
result

qc.save_statevector()

qobj
=
assemble(qc)

state
=
sim.run(qobj).result().get_statevector()

plot_bloch_multivector(state)


Out[39]:

Representing Multi‑Qubit States


In [40]: from
qiskit
import
QuantumCircuit,
Aer,
assemble

import
numpy
as
np

from
qiskit.visualization
import
plot_histogram,
plot_bloch_multivector


In [41]: qc
=
QuantumCircuit(3)

#
Apply
H­gate
to
each
qubit:

for
qubit
in
range(3):





qc.h(qubit)

#
See
the
circuit:

qc.draw()







┌───┐

Out[41]:
q_0:
┤
H
├






├───┤

q_1:
┤
H
├






├───┤

q_2:
┤
H
├






└───┘
In [42]: #
Let's
see
the
result

svsim
=
Aer.get_backend('aer_simulator')

qc.save_statevector()

qobj
=
assemble(qc)

final_state
=
svsim.run(qobj).result().get_statevector()


#
In
Jupyter
Notebooks
we
can
display
this
nicely
using
Latex.

#
If
not
using
Jupyter
Notebooks
you
may
need
to
remove
the


#
array_to_latex
function
and
use
print﴾final_state﴿
instead.

from
qiskit.visualization
import
array_to_latex

array_to_latex(final_state,
prefix="\\text{Statevector}
=
")


Out[42]:
√2 √2 √2 √2 √2 √2 √2 √2
Statevector = [ ]
4 4 4 4 4 4 4 4

In [44]: #For
example,
in
the
circuit
below:


qc
=
QuantumCircuit(2)

qc.h(0)

qc.x(1)

qc.draw()


#we
can
represent
the
simultaneous
operations
﴾H
&
X﴿
using
their
kronecker
product:







┌───┐

Out[44]:
q_0:
┤
H
├






├───┤

q_1:
┤
X
├






└───┘

In [45]: #The
Aer
simulator
multiplies
all
the
gates
in
our
circuit
together
to
compile
a
single


usim
=
Aer.get_backend('aer_simulator')

qc.save_unitary()

qobj
=
assemble(qc)

unitary
=
usim.run(qobj).result().get_unitary()


In [46]: #
In
Jupyter
Notebooks
we
can
display
this
nicely
using
Latex.

#
If
not
using
Jupyter
Notebooks
you
may
need
to
remove
the


#
array_to_latex
function
and
use
print﴾unitary﴿
instead.

from
qiskit.visualization
import
array_to_latex

array_to_latex(unitary,
prefix="\\text{Circuit
=
}\n")


Out[46]:
√2 √2
0 0
⎡ 2 2 ⎤

⎢
 √2 √2 ⎥

⎢
 0 0 − ⎥

⎢
 2 2 ⎥

Circuit
=  ⎢
 ⎥

⎢
 √2 √2 ⎥

⎢
 0 0 ⎥

⎢
 2 2 ⎥

⎢ ⎥
√2 √2
⎣ − 0 0 ⎦
2 2

In [47]: #If
we
want
to
apply
a
gate
to
only
one
qubit
at
a
time
﴾such
as
in
the
circuit
below﴿,


qc
=
QuantumCircuit(2)

qc.x(1)

qc.draw()














Out[47]:
q_0:
─────






┌───┐

q_1:
┤
X
├






└───┘

In [48]: #
Simulate
the
unitary

usim
=
Aer.get_backend('aer_simulator')

qc.save_unitary()

qobj
=
assemble(qc)

unitary
=
usim.run(qobj).result().get_unitary()

#
Display
the
results:

array_to_latex(unitary,
prefix="\\text{Circuit
=
}
")


Out[48]:
0 0 1 0
⎡ ⎤
0 0 0 1
⎢
 ⎥

Circuit
=  ⎢
 ⎥

⎢1 0 0 0⎥
⎣ ⎦
0 1 0 0

Multi‑Qubit Gates
Now we know how to represent the state of multiple qubits, we are now ready to learn how qubits
interact with each other. An important two‑qubit gate is the CNOT‑gate.
The CNOT‑Gate
You have come across this gate before in The Atoms of Computation. This gate is a conditional gate
that performs an X‑gate on the second qubit (target), if the state of the first qubit (control) is |1⟩ . The
gate is drawn on a circuit like this, with q0 as the control and q1 as the target:
In [51]: qc
=
QuantumCircuit(2)

#
Apply
CNOT

qc.cx(0,1)

#
See
the
circuit:

qc.draw()














Out[51]:
q_0:
──■──






┌─┴─┐

q_1:
┤
X
├






└───┘

In [52]: qc
=
QuantumCircuit(2)

#
Apply
CNOT

qc.cx(0,1)

#
See
the
circuit:

qc.draw('mpl')


Out[52]:

In [53]: qc
=
QuantumCircuit(2)

#
Apply
H­gate
to
the
first:

qc.h(0)

qc.draw()







┌───┐

Out[53]:
q_0:
┤
H
├






└───┘

q_1:
─────













In [54]: qc
=
QuantumCircuit(2)

#
Apply
H­gate
to
the
first:

qc.h(0)

qc.draw('mpl')


Out[54]:

In [55]: #
Let's
see
the
result:

svsim
=
Aer.get_backend('aer_simulator')

qc.save_statevector()

qobj
=
assemble(qc)

final_state
=
svsim.run(qobj).result().get_statevector()

#
Print
the
statevector
neatly:

array_to_latex(final_state,
prefix="\\text{Statevector
=
}")


Out[55]:
√2 √2
Statevector
=  [ 0 0]
2 2

In [56]: qc
=
QuantumCircuit(2)

#
Apply
H­gate
to
the
first:

qc.h(0)

#
Apply
a
CNOT:

qc.cx(0,1)

qc.draw()







┌───┐






Out[56]:
q_0:
┤
H
├──■──






└───┘┌─┴─┐

q_1:
─────┤
X
├











└───┘

In [57]: qc
=
QuantumCircuit(2)

#
Apply
H­gate
to
the
first:

qc.h(0)

#
Apply
a
CNOT:

qc.cx(0,1)

qc.draw('mpl')


Out[57]:
In [58]: #
Let's
get
the
result:

qc.save_statevector()

qobj
=
assemble(qc)

result
=
svsim.run(qobj).result()

#
Print
the
statevector
neatly:

final_state
=
result.get_statevector()

array_to_latex(final_state,
prefix="\\text{Statevector
=
}")


Out[58]:
√2 √2
Statevector
=  [ 0 0 ]
2 2

Entangled States
We saw in the previous section we could create the state: 1√2(|00⟩+|11⟩)
This is known as a Bell state. We can see that this state has 50% probability of being measured in the
state |00⟩ , and 50% chance of being measured in the state |11⟩. Most interestingly, it has a 0% chance
of being measured in the states |01⟩ or |10⟩. We can see this in Qiskit:
In [59]: plot_histogram(result.get_counts())


Out[59]:
Visualizing Entangled States
We have seen that this state cannot be written as two separate qubit states, this also means we lose
information when we try to plot our state on separate Bloch spheres:
In [60]: plot_bloch_multivector(final_state)


Out[60]:

Given how we defined the Bloch sphere in the earlier chapters, it may not be clear how Qiskit even
calculates the Bloch vectors with entangled qubits like this. In the single‑qubit case, the position of the
Bloch vector along an axis nicely corresponds to the expectation value of measuring in that basis. If we
take this as the rule of plotting Bloch vectors, we arrive at this conclusion above. This shows us there is
no single‑qubit measurement basis for which a specific measurement is guaranteed. This contrasts
with our single qubit states, in which we could always pick a single‑qubit basis. Looking at the individual
qubits in this way, we miss the important effect of correlation between the qubits. We cannot
distinguish between different entangled states. For example, the two states:
1√2(|01⟩+|10⟩)and1√2(|00⟩+|11⟩)
will both look the same on these separate Bloch spheres, despite being very different states with
different measurement outcomes.
How else could we visualize this statevector? This statevector is simply a collection of four amplitudes
(complex numbers), and there are endless ways we can map this to an image. One such visualization is
the Q‑sphere, here each amplitude is represented by a blob on the surface of a sphere. The size of the
blob is proportional to the magnitude of the amplitude, and the colour is proportional to the phase of
the amplitude. The amplitudes for |00⟩ and |11⟩ are equal, and all other amplitudes are 0:
In [61]: from
qiskit.visualization
import
plot_state_qsphere

plot_state_qsphere(final_state)


Out[61]:
Shor's Algorithm
Shor’s algorithm is famous for factoring integers in polynomial time. Since the best‑known classical
algorithm requires superpolynomial time to factor the product of two primes, the widely used
cryptosystem, RSA, relies on factoring being impossible for large enough integers.
In this chapter we will focus on the quantum part of Shor’s algorithm, which actually solves the problem
of period finding. Since a factoring problem can be turned into a period finding problem in polynomial
time, an efficient period finding algorithm can be used to factor integers efficiently too.
In [64]: import
matplotlib.pyplot
as
plt

import
numpy
as
np

from
qiskit
import
QuantumCircuit,
Aer,
transpile,
assemble

from
qiskit.visualization
import
plot_histogram

from
math
import
gcd

from
numpy.random
import
randint

import
pandas
as
pd

from
fractions
import
Fraction

print("Imports
Successful")


Imports
Successful


In [65]: def
c_amod15(a,
power):





"""Controlled
multiplication
by
a
mod
15"""





if
a
not
in
[2,4,7,8,11,13]:









raise
ValueError("'a'
must
be
2,4,7,8,11
or
13")





U
=
QuantumCircuit(4)













for
iteration
in
range(power):









if
a
in
[2,13]:













U.swap(2,3)













U.swap(1,2)













U.swap(0,1)









if
a
in
[7,8]:













U.swap(0,1)













U.swap(1,2)













U.swap(2,3)









if
a
in
[4,
11]:













U.swap(1,3)













U.swap(0,2)









if
a
in
[7,11,13]:













for
q
in
range(4):

















U.x(q)





U
=
U.to_gate()





U.name
=
"%i^%i
mod
15"
%
(a,
power)





c_U
=
U.control()





return
c_U


In [66]: #
Specify
variables

n_count
=
8

#
number
of
counting
qubits

a
=
7


In [67]: def
qft_dagger(n):





"""n­qubit
QFTdagger
the
first
n
qubits
in
circ"""





qc
=
QuantumCircuit(n)





#
Don't
forget
the
Swaps!





for
qubit
in
range(n//2):









qc.swap(qubit,
n­qubit­1)





for
j
in
range(n):









for
m
in
range(j):













qc.cp(­np.pi/float(2**(j­m)),
m,
j)









qc.h(j)





qc.name
=
"QFT†"





return
qc


In [68]: #
Create
QuantumCircuit
with
n_count
counting
qubits

#
plus
4
qubits
for
U
to
act
on

qc
=
QuantumCircuit(n_count
+
4,
n_count)


#
Initialize
counting
qubits

#
in
state
|+>

for
q
in
range(n_count):





qc.h(q)







#
And
auxiliary
register
in
state
|1>

qc.x(n_count)


#
Do
controlled­U
operations

for
q
in
range(n_count):





qc.append(c_amod15(a,
2**q),















[q]
+
[i+n_count
for
i
in
range(4)])


#
Do
inverse­QFT

qc.append(qft_dagger(n_count),
range(n_count))


#
Measure
circuit

qc.measure(range(n_count),
range(n_count))

qc.draw(fold=­1)

#
­1
means
'do
not
fold'









┌───┐








































































Out[68]:

q_0:
┤
H
├───────■────────────────────────────────────────────────────────────────






├───┤






│

































































q_1:
┤
H
├───────┼──────────────■─────────────────────────────────────────────────






├───┤






│













│


















































q_2:
┤
H
├───────┼──────────────┼──────────────■──────────────────────────────────






├───┤






│













│













│



































q_3:
┤
H
├───────┼──────────────┼──────────────┼──────────────■───────────────────






├───┤






│













│













│













│




















q_4:
┤
H
├───────┼──────────────┼──────────────┼──────────────┼──────────────■────






├───┤






│













│













│













│













│





q_5:
┤
H
├───────┼──────────────┼──────────────┼──────────────┼──────────────┼────






├───┤






│













│













│













│













│





q_6:
┤
H
├───────┼──────────────┼──────────────┼──────────────┼──────────────┼────






├───┤






│













│













│













│













│





q_7:
┤
H
├───────┼──────────────┼──────────────┼──────────────┼──────────────┼────






├───┤┌──────┴──────┐┌──────┴──────┐┌──────┴──────┐┌──────┴──────┐┌──────┴────

q_8:
┤
X
├┤0











├┤0











├┤0











├┤0











├┤0
















└───┘│












││












││












││












││












q_9:
─────┤1











├┤1











├┤1











├┤1











├┤1





















│

7^1
mod
15
││

7^2
mod
15
││

7^4
mod
15
││

7^8
mod
15
││

7^16
mod

q_10:
─────┤2











├┤2











├┤2











├┤2











├┤2





















│












││












││












││












││











q_11:
─────┤3











├┤3











├┤3











├┤3











├┤3





















└─────────────┘└─────────────┘└─────────────┘└─────────────┘└───────────

c:
8/═════════════════════════════════════════════════════════════════════════════





















































































In [69]: qc.draw('mpl')


Out[69]:
In [70]: aer_sim
=
Aer.get_backend('aer_simulator')

t_qc
=
transpile(qc,
aer_sim)

qobj
=
assemble(t_qc)

results
=
aer_sim.run(qobj).result()

counts
=
results.get_counts()

plot_histogram(counts)


Out[70]:
In [71]: rows,
measured_phases
=
[],
[]

for
output
in
counts:





decimal
=
int(output,
2)

#
Convert
﴾base
2﴿
string
to
decimal





phase
=
decimal/(2**n_count)

#
Find
corresponding
eigenvalue





measured_phases.append(phase)





#
Add
these
values
to
the
rows
in
our
table:





rows.append([f"{output}(bin)
=
{decimal:>3}(dec)",



















f"{decimal}/{2**n_count}
=
{phase:.2f}"])

#
Print
the
rows
in
a
table

headers=["Register
Output",
"Phase"]

df
=
pd.DataFrame(rows,
columns=headers)

print(df)














Register
Output










Phase

0

00000000(bin)
=


0(dec)



0/256
=
0.00

1

11000000(bin)
=
192(dec)

192/256
=
0.75

2

10000000(bin)
=
128(dec)

128/256
=
0.50

3

01000000(bin)
=

64(dec)


64/256
=
0.25


In [72]: Fraction(0.666)


Fraction(5998794703657501,
9007199254740992)
Out[72]:

In [73]: #
Get
fraction
that
most
closely
resembles
0.666

#
with
denominator
<
15

Fraction(0.666).limit_denominator(15)


Fraction(2,
3)
Out[73]:

In [74]: rows
=
[]

for
phase
in
measured_phases:





frac
=
Fraction(phase).limit_denominator(15)





rows.append([phase,
f"{frac.numerator}/{frac.denominator}",
frac.denominator])

#
Print
as
a
table

headers=["Phase",
"Fraction",
"Guess
for
r"]

df
=
pd.DataFrame(rows,
columns=headers)

print(df)





Phase
Fraction

Guess
for
r

0


0.00





0/1











1

1


0.75





3/4











4

2


0.50





1/2











2

3


0.25





1/4











4


In [75]: rows
=
[]

for
phase
in
measured_phases:





frac
=
Fraction(phase).limit_denominator(15)





rows.append([phase,
f"{frac.numerator}/{frac.denominator}",
frac.denominator])

#
Print
as
a
table

headers=["Phase",
"Fraction",
"Guess
for
r"]

df
=
pd.DataFrame(rows,
columns=headers)

print(df)





Phase
Fraction

Guess
for
r

0


0.00





0/1











1

1


0.75





3/4











4

2


0.50





1/2











2

3


0.25





1/4











4


In [76]: a2jmodN(7,
2049,
53)


­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­

NameError
































Traceback
(most
recent
call
last)

/var/folders/nd/vzx00q0j5615sxcrs0qldzh80000gn/T/ipykernel_2157/108858282.py
in
<module>

­­­­>
1
a2jmodN(7,
2049,
53)


NameError:
name
'a2jmodN'
is
not
defined

In [ ]: 



You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy