Skip to content
Azavea
Share
Explore
other samples

icon picker
refactorable Qiskit

On this page, I’m hoping to go through a description of a few Qiskit programs, describe what is happening, and then consider ways that the code could be more pythonic.

Teleportation

The teleportation protocol is one of coolest things one will first encounter when learning about quantum computing. Thankfully, qiskit provides us with all of the tools necessary to run a teleportation operation.
The basic circuit for quantum teleportation requires a setup of 2 registers:
1
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute, Aer, IBMQ, BasicAer
import math

# Set up the program
alice = QuantumRegister(1, name='alice')
ep = QuantumRegister(1, name='ep')
bob = QuantumRegister(1, name='bob')
alice_c = ClassicalRegister(1, name='alicec')
ep_c = ClassicalRegister(1, name='epc')
bob_c = ClassicalRegister(1, name='bobc')
qc = QuantumCircuit(alice, ep, bob, alice_c, ep_c, bob_c)
consideration:
the code feels a little “boilerplate”. I wonder about creating a function that do away with some bulk.
There are no rows in this table
The story of teleportation is usually described by the following story: somehow, Alice and Bob share a pair of qubits, entangled into one of the four Bell states. They can go far away from each other, and once one of them has (quantum) information they’d like to transmit, they entangle that qubit state with their own half of the entangled Bell pair. They then measure their basis states, and classically send them over a channel, and the receiver must apply some unitary transformation to their own qubit, at which point their qubit is ensured to be in the state of the qubit that was sent.
1
the ep qubit is entangled with bob’s qubit, by first applying a hadamard gate to the qubit, and then performing a controlled NOT gate from the ep to bob’s.
2
qc.h(ep)
qc.cx(ep, bob)
3
alice’s state is prepared.
4
# prep payload
qc.reset(alice)
qc.h(alice)
qc.rz(math.radians(45), alice)
qc.h(alice)
consideration:
when working with Qiskit, there are a lot of instances where the code seems a little redundant; something that is a little more functional (i.e. lambda functional) would be interesting.
5
then measure the qubits, and apply the necessary unitary gates:
6
# send
qc.cx(alice, ep)
qc.h(alice)
qc.measure(alice, alice_c)
qc.measure(ep, ep_c)
qc.barrier()

# receive
qc.z(bob).c_if(alice_c, 1)
qc.x(bob).c_if(ep_c, 1)

# verify
qc.h(bob)
qc.rz(math.radians(-45), bob)
qc.h(bob)
qc.measure(bob, bob_c)
There are no rows in this table

When using Qiskit, it is not at all uncommon to work with Aer or BasicAer. I’m not sure why these things are separated from the main Qiskit package, as they seem pretty entangled in most current use-cases to me. I’m sure theres some key information I’m not seeing, but in any case, we can execute the Qiskit program by setting up the backend, the execution function, and get the result. The result will always be that the output state is the same as the one Alice transmitted
1
backend = BasicAer.get_backend('statevector_simulator')
job = execute(qc, backend)
result = job.result()

counts = result.get_counts(qc)
print('counts:',counts)

outputstate = result.get_statevector(qc, decimals=3)
print(outputstate)
qc.draw()
There are no rows in this table

There are a number of ways teleportation protocol can be achieved. Vazirani’s description in his series of YouTube lectures I have found to be the best; they helped me to understand, mathematically, what was happening in Nielsen and Chuang’s description. The scenario is slightly different than what the O’Reilly book provides; I think by simply changing which qubit is named “Alice” would make the protocol as a whole a bit more intuitive.

QFT


1
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute, Aer, IBMQ, BasicAer
import math

reg = QuantumRegister(4, name='reg')
scratch = QuantumRegister(1, name='scratch')
qc = QuantumCircuit(reg, scratch)
There are no rows in this table

1
def main():
n2f = [0,1,2]
number_of_iterations = 5

qc.h(reg)

for i in range(number_of_iterations):
## Flip the marked value
qc.barrier()
for number_to_flip in n2f:
x_bits = ~number_to_flip
x_list = [reg[x] for x in range(len(reg)) if x_bits & (1 << x)]
qc.x(x_list)
multi_cz([x for x in reg])
qc.x(x_list)

qc.barrier()
Grover(reg)
There are no rows in this table

1

def Grover(qreg, condition_qubits=None):
if condition_qubits is None:
condition_qubits = []
qc.h(qreg)
qc.x(qreg)
multi_cz([x for x in qreg] + condition_qubits)
qc.x(qreg)
qc.h(qreg)
There are no rows in this table
1
def multi_cz(qubits):
## This will perform a CCCCCZ on as many qubits as we want,
## as long as we have enough scratch qubits
multi_cx(qubits, do_cz=True)

def multi_cx(qubits, do_cz=False):
## This will perform a CCCCCX with as many conditions as we want,
## as long as we have enough scratch qubits
## The last qubit in the list is the target.
target = qubits[-1]
conds = qubits[:-1]
scratch_index = 0
ops = []
while len(conds) > 2:
new_conds = []
for i in range(len(conds)//2):
ops.append((conds[i * 2], conds[i * 2 + 1], scratch[scratch_index]))
new_conds.append(scratch[scratch_index])
scratch_index += 1
if len(conds) & 1:
new_conds.append(conds[-1])
conds = new_conds
for op in ops:
qc.ccx(op[0], op[1], op[2])
if do_cz:
qc.h(target)
if len(conds) == 0:
qc.x(target)
elif len(conds) == 1:
qc.cx(conds[0], target)
else:
qc.ccx(conds[0], conds[1], target)
if do_cz:
qc.h(target)
ops.reverse()
for op in ops:
qc.ccx(op[0], op[1], op[2])

main()
There are no rows in this table
1
backend = BasicAer.get_backend('statevector_simulator')
job = execute(qc, backend)
result = job.result()

outputstate = result.get_statevector(qc, decimals=3)
total_prob = 0
for i,amp in enumerate(outputstate):
if abs(amp) > 0.000001:
prob = abs(amp) * abs(amp)
total_prob += prob
print('|{}> {} probability = {}%'.format(i, amp, round(prob * 100, 5)))
print('Total probability: {}%'.format(int(round(total_prob * 100))))
qc.draw() # draw the circuit
There are no rows in this table
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.