partial measurement half-implemented

This commit is contained in:
Daniel Tsvetkov 2020-02-20 11:01:05 +01:00
parent 14bee6764a
commit aa06605f6c

View File

@ -140,6 +140,7 @@ class State(Vector):
"""State vector representing quantum state""" """State vector representing quantum state"""
super().__init__(m, *args, **kwargs) super().__init__(m, *args, **kwargs)
self.name = name self.name = name
self.measurement_result = None
if not self._is_normalized(): if not self._is_normalized():
raise TypeError("Not a normalized state vector") raise TypeError("Not a normalized state vector")
@ -246,9 +247,10 @@ class State(Vector):
def measure(self): def measure(self):
""" """
Measures in the computational basis Measures in the computational basis.
Irreversable operation. Measuring again will result in the same result
TODO: Generalize the method so it takes a basis TODO: Generalize the method so it takes a basis
TODO: Should we memoize the result? Should we memoize per basis? TODO: Should we memoize per basis?
If it's measured twice, should it return the same state? If it's measured twice, should it return the same state?
What about if measured twice but in different bases? What about if measured twice but in different bases?
E.g. measure1 -> computation -> A E.g. measure1 -> computation -> A
@ -257,10 +259,13 @@ class State(Vector):
measure4 -> +/- basis -> should it return B again or random weighted? measure4 -> +/- basis -> should it return B again or random weighted?
:return: binary representation of the measured qubit (e.g. "011") :return: binary representation of the measured qubit (e.g. "011")
""" """
if self.measurement_result:
return self.measurement_result
weights = [self.get_prob(j) for j in range(len(self))] weights = [self.get_prob(j) for j in range(len(self))]
format_str = self.get_fmt_of_element() format_str = self.get_fmt_of_element()
choices = [format_str.format(i) for i in range(len(weights))] choices = [format_str.format(i) for i in range(len(weights))]
return random.choices(choices, weights)[0] self.measurement_result = random.choices(choices, weights)[0]
return self.measurement_result
def measure_with_op(self, mo): def measure_with_op(self, mo):
""" """
@ -270,15 +275,24 @@ class State(Vector):
m = mo.on(self) / np.sqrt(mo.get_prob(self)) m = mo.on(self) / np.sqrt(mo.get_prob(self))
return State(m) return State(m)
def measure_n(self, n=1): def measure_partial(self, qubit_n):
"""measures n times """Partial measurement of state
TODO: Does this make sense? When a state is measured once, it should "collapse" Measures the n-th qubit with probability sum(a_n),
adjusting the probability of the rest of the state
""" """
measurements = defaultdict(int) max_qubits = int(np.log2(len(self)))
for _ in range(n): if not (0 < qubit_n <= max_qubits):
k = self.measure() raise Exception("Partial measurement of qubit_n must be between 1 and {}".format(max_qubits))
measurements[k] += 1 format_str = self.get_fmt_of_element()
return measurements bin_repr = [format_str.format(i) for i in range(len(self))]
partial_measurement_of_qbit = [int(b[qubit_n - 1]) for b in bin_repr]
indexes_for_p_0 = [i for i, index in enumerate(partial_measurement_of_qbit) if index==0]
weights_0 = [self.get_prob(j) for j in indexes_for_p_0]
choices_0 = [format_str.format(i) for i in indexes_for_p_0]
measurement_result = random.choices(choices_0, weights_0)[0]
# TODO: collapse the state and change the probabilities of the rest
# https://www.youtube.com/watch?v=MG_9JWsrKtM&list=PL1826E60FD05B44E4&index=16
return measurement_result
def pretty_print(self): def pretty_print(self):
format_str = self.get_fmt_of_element() + " | {}" format_str = self.get_fmt_of_element() + " | {}"
@ -312,6 +326,11 @@ class State(Vector):
return [x, y, z] return [x, y, z]
def test_measure_partial():
state = s("|000>")
state.measure_partial(2)
def normalize_state(state_vector: ListOrNdarray): def normalize_state(state_vector: ListOrNdarray):
"""Normalize a state by dividing by the square root of sum of the squares of states""" """Normalize a state by dividing by the square root of sum of the squares of states"""
norm_coef = np.sqrt(np.sum(np.array(state_vector) ** 2)) norm_coef = np.sqrt(np.sum(np.array(state_vector) ** 2))
@ -923,16 +942,6 @@ def test_to_from_angles():
assert s == qbit assert s == qbit
def test_measure_n():
qq = State([
[0.5],
[0.5],
[0.5],
[0.5],
])
qq.measure_n(100)
def naive_load_test(N): def naive_load_test(N):
import os import os
import psutil import psutil
@ -1154,6 +1163,7 @@ def test_quantum_processor():
def test_light(): def test_light():
# TODO: Are these measurement operators the correct way to represent hor/ver/diag filter? # TODO: Are these measurement operators the correct way to represent hor/ver/diag filter?
# No, becuase they are not unitaries
hor_filter = MeasurementOperator.create_from_prob(Matrix(_0.m), name='h') hor_filter = MeasurementOperator.create_from_prob(Matrix(_0.m), name='h')
diag_filter = MeasurementOperator.create_from_prob(Matrix(_p.m), name='d') diag_filter = MeasurementOperator.create_from_prob(Matrix(_p.m), name='d')
ver_filter = MeasurementOperator.create_from_prob(Matrix(_1.m), name='v') ver_filter = MeasurementOperator.create_from_prob(Matrix(_1.m), name='v')
@ -1164,6 +1174,7 @@ def test_light():
qc = QuantumCircuit(1, initial_steps=[[random_light]]) qc = QuantumCircuit(1, initial_steps=[[random_light]])
# add three filters as operators # add three filters as operators
# qc.add_row([hor_filter, ver_filter])
qc.add_row([hor_filter, diag_filter, ver_filter]) qc.add_row([hor_filter, diag_filter, ver_filter])
qc.print() qc.print()
qp = QuantumProcessor(qc) qp = QuantumProcessor(qc)
@ -1173,6 +1184,7 @@ def test_light():
if __name__ == "__main__": if __name__ == "__main__":
test() # test()
test_quantum_processor() # test_quantum_processor()
# test_light() # test_light()
test_measure_partial()