quantum framework + dense coding
This commit is contained in:
parent
b80fa8e3e0
commit
32ba69a3b2
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
venv
|
||||
.idea
|
||||
.idea
|
||||
__pycache__
|
66
04_qkd_2.py
66
04_qkd_2.py
@ -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
54
05_dense_coding.py
Normal 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()
|
@ -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
71
lib_q_computer_old.py
Normal 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))
|
Loading…
Reference in New Issue
Block a user