A code repository for tutorial https://mareknarozniak.com/2020/06/09/simulating-superdense-coding/
import qiskit | |
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister | |
import itertools | |
def makeCircuit(N): | |
q = QuantumRegister(2) | |
c = ClassicalRegister(2) | |
qc = QuantumCircuit(q, c) | |
return q, c, qc | |
def superDenseCoding(b1, b2, backend, shots=1024, basis_gates=None, noise_model=None, draw_diagram=False): | |
q, c, qc = makeCircuit(2) | |
# prepare share entangled state | |
qc.h(q[0]) | |
qc.cx(q[0], q[1]) | |
# superdense coding operation depend on sended binary bits | |
# this part of the circuit is classically controlled | |
if b1: | |
qc.x(q[0]) | |
if b2: | |
qc.z(q[0]) | |
# suppose q0 register is sent to receiver | |
# decode the transfered information by the receiver | |
qc.cx(q[0], q[1]) | |
qc.h(q[0]) | |
# measurement | |
qc.measure(q, c) | |
# build diagram for visualisation | |
diagram = None | |
if draw_diagram: | |
diagram = qc.draw(output="mpl") | |
# perform simulation and extract counts | |
job = qiskit.execute( | |
qc, backend, | |
shots=shots, | |
basis_gates=basis_gates, | |
noise_model=noise_model) | |
result = job.result() | |
counts = result.get_counts() | |
comb = ["".join(seq) for seq in itertools.product('01', repeat=2)] | |
for key in comb: | |
if key not in counts.keys(): | |
counts[key] = 0 | |
# return everything | |
return qc, diagram, counts | |
def simulateCommunicationChannel(b1, b2, backend, basis_gates=None, noise_model=None): | |
_, _, counts = superDenseCoding(b1, b2, backend, shots=1, basis_gates=basis_gates, noise_model=noise_model) | |
received_b1 = None | |
received_b2 = None | |
combinations = list(itertools.product([0, 1], repeat=2)) | |
for cb1, cb2 in combinations: | |
index = str(cb1) + str(cb2) | |
if counts[index] == 1: | |
received_b1 = cb1 | |
received_b2 = cb2 | |
return received_b1, received_b2 |
import numpy as np | |
from PIL import Image | |
from qiskit import Aer | |
import qiskit.providers.aer.noise as noise | |
from qm import simulateCommunicationChannel | |
# Error probabilities | |
# play with those values and look how the file received_mario_sprite.bmp changes compared to mario_sprite.bmp | |
prob_1 = 0.15 # 1-qubit gate | |
prob_2 = prob_1 # 2-qubit gate | |
# Depolarizing quantum errors | |
error_1 = noise.depolarizing_error(prob_1, 1) | |
error_2 = noise.depolarizing_error(prob_2, 2) | |
# Add errors to noise model | |
noise_model = noise.NoiseModel() | |
noise_model.add_all_qubit_quantum_error(error_1, ['u1', 'u2', 'u3']) | |
noise_model.add_all_qubit_quantum_error(error_2, ['cx']) | |
# Get basis gates from noise model | |
basis_gates = noise_model.basis_gates | |
backend = Aer.get_backend('qasm_simulator') | |
# if your sprite is png and not bmp, run the following | |
# convert mario_sprite.png -depth 2 mario_sprite.bmp | |
# source: https://imagemagick.org/script/command-line-options.php#depth | |
im = Image.open('mario_sprite.bmp') | |
pixels = np.array(im) | |
im.close() | |
columns, rows, colors = pixels.shape | |
dtype = pixels.dtype | |
hashes = [] | |
palette = {} | |
indices = {} | |
# get the palette and hashed colors | |
for row in range(rows): | |
for column in range(columns): | |
color = pixels[column, row, :] | |
hashed = hash(tuple(color)) | |
hashes.append(hashed) | |
palette[hashed] = color | |
hashes = list(set(hashes)) | |
# assign a unique index to each color | |
for i, hashed in enumerate(hashes): | |
indices[hashed] = i | |
# get binary tuple from the integer | |
def binaryTupleFromInteger(i): | |
return tuple([int(j) for j in list(bin(i)[2:].zfill(2))]) | |
print('Test converting integer to a binary tuple') | |
print(binaryTupleFromInteger(0)) | |
print(binaryTupleFromInteger(1)) | |
print(binaryTupleFromInteger(2)) | |
print(binaryTupleFromInteger(3)) | |
# get integer from binary tuple | |
def integerFromBinaryTuple(a, b): | |
return a*2**1 + b*2**0 | |
print('Test converting binary tuple to integer') | |
print(integerFromBinaryTuple(0, 0)) | |
print(integerFromBinaryTuple(0, 1)) | |
print(integerFromBinaryTuple(1, 0)) | |
print(integerFromBinaryTuple(1, 1)) | |
# time to send the Mario | |
received_mario = np.zeros((columns, rows, colors), dtype=dtype) | |
for row in range(rows): | |
for column in range(columns): | |
color = pixels[column, row, :] | |
hashed = hash(tuple(color)) | |
index = indices[hashed] | |
b1, b2 = binaryTupleFromInteger(index) | |
# here quantum magic happens TODO | |
cb1, cb2 = simulateCommunicationChannel(b1, b2, backend, basis_gates, noise_model=noise_model) | |
# quantum magick is done | |
received_index = integerFromBinaryTuple(cb1, cb2) | |
received_hashed = hashes[received_index] | |
received_color = palette[received_hashed] | |
received_mario[column, row, :] = received_color | |
print('Is received Mario identical to Mario that has been sent?') | |
print((pixels == received_mario).all()) | |
# make image of the received Mario | |
received_im = Image.fromarray(received_mario) | |
received_im.save('received_mario_sprite.bmp') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment