From 6ae883d81834deea5a1f1d9c604eb3167003d26b Mon Sep 17 00:00:00 2001 From: Daniel Tsvetkov Date: Sun, 29 Mar 2020 18:15:40 +0200 Subject: [PATCH] normalize state --- 10_krisi_3qubits_game.py | 5 +-- grover.py | 10 +++--- lib.py | 66 ++++++++++++++++++++++------------------ 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/10_krisi_3qubits_game.py b/10_krisi_3qubits_game.py index 8e57fad..89bc73b 100644 --- a/10_krisi_3qubits_game.py +++ b/10_krisi_3qubits_game.py @@ -115,7 +115,8 @@ def test_krisi_measurement_3(): # P_minus = b_psi_m.x(b_psi_m) P_s = b_psi_p.x(b_psi_p) + b_phi_m.x(b_phi_m) + b_phi_p.x(b_phi_p) - post_state = State(MeasurementOperator(P_s.m).on(q1q2_st)) + meas = MeasurementOperator(P_s.m).on(q1q2_st) + post_state = State(State.normalize(meas)) if case == CASE_ID_ID: assert post_state == q1q2_st @@ -123,7 +124,7 @@ def test_krisi_measurement_3(): assert post_state != q1q2_st q3 = State.from_bloch_angles(theta2, phi2) - meas = State(post_state * q3).measure(basis=basis) + meas = State(State.normalize(post_state * q3)).measure(basis=basis) # # TODO: This part measures the first two qubits in Bell basis, then: # # 1. constructs a new pure state diff --git a/grover.py b/grover.py index b4b4f05..8c270e4 100644 --- a/grover.py +++ b/grover.py @@ -34,7 +34,7 @@ def classical_func_search_single_rv(func, input_range): return rv -def _3sat_old(params): +def _3sat(params): # 3-SAT from here: https://qiskit.org/textbook/ch-applications/satisfiability-grover.html x1, x2, x3 = params return (not x1 or not x2 or not x3) and \ @@ -43,7 +43,8 @@ def _3sat_old(params): (x1 or not x2 or not x3) and \ (not x1 or x2 or x3) -def _3sat(params): + +def _3sat_2(params): # 3-SAT from here: https://cstheory.stackexchange.com/questions/38538/oracle-construction-for-grovers-algorithm x1, x2, x3, x4 = params return (not x1 or not x3 or not x4) and \ @@ -52,9 +53,10 @@ def _3sat(params): (x1 or x3 or x4) and \ (not x1 or x2 or not x3) + def classical_3sat(func): - # Generate all possible true/false tupples for the 3-sat problem - input_range = list(itertools.product([True, False], repeat=4)) + # Generate all possible true/false tuples for the 3-sat problem + input_range = list(itertools.product([True, False], repeat=3)) random.shuffle(input_range) return classical_func_search_multi_rv(func, input_range) diff --git a/lib.py b/lib.py index afbc93c..6f9de2c 100644 --- a/lib.py +++ b/lib.py @@ -130,21 +130,32 @@ class Matrix(object): return str(self.m) +MatrixOrList = Union[Matrix, ListOrNdarray] + + class HorizontalVector(Matrix): """Horizontal vector is basically a list""" - def __init__(self, m: ListOrNdarray = None, *args, **kwargs): + def __init__(self, m: MatrixOrList = None, *args, **kwargs): super().__init__(m, *args, **kwargs) - if not self._is_vector(): - raise TypeError("Not a vector") + if type(m) in [Matrix]: + super().__init__(m.m, *args, **kwargs) + else: + super().__init__(m, *args, **kwargs) + if not self._is_horizontal_vector(): + raise TypeError("Not a horizontal vector") - def _is_vector(self): + def _is_horizontal_vector(self): return len(self.m.shape) == 1 class Vector(Matrix): - def __init__(self, m: ListOrNdarray = None, *args, **kwargs): + def __init__(self, m: MatrixOrList = None, *args, **kwargs): super().__init__(m, *args, **kwargs) + if type(m) in [Matrix]: + super().__init__(m.m, *args, **kwargs) + else: + super().__init__(m, *args, **kwargs) if not self._is_vector(): raise TypeError("Not a vector") @@ -152,13 +163,14 @@ class Vector(Matrix): return self.m.shape[1] == 1 -VectorOrList = Union[Vector, Matrix, ListOrNdarray] +VectorOrList = Union[Vector, MatrixOrList] class State(Vector): - def __init__(self, m: VectorOrList = None, name: str = '', *args, **kwargs): + def __init__(self, m: VectorOrList = None, name: str = '', + allow_unnormalized=False, *args, **kwargs): """State vector representing quantum state""" - if type(m) in [Vector, Matrix]: + if type(m) in [Vector, Matrix, State]: super().__init__(m.m, *args, **kwargs) else: super().__init__(m, *args, **kwargs) @@ -166,8 +178,18 @@ class State(Vector): self.measurement_result = None self.last_basis = None # TODO: SHOULD WE NORMALIZE? - # if not self._is_normalized(): - # raise TypeError("Not a normalized state vector") + if not allow_unnormalized and not self._is_normalized(): + raise TypeError("Not a normalized state vector") + + @staticmethod + def normalize(vector: Vector): + """Normalize a state by dividing by the square root of sum of the + squares of states""" + norm_coef = np.sqrt(np.sum(np.abs(vector.m ** 2))) + if norm_coef == 0: + raise TypeError("zero-sum vector") + new_m = vector.m / norm_coef + return State(new_m) def _is_normalized(self): return np.isclose(np.sum(np.abs(self.m ** 2)), 1.0) @@ -324,7 +346,7 @@ class State(Vector): weights += [prob] empty_choices, empty_weights = [], [] - if allow_empty == True: + if allow_empty: empty_prob = 1.0 - sum(weights) empty_weights = [empty_prob] empty_choices = [REPR_EMPTY_SET] @@ -332,7 +354,7 @@ class State(Vector): # TODO: This may be wrong # normalize the weights weights = list(np.array(weights) / sum(weights)) - # assert np.isclose(sum(weights), 1.0) + assert np.isclose(sum(weights), 1.0) format_str = self.get_fmt_of_element() choices = empty_choices + [format_str.format(i) for i in @@ -424,20 +446,6 @@ class Ket(State): State.__init__(self, *args, **kwargs) -def test_measure_partial(): - state = b_phi_p - state.measure_partial(1) - - -def normalize_state(vector: Vector): - """Normalize a state by dividing by the square root of sum of the squares - of states""" - norm_coef = np.sqrt(np.sum(np.array(vector.m) ** 2)) - if norm_coef == 0: - raise TypeError("zero-sum vector") - return State(vector.m / norm_coef) - - def s(q, name=None): """Helper method for creating state easily""" if type(q) == str: @@ -741,7 +749,7 @@ Define States and Operators """ # EMPTY STATE -_E = State([[0], +_E = Vector([[0], [0]], name=REPR_EMPTY_SET) @@ -1516,7 +1524,7 @@ def test_light(): def random_light(): random_pol = Vector( [[np.random.uniform(0, 1)], [np.random.uniform(0, 1)]]) - return normalize_state(random_pol) + return State.normalize(random_pol) def experiment(id, random_ls, filters): total_light = defaultdict(int) @@ -1528,7 +1536,7 @@ def test_light(): st = filters[0].on(r) for filter in filters: st = filter.on(st) - st = State(st) + st = State(st, allow_unnormalized=True) total_light[st.measure(allow_empty=True)] += 1 print("{}. {}:\n {}".format(id, human_state, dict(total_light)))