moved some methods from the old lib
This commit is contained in:
parent
a0634208ed
commit
5aa2d30abd
@ -1,12 +1,23 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
# Raw matrixes to be used for initialization of qubits and gates
|
# Raw matrixes to be used for initialization of qubits and gates
|
||||||
|
|
||||||
|
# |0> and |1>
|
||||||
__0 = [[1],
|
__0 = [[1],
|
||||||
[0]]
|
[0]]
|
||||||
|
|
||||||
__1 = [[0],
|
__1 = [[0],
|
||||||
[1]]
|
[1]]
|
||||||
|
|
||||||
|
# |+> and |->
|
||||||
|
__p = [[1 / np.sqrt(2)],
|
||||||
|
[1 / np.sqrt(2)]]
|
||||||
|
__m = [[1 / np.sqrt(2)],
|
||||||
|
[-1 / np.sqrt(2)]]
|
||||||
|
|
||||||
|
# Gate/Operator raws
|
||||||
_I = [
|
_I = [
|
||||||
[1, 0],
|
[1, 0],
|
||||||
[0, 1],
|
[0, 1],
|
||||||
@ -42,6 +53,7 @@ _CNOT = [
|
|||||||
|
|
||||||
class State(object):
|
class State(object):
|
||||||
"""Represents a quantum state"""
|
"""Represents a quantum state"""
|
||||||
|
|
||||||
def __init__(self, matrix_state):
|
def __init__(self, matrix_state):
|
||||||
"""
|
"""
|
||||||
Can be initialized with a matrix, e.g. for |0> this is [[0],[1]]
|
Can be initialized with a matrix, e.g. for |0> this is [[0],[1]]
|
||||||
@ -51,8 +63,10 @@ class State(object):
|
|||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
"""
|
"""
|
||||||
Kind of hacky way to store a substate of an item for use in Gate operations
|
Kind of hacky way to store a substate of an item for use in Gate
|
||||||
so that one can use state[0] and the encompassing operator can access this.
|
operations
|
||||||
|
so that one can use state[0] and the encompassing operator can access
|
||||||
|
this.
|
||||||
:param item:
|
:param item:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
@ -67,6 +81,31 @@ class State(object):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return str(self.matrix_state)
|
return str(self.matrix_state)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return np.array_equal(self.matrix_state, other.matrix_state)
|
||||||
|
|
||||||
|
def density_matrix(self):
|
||||||
|
return self.matrix_state.dot(np.transpose(self.matrix_state))
|
||||||
|
|
||||||
|
def measure_probability(self):
|
||||||
|
"""
|
||||||
|
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]) ** 2 for qbit in self.matrix_state]
|
||||||
|
|
||||||
|
def measure(self):
|
||||||
|
"""
|
||||||
|
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"""
|
||||||
|
weights = self.measure_probability()
|
||||||
|
format_str = "{:0" + str(int(np.ceil(np.log2(len(weights))))) + "b}"
|
||||||
|
choices = [format_str.format(i) for i in range(len(weights))]
|
||||||
|
return random.choices(choices, weights)[0]
|
||||||
|
|
||||||
|
|
||||||
def kron(_list):
|
def kron(_list):
|
||||||
"""Calculates a Kronicker product of a list of matrices
|
"""Calculates a Kronicker product of a list of matrices
|
||||||
@ -83,9 +122,11 @@ class Gate(State):
|
|||||||
def on(self, other_state):
|
def on(self, other_state):
|
||||||
"""
|
"""
|
||||||
Applies a gate operation on a state.
|
Applies a gate operation on a state.
|
||||||
If applying to a substate, use the index of the substate, e.g. `H.on(bell[0])` will apply the Hadamard gate
|
If applying to a substate, use the index of the substate, e.g. `H.on(
|
||||||
|
bell[0])` will apply the Hadamard gate
|
||||||
on the 0th qubit of the `bell` state.
|
on the 0th qubit of the `bell` state.
|
||||||
:param other_state: another state (e.g. `H.on(q1)` or a list of states (e.g. for `CNOT.on([q1, q2])`)
|
:param other_state: another state (e.g. `H.on(q1)` or a list of
|
||||||
|
states (e.g. for `CNOT.on([q1, q2])`)
|
||||||
:return: the state after the application of the Gate
|
:return: the state after the application of the Gate
|
||||||
"""
|
"""
|
||||||
this_state_m = self.matrix_state
|
this_state_m = self.matrix_state
|
||||||
@ -97,7 +138,8 @@ class Gate(State):
|
|||||||
# Use the Kronicker product of Identity with the state.item where
|
# Use the Kronicker product of Identity with the state.item where
|
||||||
# state.item is the substate
|
# state.item is the substate
|
||||||
larger_side = max(len(self), len(other_state))
|
larger_side = max(len(self), len(other_state))
|
||||||
_list = [this_state_m if i == other_state.item else _I for i in range(larger_side)]
|
_list = [this_state_m if i == other_state.item else _I
|
||||||
|
for i in range(larger_side)]
|
||||||
this_state_m = kron(_list)
|
this_state_m = kron(_list)
|
||||||
return State(this_state_m.dot(other_state_m))
|
return State(this_state_m.dot(other_state_m))
|
||||||
|
|
||||||
@ -113,3 +155,38 @@ Z = Gate(_Z)
|
|||||||
H = Gate(_H)
|
H = Gate(_H)
|
||||||
|
|
||||||
CNOT = Gate(_CNOT)
|
CNOT = Gate(_CNOT)
|
||||||
|
|
||||||
|
|
||||||
|
def run_qbit_tests():
|
||||||
|
# asserts are sets of tests to check if mathz workz
|
||||||
|
# initialize qubits
|
||||||
|
_0 = Qubit(__0)
|
||||||
|
_1 = Qubit(__1)
|
||||||
|
_p = Qubit(__p)
|
||||||
|
_m = Qubit(__m)
|
||||||
|
|
||||||
|
# Identity: verify that I|0> == |0> and I|1> == |0>
|
||||||
|
assert I.on(_0) == _0
|
||||||
|
assert I.on(_1) == _1
|
||||||
|
|
||||||
|
# Pauli X: verify that X|0> == |1> and X|1> == |0>
|
||||||
|
assert X.on(_0) == _1
|
||||||
|
assert X.on(_1) == _0
|
||||||
|
|
||||||
|
# measure probabilities in sigma_x of |0> and |1>
|
||||||
|
# using allclose since dealing with floats
|
||||||
|
assert np.allclose(_0.measure_probability(), (1.0, 0.0))
|
||||||
|
assert np.allclose(_1.measure_probability(), (0.0, 1.0))
|
||||||
|
|
||||||
|
# applying Hadamard puts the qbit in orthogonal +/- basis
|
||||||
|
assert np.array_equal(H.on(_0), _p)
|
||||||
|
assert np.array_equal(H.on(_1), _m)
|
||||||
|
|
||||||
|
# measure probabilities in sigma_x of |+> and |->
|
||||||
|
# using allclose since dealing with floats
|
||||||
|
assert np.allclose(_p.measure_probability(), (0.5, 0.5))
|
||||||
|
assert np.allclose(_m.measure_probability(), (0.5, 0.5))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run_qbit_tests()
|
||||||
|
Loading…
Reference in New Issue
Block a user