@@ -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) | ||||