@@ -0,0 +1,18 @@ | |||
import numpy as np | |||
import os, json | |||
decompositions = ("xxxx", "xx", "zzxx", "zz", "zxx", "z", "zzz", "xxz", | |||
"xzx", "xzxxx", "xzzzx", "xxxzx", "xzz", "zzx", "xxx", "x", | |||
"zzzx", "xxzx", "zx", "zxxx", "xxxz", "xzzz", "xz", "xzxx") | |||
directory = os.path.dirname(os.path.abspath(__file__)) | |||
where = os.path.join(directory, "tables/") | |||
os.chdir(where) | |||
unitaries = np.load("unitaries.npy") | |||
conjugation_table = np.load("conjugation_table.npy") | |||
times_table = np.load("times_table.npy") | |||
cz_table = np.load("cz_table.npy") | |||
with open("by_name.json") as f: | |||
by_name = json.load(f) | |||
@@ -4,7 +4,7 @@ Provides an extremely basic graph structure, based on neighbour lists | |||
from collections import defaultdict | |||
import itertools as it | |||
import tables as clifford | |||
import clifford | |||
class GraphState(object): | |||
@@ -5,15 +5,13 @@ | |||
This program generates lookup tables | |||
""" | |||
import os, json | |||
from functools import reduce | |||
import itertools as it | |||
import qi | |||
import numpy as np | |||
from tqdm import tqdm | |||
from functools import reduce | |||
import itertools as it | |||
decompositions = ("xxxx", "xx", "zzxx", "zz", "zxx", "z", "zzz", "xxz", | |||
"xzx", "xzxxx", "xzzzx", "xxxzx", "xzz", "zzx", "xxx", "x", | |||
"zzzx", "xxzx", "zx", "zxxx", "xxxz", "xzzz", "xz", "xzxx") | |||
from clifford import decompositions | |||
def find_clifford(needle, haystack): | |||
@@ -52,19 +50,20 @@ def compose_u(decomposition): | |||
return reduce(np.dot, matrices, np.matrix(np.eye(2, dtype=complex))) | |||
def get_unitaries(decompositions): | |||
def get_unitaries(): | |||
""" The Clifford group """ | |||
return [compose_u(d) for d in decompositions] | |||
def hermitian_conjugate(u): | |||
""" Get the hermitian conjugate """ | |||
return np.conjugate(np.transpose(u)) | |||
def get_by_name(unitaries): | |||
""" Get a lookup table of cliffords by name """ | |||
return {name: find_clifford(u, unitaries) | |||
for name, u in qi.by_name.items()} | |||
def get_conjugation_table(unitaries): | |||
""" Construct the conjugation table """ | |||
return np.array([find_clifford(hermitian_conjugate(u), unitaries) for u in unitaries]) | |||
return np.array([find_clifford(qi.hermitian_conjugate(u), unitaries) for u in unitaries]) | |||
def get_times_table(unitaries): | |||
@@ -73,10 +72,11 @@ def get_times_table(unitaries): | |||
for u in tqdm(unitaries, desc="Building times-table")]) | |||
def get_state_table(): | |||
def get_state_table(unitaries): | |||
""" Cache a table of state to speed up a little bit """ | |||
state_table = np.zeros((2, 24, 24, 4), dtype=complex) | |||
for bond, i, j in it.product([0, 1], range(24), range(24)): | |||
params = list(it.product([0, 1], range(24), range(24))) | |||
for bond, i, j in tqdm(params, desc="Building state table"): | |||
state = qi.bond if bond else qi.nobond | |||
kp = np.kron(unitaries[i], unitaries[j]) | |||
state_table[bond, i, j, :] = np.dot(kp, state).T | |||
@@ -85,10 +85,11 @@ def get_state_table(): | |||
def get_cz_table(unitaries): | |||
""" Compute the lookup table for the CZ (A&B eq. 9) """ | |||
commuters = (qi.id, qi.px, qi.pz, qi.ph, hermitian_conjugate(qi.ph)) | |||
commuters = (qi.id, qi.px, qi.pz, qi.ph, qi.hermitian_conjugate(qi.ph)) | |||
commuters = [find_clifford(u, unitaries) for u in commuters] | |||
state_table = get_state_table() | |||
state_table = get_state_table(unitaries) | |||
# TODO: it's symmetric. this can be much faster | |||
cz_table = np.zeros((2, 24, 24, 3)) | |||
rows = list(it.product([0, 1], range(24), range(24))) | |||
for bond, c1, c2 in tqdm(rows, desc="Building CZ table"): | |||
@@ -96,23 +97,23 @@ def get_cz_table(unitaries): | |||
return cz_table | |||
if not __name__ == "__main__": | |||
try: | |||
unitaries = np.load("tables/unitaries.npy") | |||
conjugation_table = np.load("tables/conjugation_table.npy") | |||
times_table = np.load("tables/times_table.npy") | |||
cz_table = np.load("tables/cz_table.npy") | |||
except IOError: | |||
print "Precomputed tables not found, try running `python make_tables.py`" | |||
if __name__ == "__main__": | |||
unitaries = get_unitaries(decompositions) | |||
# Spend time loading the stuff | |||
unitaries = get_unitaries() | |||
by_name = get_by_name(unitaries) | |||
conjugation_table = get_conjugation_table(unitaries) | |||
times_table = get_times_table(unitaries) | |||
cz_table = get_cz_table(unitaries) | |||
#cz_table = get_cz_table(unitaries) | |||
# Write it all to disk | |||
directory = os.path.dirname(os.path.abspath(__file__)) | |||
where = os.path.join(directory, "tables/") | |||
os.chdir(where) | |||
np.save("unitaries.npy", unitaries) | |||
np.save("conjugation_table.npy", conjugation_table) | |||
np.save("times_table.npy", times_table) | |||
#np.save("cz_table.npy", cz_table) | |||
with open("by_name.json", "wb") as f: | |||
json.dump(by_name, f) | |||
np.save("tables/unitaries.npy", unitaries) | |||
np.save("tables/conjugation_table.npy", conjugation_table) | |||
np.save("tables/times_table.npy", times_table) | |||
np.save("tables/cz_table.npy", cz_table) |
@@ -8,6 +8,10 @@ Exposes a few basic QI operators | |||
import numpy as np | |||
from scipy.linalg import sqrtm | |||
def hermitian_conjugate(u): | |||
""" Shortcut to the Hermitian conjugate """ | |||
return np.conjugate(np.transpose(u)) | |||
# Operators | |||
id = np.array(np.eye(2, dtype=complex)) | |||
px = np.array([[0, 1], [1, 0]], dtype=complex) | |||
@@ -0,0 +1 @@ | |||
../abp/ |
@@ -0,0 +1,13 @@ | |||
from abp import make_tables | |||
import cProfile, pstats, StringIO | |||
unitaries = make_tables.get_unitaries() | |||
profiler = cProfile.Profile() | |||
profiler.enable() | |||
make_tables.get_cz_table(unitaries) | |||
profiler.disable() | |||
# Print output | |||
stats = pstats.Stats(profiler).strip_dirs().sort_stats('tottime') | |||
stats.print_stats(10) |
@@ -1,59 +1,8 @@ | |||
import tables as lc | |||
from numpy import * | |||
from scipy.linalg import sqrtm | |||
import qi | |||
from tqdm import tqdm | |||
import itertools as it | |||
from abp import clifford | |||
def identify_pauli(m): | |||
""" Given a signed Pauli matrix, name it. """ | |||
for sign in (+1, -1): | |||
for pauli_label, pauli in zip("xyz", qi.paulis): | |||
if allclose(sign * pauli, m): | |||
return sign, pauli_label | |||
def _test_find(): | |||
""" Test that slightly suspicious function """ | |||
assert lc.find(id, lc.unitaries) == 0 | |||
assert lc.find(px, lc.unitaries) == 1 | |||
assert lc.find(exp(1j*pi/4.)*ha, lc.unitaries) == 4 | |||
def get_action(u): | |||
""" What does this unitary operator do to the Paulis? """ | |||
return [identify_pauli(u * p * u.H) for p in qi.paulis] | |||
def format_action(action): | |||
return "".join("{}{}".format("+" if s >= 0 else "-", p) for s, p in action) | |||
def test_we_have_24_matrices(): | |||
""" Check that we have 24 unique actions on the Bloch sphere """ | |||
actions = set(tuple(get_action(u)) for u in lc.unitaries) | |||
assert len(set(actions)) == 24 | |||
def test_we_have_all_useful_gates(): | |||
""" Check that all the interesting gates are included up to a global phase """ | |||
for name, u in qi.by_name.items(): | |||
lc.find(u, lc.unitaries) | |||
def _test_group(): | |||
""" Test we are really in a group """ | |||
matches = set() | |||
for a, b in tqdm(it.combinations(lc.unitaries, 2), "Testing this is a group"): | |||
i, phase = lc.find(a*b, lc.unitaries) | |||
matches.add(i) | |||
assert len(matches)==24 | |||
def test_conjugation_table(): | |||
""" Check that the table of Hermitian conjugates is okay """ | |||
assert len(set(lc.conjugation_table))==24 | |||
def test_times_table(): | |||
""" Check the times table """ | |||
assert lc.times_table[0][4]==4 |
@@ -1,5 +1,5 @@ | |||
from graph import GraphState | |||
import tables as lc | |||
from abp.graph import GraphState | |||
import abp.tables as tables | |||
import time | |||
@@ -41,13 +41,13 @@ def test_remove_vop(): | |||
""" Test that removing VOPs really works """ | |||
g = demograph() | |||
g.remove_vop(0, 1) | |||
assert g.vops[0] == lc.by_name["identity"] | |||
#assert g.vops[0] == lc.by_name["identity"] | |||
g.remove_vop(1, 1) | |||
assert g.vops[1] == lc.by_name["identity"] | |||
#assert g.vops[1] == lc.by_name["identity"] | |||
g.remove_vop(2, 1) | |||
assert g.vops[2] == lc.by_name["identity"] | |||
#assert g.vops[2] == lc.by_name["identity"] | |||
g.remove_vop(0, 1) | |||
assert g.vops[0] == lc.by_name["identity"] | |||
#assert g.vops[0] == lc.by_name["identity"] | |||
def test_edgelist(): | |||