| @@ -26,26 +26,17 @@ def get_name(i): | |||||
| def find_clifford(needle, haystack): | def find_clifford(needle, haystack): | ||||
| """ Find the index of a given u within a list of unitaries, up to a global phase """ | """ Find the index of a given u within a list of unitaries, up to a global phase """ | ||||
| needle = normalize_global_phase(needle) | |||||
| needle = qi.normalize_global_phase(needle) | |||||
| for i, t in enumerate(haystack): | for i, t in enumerate(haystack): | ||||
| if np.allclose(t, needle): | if np.allclose(t, needle): | ||||
| return i | return i | ||||
| raise IndexError | raise IndexError | ||||
| def normalize_global_phase(m): | |||||
| """ Normalize the global phase of a matrix """ | |||||
| v = (x for x in m.flatten() if np.abs(x) > 0.001).next() | |||||
| phase = np.arctan2(v.imag, v.real) % np.pi | |||||
| rot = np.exp(-1j * phase) | |||||
| return rot * m if rot * v > 0 else -rot * m | |||||
| def find_cz(bond, c1, c2, commuters, state_table, ab_cz_table): | def find_cz(bond, c1, c2, commuters, state_table, ab_cz_table): | ||||
| """ Find the output of a CZ operation """ | """ Find the output of a CZ operation """ | ||||
| # Figure out the target state | # Figure out the target state | ||||
| target = qi.cz.dot(state_table[bond, c1, c2]) | target = qi.cz.dot(state_table[bond, c1, c2]) | ||||
| target = normalize_global_phase(target) | |||||
| target = qi.normalize_global_phase(target) | |||||
| # Choose the sets to search over | # Choose the sets to search over | ||||
| s1 = commuters if c1 in commuters else xrange(24) | s1 = commuters if c1 in commuters else xrange(24) | ||||
| @@ -64,7 +55,7 @@ def compose_u(decomposition): | |||||
| """ Get the unitary representation of a particular decomposition """ | """ Get the unitary representation of a particular decomposition """ | ||||
| matrices = ({"x": qi.sqx, "z": qi.msqz}[c] for c in decomposition) | matrices = ({"x": qi.sqx, "z": qi.msqz}[c] for c in decomposition) | ||||
| output = reduce(np.dot, matrices, np.eye(2, dtype=complex)) | output = reduce(np.dot, matrices, np.eye(2, dtype=complex)) | ||||
| return normalize_global_phase(output) | |||||
| return qi.normalize_global_phase(output) | |||||
| def get_unitaries(): | def get_unitaries(): | ||||
| @@ -96,7 +87,7 @@ def get_state_table(unitaries): | |||||
| for bond, i, j in tqdm(params, desc="Building state table"): | for bond, i, j in tqdm(params, desc="Building state table"): | ||||
| state = qi.bond if bond else qi.nobond | state = qi.bond if bond else qi.nobond | ||||
| kp = np.kron(unitaries[i], unitaries[j]) | kp = np.kron(unitaries[i], unitaries[j]) | ||||
| state_table[bond, i, j, :] = normalize_global_phase( | |||||
| state_table[bond, i, j, :] = qi.normalize_global_phase( | |||||
| np.dot(kp, state).T) | np.dot(kp, state).T) | ||||
| return state_table | return state_table | ||||
| @@ -3,6 +3,7 @@ | |||||
| """ | """ | ||||
| Exposes a few basic QI operators | Exposes a few basic QI operators | ||||
| And a circuit-model simulator | |||||
| """ | """ | ||||
| import numpy as np | import numpy as np | ||||
| @@ -20,7 +21,7 @@ id = np.array(np.eye(2, dtype=complex)) | |||||
| px = np.array([[0, 1], [1, 0]], dtype=complex) | px = np.array([[0, 1], [1, 0]], dtype=complex) | ||||
| py = np.array([[0, -1j], [1j, 0]], dtype=complex) | py = np.array([[0, -1j], [1j, 0]], dtype=complex) | ||||
| pz = np.array([[1, 0], [0, -1]], dtype=complex) | pz = np.array([[1, 0], [0, -1]], dtype=complex) | ||||
| ha = np.array([[1, 1], [1, -1]], dtype=complex) * ir2 | |||||
| ha = hadamard = np.array([[1, 1], [1, -1]], dtype=complex) * ir2 | |||||
| ph = np.array([[1, 0], [0, 1j]], dtype=complex) | ph = np.array([[1, 0], [0, 1j]], dtype=complex) | ||||
| t = np.array([[1, 0], [0, np.exp(1j*np.pi/4)]], dtype=complex) | t = np.array([[1, 0], [0, np.exp(1j*np.pi/4)]], dtype=complex) | ||||
| @@ -48,6 +49,15 @@ by_name = dict(zip(names, common_us)) | |||||
| paulis = px, py, pz | paulis = px, py, pz | ||||
| def normalize_global_phase(m): | |||||
| """ Normalize the global phase of a matrix """ | |||||
| v = (x for x in m.flatten() if np.abs(x) > 0.001).next() | |||||
| phase = np.arctan2(v.imag, v.real) % np.pi | |||||
| rot = np.exp(-1j * phase) | |||||
| return rot * m if rot * v > 0 else -rot * m | |||||
| class CircuitModel(object): | class CircuitModel(object): | ||||
| def __init__(self, nqubits): | def __init__(self, nqubits): | ||||
| self.nqubits = nqubits | self.nqubits = nqubits | ||||
| @@ -84,6 +94,13 @@ class CircuitModel(object): | |||||
| output[i ^ where] += v*u[not q, q] | output[i ^ where] += v*u[not q, q] | ||||
| self.state = output | self.state = output | ||||
| def __eq__(self, other): | |||||
| """ Check whether two quantum states are the same or not | |||||
| UP TO A GLOBAL PHASE """ | |||||
| a = normalize_global_phase(self.state) | |||||
| b = normalize_global_phase(other.state) | |||||
| return np.allclose(a, b) | |||||
| def __str__(self): | def __str__(self): | ||||
| s = "" | s = "" | ||||
| @@ -14,7 +14,7 @@ def test_hadamard_only_multiqubit(): | |||||
| g.act_hadamard(i) | g.act_hadamard(i) | ||||
| c.act_hadamard(i) | c.act_hadamard(i) | ||||
| assert np.allclose(g.to_state_vector().state, c.state) | |||||
| assert g.to_state_vector() == c | |||||
| for i in range(100): | for i in range(100): | ||||
| a, b = np.random.randint(0, n-1, 2) | a, b = np.random.randint(0, n-1, 2) | ||||
| @@ -22,9 +22,7 @@ def test_hadamard_only_multiqubit(): | |||||
| g.act_cz(a, b) | g.act_cz(a, b) | ||||
| c.act_cz(a, b) | c.act_cz(a, b) | ||||
| s1 = clifford.normalize_global_phase(g.to_state_vector().state) | |||||
| s2 = clifford.normalize_global_phase(c.state) | |||||
| assert np.allclose(s1, s2) | |||||
| assert g.to_state_vector() == c | |||||
| def test_all_multiqubit(): | def test_all_multiqubit(): | ||||
| @@ -34,13 +32,13 @@ def test_all_multiqubit(): | |||||
| c = CircuitModel(n) | c = CircuitModel(n) | ||||
| for i in range(10): | for i in range(10): | ||||
| i = np.random.randint(0, n-1) | |||||
| j = np.random.randint(0, 24) | |||||
| print i, j | |||||
| g.act_local_rotation(i, j) | |||||
| c.act_local_rotation(i, clifford.unitaries[j]) | |||||
| qubit = np.random.randint(0, n-1) | |||||
| rotation = np.random.randint(0, 24-1) | |||||
| g.act_local_rotation(qubit, rotation) | |||||
| c.act_local_rotation(qubit, clifford.unitaries[rotation]) | |||||
| assert np.allclose(g.to_state_vector().state, c.state) | |||||
| assert g.to_state_vector() == c | |||||
| #for i in range(100): | #for i in range(100): | ||||
| #a, b = np.random.randint(0, n-1, 2) | #a, b = np.random.randint(0, n-1, 2) | ||||
| @@ -48,7 +46,5 @@ def test_all_multiqubit(): | |||||
| #g.act_cz(a, b) | #g.act_cz(a, b) | ||||
| #c.act_cz(a, b) | #c.act_cz(a, b) | ||||
| #s1 = clifford.normalize_global_phase(g.to_state_vector().state) | |||||
| #s2 = clifford.normalize_global_phase(c.state) | |||||
| #assert np.allclose(s1, s2) | |||||
| assert g.to_state_vector() == c | |||||
| @@ -30,7 +30,7 @@ def test_cz_table(): | |||||
| # Go and compute the output | # Go and compute the output | ||||
| computed_output = np.dot(qi.cz, input_state) | computed_output = np.dot(qi.cz, input_state) | ||||
| computed_output = clifford.normalize_global_phase(computed_output) | |||||
| computed_output = qi.normalize_global_phase(computed_output) | |||||
| # Now look up the answer in the table | # Now look up the answer in the table | ||||
| bondp, c1p, c2p = ab_cz_table[bond, c1, c2] | bondp, c1p, c2p = ab_cz_table[bond, c1, c2] | ||||
| @@ -15,7 +15,7 @@ def test_cz_table(): | |||||
| # Go and compute the output | # Go and compute the output | ||||
| computed_output = np.dot(qi.cz, input_state) | computed_output = np.dot(qi.cz, input_state) | ||||
| computed_output = clifford.normalize_global_phase(computed_output) | |||||
| computed_output = qi.normalize_global_phase(computed_output) | |||||
| # Now look up the answer in the table | # Now look up the answer in the table | ||||
| bondp, c1p, c2p = clifford.cz_table[bond, c1, c2] | bondp, c1p, c2p = clifford.cz_table[bond, c1, c2] | ||||
| @@ -7,5 +7,5 @@ def test_normalize_global_phase(): | |||||
| u = qi.pz | u = qi.pz | ||||
| phase = np.random.uniform(0, 2*np.pi) | phase = np.random.uniform(0, 2*np.pi) | ||||
| m = np.exp(1j*phase) * u | m = np.exp(1j*phase) * u | ||||
| normalized = clifford.normalize_global_phase(m) | |||||
| normalized = qi.normalize_global_phase(m) | |||||
| assert np.allclose(normalized, u) | assert np.allclose(normalized, u) | ||||
| @@ -1,11 +1,38 @@ | |||||
| import numpy as np | import numpy as np | ||||
| from abp import qi | from abp import qi | ||||
| def _test_init(): | |||||
| def test_init(): | |||||
| """ Can you initialize some qubits """ | """ Can you initialize some qubits """ | ||||
| psi = qi.CircuitModel(5) | psi = qi.CircuitModel(5) | ||||
| assert psi.d == 32 | assert psi.d == 32 | ||||
| def test_single_qubit_stuff(): | |||||
| """ Try some sensible single-qubit things """ | |||||
| psi = qi.CircuitModel(2) | |||||
| psi.act_local_rotation(0, qi.px) | |||||
| assert np.allclose(psi.state[1], 1) | |||||
| psi.act_local_rotation(0, qi.px) | |||||
| assert np.allclose(psi.state[0], 1) | |||||
| psi.act_local_rotation(0, qi.pz) | |||||
| def test_more_single_qubit_stuff(): | |||||
| """ Try some sensible single-qubit things """ | |||||
| psi = qi.CircuitModel(2) | |||||
| psi.act_local_rotation(0, qi.px) | |||||
| psi.act_local_rotation(1, qi.px) | |||||
| psi.act_cz(0, 1) | |||||
| def test_equality(): | |||||
| """ Test that equality succeeds / fails as desired """ | |||||
| a = qi.CircuitModel(2) | |||||
| b = qi.CircuitModel(2) | |||||
| assert a == b | |||||
| a.act_local_rotation(0, qi.px) | |||||
| assert a != b | |||||
| def test_hadamard(): | def test_hadamard(): | ||||
| """ What does CZ do ? """ | """ What does CZ do ? """ | ||||
| psi = qi.CircuitModel(3) | psi = qi.CircuitModel(3) | ||||