Last active
June 9, 2020 07:16
-
-
Save marekyggdrasil/2f86f404f1d3c92fbcc0d83cfbb2663d to your computer and use it in GitHub Desktop.
A code repository for tutorial https://mareknarozniak.com/2020/06/09/simulating-superdense-coding/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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