quantum framework + dense coding

This commit is contained in:
Daniel Tsvetkov 2019-12-04 17:17:36 +01:00
parent b80fa8e3e0
commit 32ba69a3b2
5 changed files with 214 additions and 93 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
venv
.idea
.idea
__pycache__

View File

@ -3,6 +3,8 @@ import random
import numpy as np
# should print some debugging statements?
from lib_q_computer_old import _0, I, X, H, measure, run_qbit_tests
DEBUG = True
# How long should be the stream - in general about half of the stream
@ -13,70 +15,6 @@ STREAM_LENGTH = 20
# The message that Alice wants to send to Bob
_ALICE_MESSAGE = 'd'
# |0> and |1>
_0 = np.array([[1],
[0]])
_1 = np.array([[0],
[1]])
# |+> and |->
_p = np.array([[1 / np.sqrt(2)],
[1 / np.sqrt(2)]])
_m = np.array([[1 / np.sqrt(2)],
[-1 / np.sqrt(2)]])
# Gates - Identity, Pauli X and Hadamard
I = np.array([[1, 0],
[0, 1]])
X = np.array([[0, 1],
[1, 0]])
H = np.array([[1 / np.sqrt(2), 1 / np.sqrt(2)],
[1 / np.sqrt(2), -1 / np.sqrt(2)]])
def measure_probability(qbit):
"""
In a qbit [a, b] normalized: |a|^2 + |b|^2 = 1
Probability of 0 is |a|^2 and 1 with prob |b|^2
:returns: tuple of probabilities to measure 0 or 1"""
return np.abs(qbit[0][0]) ** 2, np.abs(qbit[1][0]) ** 2
def measure(qbit):
"""
This gets a random choice of either 0 and 1 with weights
based on the probabilities of the qbit
:returns: classical bit based on qbit probabilities"""
return random.choices([0, 1], measure_probability(qbit))[0]
def run_qbit_tests():
# asserts are sets of tests to check if mathz workz
# Identity: verify that I|0> == |0> and I|1> == |0>
assert np.array_equal(I.dot(_0), _0)
assert np.array_equal(I.dot(_1), _1)
# Pauli X: verify that X|0> == |1> and X|1> == |0>
assert np.array_equal(X.dot(_0), _1)
assert np.array_equal(X.dot(_1), _0)
# measure probabilities in sigma_x of |0> and |1>
# using allclose since dealing with floats
assert np.allclose(measure_probability(_0), (1.0, 0.0))
assert np.allclose(measure_probability(_1), (0.0, 1.0))
# applying Hadamard puts the qbit in orthogonal +/- basis
assert np.array_equal(H.dot(_0), _p)
assert np.array_equal(H.dot(_1), _m)
# measure probabilities in sigma_x of |+> and |->
# using allclose since dealing with floats
assert np.allclose(measure_probability(_p), (0.5, 0.5))
assert np.allclose(measure_probability(_m), (0.5, 0.5))
def bases_to_classical(qbits):
"""

54
05_dense_coding.py Normal file
View File

@ -0,0 +1,54 @@
from lib_q_computer import Qubit, __0, H, CNOT, I, X, Z
def quantum_dense_coding():
q1 = Qubit(__0)
q2 = Qubit(__0)
print("Hadamard on q1")
q1 = H.on(q1)
print(q1)
print()
print("Bell state")
bell = CNOT.on([q1, q2])
print(bell)
print()
print("Want to send 00")
_00 = I.on(bell[0])
print(_00)
print()
print("Want to send 01")
_01 = X.on(bell[0])
print(_01)
print()
print("Want to send 10")
_10 = Z.on(bell[0])
print(_10)
print()
print("Want to send 11")
_11 = X.on(Z.on(bell[0])[0])
print(_11)
print()
print("Bob measures...")
print("00")
m00 = H.on(CNOT.on(_00)[0])
print(m00)
print()
print("01")
m01 = H.on(CNOT.on(_01)[0])
print(m01)
print()
print("10")
m10 = H.on(CNOT.on(_10)[0])
print(m10)
print()
print("11")
m11 = H.on(CNOT.on(_11)[0])
print(m11)
if __name__ == "__main__":
quantum_dense_coding()

View File

@ -1,44 +1,101 @@
import numpy as np
__0 = [[1],
[0]]
__1 = [[0],
[1]]
_I = [
[1, 0],
[0, 1],
]
_X = [
[0, 1],
[1, 0],
]
_Y = [
[0, complex(0, -1)],
[complex(0, 1), 0],
]
_Z = [
[1, 0],
[0, -1],
]
_H = [
[1 / np.sqrt(2), 1 / np.sqrt(2)],
[1 / np.sqrt(2), -1 / np.sqrt(2)]
]
_CNOT = [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
]
class State(object):
def __init__(self, matrix_state):
self._matrix_state = matrix_state
self.matrix_state = np.array(matrix_state)
def __getitem__(self, item):
if item >= len(self):
raise IndexError
self.item = item
return self
def __len__(self):
return int(np.log2(self.matrix_state.shape[0]))
def __repr__(self):
return str(self._matrix_state)
return str(self.matrix_state)
def kron(_list):
"""Calculates a Kronicker product of a list of matrices
This is essentially a np.kron(*args) since np.kron takes (a,b)"""
if type(_list) != list or len(_list) <= 1:
return np.array([])
rv = np.array(_list[0])
for item in _list[1:]:
rv = np.kron(rv, item)
return rv
class Gate(State):
def on(self, state, q2=None):
this = self._matrix_state
a = state._matrix_state
if q2:
a = np.kron(a, q2._matrix_state)
return State(this.dot(a))
def on(self, state):
"""
Applies
:param state: another state (e.g. H(q1) or a list of states (e.g. for CNOT([q1, q2]))
:return:
"""
this_state = self.matrix_state
if type(state) == list:
other_state = kron([e.matrix_state for e in state])
else:
other_state = state.matrix_state
if this_state.shape[1] != other_state.shape[0]:
# The two arrays are different sizes
# Use the Kronicker product of Identity with the state.item
larger_side = max(this_state.shape[1], this_state.shape[0])
_list = [this_state if i == state.item else _I for i in range(larger_side)]
this_state = kron(_list)
return State(this_state.dot(other_state))
class Qubit(State): ...
_0 = np.array([[1],
[0]])
# List of gates
I = Gate(_I)
X = Gate(_X)
Y = Gate(_Y)
Z = Gate(_Z)
H = Gate(_H)
H = Gate(np.array([
[1 / np.sqrt(2), 1 / np.sqrt(2)],
[1 / np.sqrt(2), -1 / np.sqrt(2)]
]))
CNOT = Gate(np.array([
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
]))
if __name__ == "__main__":
# E.g. Bell state
q1 = Qubit(_0)
q2 = Qubit(_0)
bell = CNOT.on(H.on(q1), q2)
print(bell)
CNOT = Gate(_CNOT)

71
lib_q_computer_old.py Normal file
View File

@ -0,0 +1,71 @@
"""
TODO: DEPRECATE THIS ONE IN FAVOR OF lib_q_computer.py
"""
import random
import numpy as np
# |0> and |1>
_0 = np.array([[1],
[0]])
_1 = np.array([[0],
[1]])
# |+> and |->
_p = np.array([[1 / np.sqrt(2)],
[1 / np.sqrt(2)]])
_m = np.array([[1 / np.sqrt(2)],
[-1 / np.sqrt(2)]])
# Gates - Identity, Pauli X and Hadamard
I = np.array([[1, 0],
[0, 1]])
X = np.array([[0, 1],
[1, 0]])
H = np.array([[1 / np.sqrt(2), 1 / np.sqrt(2)],
[1 / np.sqrt(2), -1 / np.sqrt(2)]])
def measure_probability(qbit):
"""
In a qbit [a, b] normalized: |a|^2 + |b|^2 = 1
Probability of 0 is |a|^2 and 1 with prob |b|^2
:returns: tuple of probabilities to measure 0 or 1"""
return np.abs(qbit[0][0]) ** 2, np.abs(qbit[1][0]) ** 2
def measure(qbit):
"""
This gets a random choice of either 0 and 1 with weights
based on the probabilities of the qbit
:returns: classical bit based on qbit probabilities"""
return random.choices([0, 1], measure_probability(qbit))[0]
def run_qbit_tests():
# asserts are sets of tests to check if mathz workz
# Identity: verify that I|0> == |0> and I|1> == |0>
assert np.array_equal(I.dot(_0), _0)
assert np.array_equal(I.dot(_1), _1)
# Pauli X: verify that X|0> == |1> and X|1> == |0>
assert np.array_equal(X.dot(_0), _1)
assert np.array_equal(X.dot(_1), _0)
# measure probabilities in sigma_x of |0> and |1>
# using allclose since dealing with floats
assert np.allclose(measure_probability(_0), (1.0, 0.0))
assert np.allclose(measure_probability(_1), (0.0, 1.0))
# applying Hadamard puts the qbit in orthogonal +/- basis
assert np.array_equal(H.dot(_0), _p)
assert np.array_equal(H.dot(_1), _m)
# measure probabilities in sigma_x of |+> and |->
# using allclose since dealing with floats
assert np.allclose(measure_probability(_p), (0.5, 0.5))
assert np.allclose(measure_probability(_m), (0.5, 0.5))