From aa06605f6cccc3ee3eb4977ee5e7f1b6526f83ce Mon Sep 17 00:00:00 2001 From: Daniel Tsvetkov Date: Thu, 20 Feb 2020 11:01:05 +0100 Subject: [PATCH] partial measurement half-implemented --- lib_q_computer_math.py | 58 +++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/lib_q_computer_math.py b/lib_q_computer_math.py index 3f4729c..2853673 100644 --- a/lib_q_computer_math.py +++ b/lib_q_computer_math.py @@ -140,6 +140,7 @@ class State(Vector): """State vector representing quantum state""" super().__init__(m, *args, **kwargs) self.name = name + self.measurement_result = None if not self._is_normalized(): raise TypeError("Not a normalized state vector") @@ -246,9 +247,10 @@ class State(Vector): 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: 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? What about if measured twice but in different bases? E.g. measure1 -> computation -> A @@ -257,10 +259,13 @@ class State(Vector): measure4 -> +/- basis -> should it return B again or random weighted? :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))] format_str = self.get_fmt_of_element() 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): """ @@ -270,15 +275,24 @@ class State(Vector): m = mo.on(self) / np.sqrt(mo.get_prob(self)) return State(m) - def measure_n(self, n=1): - """measures n times - TODO: Does this make sense? When a state is measured once, it should "collapse" + def measure_partial(self, qubit_n): + """Partial measurement of state + Measures the n-th qubit with probability sum(a_n), + adjusting the probability of the rest of the state """ - measurements = defaultdict(int) - for _ in range(n): - k = self.measure() - measurements[k] += 1 - return measurements + max_qubits = int(np.log2(len(self))) + if not (0 < qubit_n <= max_qubits): + raise Exception("Partial measurement of qubit_n must be between 1 and {}".format(max_qubits)) + format_str = self.get_fmt_of_element() + 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): format_str = self.get_fmt_of_element() + " | {}" @@ -312,6 +326,11 @@ class State(Vector): return [x, y, z] +def test_measure_partial(): + state = s("|000>") + state.measure_partial(2) + + def normalize_state(state_vector: ListOrNdarray): """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)) @@ -923,16 +942,6 @@ def test_to_from_angles(): 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): import os import psutil @@ -1154,6 +1163,7 @@ def test_quantum_processor(): def test_light(): # 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') diag_filter = MeasurementOperator.create_from_prob(Matrix(_p.m), name='d') 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]]) # add three filters as operators + # qc.add_row([hor_filter, ver_filter]) qc.add_row([hor_filter, diag_filter, ver_filter]) qc.print() qp = QuantumProcessor(qc) @@ -1173,6 +1184,7 @@ def test_light(): if __name__ == "__main__": - test() - test_quantum_processor() + # test() + # test_quantum_processor() # test_light() + test_measure_partial()