diff --git a/06_krisis.py b/06_krisis.py index 75dc7e6..7ffa6a9 100644 --- a/06_krisis.py +++ b/06_krisis.py @@ -29,7 +29,7 @@ def print_all_samples(name, all_samples): print("==============================================") -def math_sim(q2func=State.from_angles, iterations=1000, sample_count=1): +def math_sim(q2func=State.from_bloch_angles, iterations=1000, sample_count=1): all_samples = defaultdict(int) for i in range(iterations): # print("Running iteration {}".format(i)) @@ -45,7 +45,7 @@ def math_sim(q2func=State.from_angles, iterations=1000, sample_count=1): # print("theta: {:.2f} ({:.2f} deg) | phi: {:.2f} ({:.2f} deg)".format( # theta, np.rad2deg(theta), # phi, np.rad2deg(phi))) - q1 = State.from_angles(theta, phi) + q1 = State.from_bloch_angles(theta, phi) q2 = q2func(theta, phi) qc = QuantumCircuit(2, [[q1, q2], ]) @@ -131,7 +131,7 @@ def cirq_sim(q1func, q2func, iterations=1000, sample_count=1): def math_sim_0(*args, **kwargs): - math_sim(q2func=State.from_angles, *args, **kwargs) + math_sim(q2func=State.from_bloch_angles, *args, **kwargs) def math_sim_1(*args, **kwargs): diff --git a/lib_q_computer_math.py b/lib_q_computer_math.py index 80720ef..70590a2 100644 --- a/lib_q_computer_math.py +++ b/lib_q_computer_math.py @@ -155,16 +155,18 @@ class State(Vector): return theta, phi @classmethod - def from_angles(cls, theta, phi): + def from_bloch_angles(cls, theta, phi): + """Creates a state from angles in Bloch sphere""" theta, phi = cls._normalize_angles(theta, phi) m0 = np.cos(theta / 2) m1 = np.sin(theta / 2) * np.power(np.e, (1j * phi)) m = m0 * _0 + m1 * _1 return cls(m.m) - def to_angles(self): + def to_bloch_angles(self): + """Returns the angles of this state on the Bloch sphere""" if not self.m.shape == (2, 1): - raise Exception("State needs to be 2x1 matrix") + raise Exception("State needs to describe only 1 qubit on the bloch sphere (2x1 matrix)") m0, m1 = self.m[0][0], self.m[1][0] # theta is between 0 and pi @@ -303,23 +305,33 @@ class State(Vector): return theta, phi def get_bloch_coordinates(self): - theta, phi = self.to_angles() + theta, phi = self.to_bloch_angles() x = np.sin(theta) * np.cos(phi) y = np.sin(theta) * np.sin(phi) z = np.cos(theta) return [x, y, z] -def s(q): +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)) + if norm_coef == 0: + raise TypeError("zero-sum vector") + return state_vector / norm_coef + + +def s(q, name=None): """Helper method for creating state easily""" if type(q) == str: # e.g. |000> if q[0] == '|' and q[-1] == '>': - return State.from_string(q) + state = State.from_string(q) + state.name = name + return state elif type(q) == list: # e.g. s([1,0]) => |0> - return State(np.reshape(q, (len(q), 1))) - return State(q) + return State(np.reshape(q, (len(q), 1)), name=name) + return State(q, name=name) def humanize_num(fl, tolerance=1e-3): @@ -714,13 +726,13 @@ def test_unitary_hermitian(): assert_raises(TypeError, "Not a Unitary matrix", UnitaryMatrix, not_u_not_h) -class MeasurementOpeartor(HermitianOperator): +class MeasurementOperator(HermitianOperator): """Measurement operators are Hermitians: <ψ|M†_m M_m|ψ>""" @classmethod - def create_from_prob(cls, matrix: Matrix): + def create_from_prob(cls, matrix: Matrix, *args, **kwargs): """returns |M†_m> @@ -732,8 +744,8 @@ class MeasurementOpeartor(HermitianOperator): def test_measurement_ops(): - m0 = MeasurementOpeartor.create_from_prob(Matrix([1, 0])) - m1 = MeasurementOpeartor.create_from_prob(Matrix([0, 1])) + m0 = MeasurementOperator.create_from_prob(Matrix([1, 0])) + m1 = MeasurementOperator.create_from_prob(Matrix([0, 1])) assert m0 == Matrix([[1, 0], [0, 0]]) assert m1 == Matrix([[0, 0], @@ -893,21 +905,21 @@ def test(): def test_to_from_angles(): for q in [_0, _1, _p, _m]: - angles = q.to_angles() - s = State.from_angles(*angles) + angles = q.to_bloch_angles() + s = State.from_bloch_angles(*angles) assert q == s - assert State.from_angles(0, 0) == _0 - assert State.from_angles(np.pi, 0) == _1 - assert State.from_angles(np.pi / 2, 0) == _p - assert State.from_angles(np.pi / 2, np.pi) == _m + assert State.from_bloch_angles(0, 0) == _0 + assert State.from_bloch_angles(np.pi, 0) == _1 + assert State.from_bloch_angles(np.pi / 2, 0) == _p + assert State.from_bloch_angles(np.pi / 2, np.pi) == _m for theta, phi, qbit in [ (0, 0, _0), (np.pi, 0, _1), (np.pi / 2, 0, _p), (np.pi / 2, np.pi, _m), ]: - s = State.from_angles(theta, phi) + s = State.from_bloch_angles(theta, phi) assert s == qbit @@ -1140,6 +1152,29 @@ def test_quantum_processor(): qp.print_sample(qp.get_sample(100)) +def test_light(): + global UNIVERSE_STATES + UNIVERSE_STATES = [] + hor = s('|0>', name='→') + ver = s('|1>', name='↑') + diag1 = hor + ver + diag1.name = '🡕' + hor_filter = MeasurementOperator.create_from_prob(Matrix(hor.m), name='h') + diag_filter = MeasurementOperator.create_from_prob(Matrix(diag1.m), name='d') + ver_filter = MeasurementOperator.create_from_prob(Matrix(ver.m), name='v') + + for i in range(10): + random_pol = [[np.random.uniform(0, 1)], [np.random.uniform(0, 1)]] + random_light = State(normalize_state(random_pol)) + qc = QuantumCircuit(1, initial_steps=[[random_light]]) + qc.add_row([hor_filter, diag_filter, ver_filter]) + qc.print() + qp = QuantumProcessor(qc) + # TODO: Dealing with non-normalized state vectors + qp.print_sample(qp.get_sample(100)) + + if __name__ == "__main__": test() test_quantum_processor() + # test_light()