From 42d209b27e4444ee6ca3a63cf1df0f3c25968c18 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Fri, 6 May 2016 13:40:30 +0100 Subject: [PATCH] Re-organize --- abp/clifford.py | 148 ++++++++++++++++++++++++++++++++++++++++++--- abp/make_tables.py | 129 --------------------------------------- 2 files changed, 138 insertions(+), 139 deletions(-) delete mode 100644 abp/make_tables.py diff --git a/abp/clifford.py b/abp/clifford.py index e3ed58c..ca489a8 100644 --- a/abp/clifford.py +++ b/abp/clifford.py @@ -1,18 +1,146 @@ -import numpy as np +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +This program generates lookup tables +""" + import os, json +from functools import reduce +import itertools as it +from . import qi +import numpy as np +import tempfile +from tqdm import tqdm 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) +def find_clifford(needle, haystack): + """ Find the index of a given u within a list of unitaries, up to a global phase """ + needle = normalize_global_phase(needle) + for i, t in enumerate(haystack): + if np.allclose(t, needle): + return i + 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): + """ Find the output of a CZ operation """ + # Figure out the target state + target = qi.cz.dot(state_table[bond, c1, c2]) + target = normalize_global_phase(target) + + # Choose the sets to search over + s1 = commuters if c1 in commuters else xrange(24) + s2 = commuters if c2 in commuters else xrange(24) + + # Find a match + for bond, c1p, c2p in it.product([0, 1], s1, s2): + if np.allclose(target, state_table[bond, c1p, c2p]): + return bond, c1p, c2p + + # Didn't find anything - this should never happen + raise IndexError + + +def compose_u(decomposition): + """ Get the unitary representation of a particular decomposition """ + matrices = ({"x": qi.sqx, "z": qi.msqz}[c] for c in decomposition) + output = reduce(np.dot, matrices, np.eye(2, dtype=complex)) + return normalize_global_phase(output) + + +def get_unitaries(): + """ The Clifford group """ + return [compose_u(d) for d in decompositions] + + +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(qi.hermitian_conjugate(u), unitaries) for u in unitaries]) + + +def get_times_table(unitaries): + """ Construct the times-table """ + return np.array([[find_clifford(u.dot(v), unitaries) for v in unitaries] + for u in tqdm(unitaries, desc="Building times-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) + 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, :] = normalize_global_phase( + np.dot(kp, state).T) + return state_table + + +def get_cz_table(unitaries): + """ Compute the lookup table for the CZ (A&B eq. 9) """ + # This is the set of Cliffords which commute with CZ + commuters = (qi.id, qi.px, qi.pz, qi.ph, qi.hermitian_conjugate(qi.ph)) + commuters = [find_clifford(u, unitaries) for u in commuters] + + # Get a cached state table + state_table = get_state_table(unitaries) + + # And now build the CZ table + cz_table = np.zeros((2, 24, 24, 3)) + rows = list(it.product([0, 1], it.combinations(range(24), 2))) + # CZ is symmetric so we only need combinations + for bond, (c1, c2) in tqdm(rows, desc="Building CZ table"): + newbond, c1p, c2p = find_cz(bond, c1, c2, commuters, state_table) + cz_table[bond, c1, c2] = [newbond, c1p, c2p] + cz_table[bond, c2, c1] = [newbond, c2p, c1p] + return cz_table + + +# First try to load tables from cache. If that fails, build them from +# scratch and store +os.chdir(tempfile.gettempdir()) +try: + 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) + + print "Loaded tables from cache" +except IOError: + # Spend time building the tables + 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) + + # Write it all to disk + 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) diff --git a/abp/make_tables.py b/abp/make_tables.py deleted file mode 100644 index 602abc1..0000000 --- a/abp/make_tables.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -This program generates lookup tables -""" - -import os, json -from functools import reduce -import itertools as it -import qi -import numpy as np -import tempfile -from tqdm import tqdm -from clifford import decompositions - - -def find_clifford(needle, haystack): - """ Find the index of a given u within a list of unitaries, up to a global phase """ - needle = normalize_global_phase(needle) - for i, t in enumerate(haystack): - if np.allclose(t, needle): - return i - 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): - """ Find the output of a CZ operation """ - # Figure out the target state - target = qi.cz.dot(state_table[bond, c1, c2]) - target = normalize_global_phase(target) - - # Choose the sets to search over - s1 = commuters if c1 in commuters else xrange(24) - s2 = commuters if c2 in commuters else xrange(24) - - # Find a match - for bond, c1p, c2p in it.product([0, 1], s1, s2): - if np.allclose(target, state_table[bond, c1p, c2p]): - return bond, c1p, c2p - - # Didn't find anything - this should never happen - raise IndexError - - -def compose_u(decomposition): - """ Get the unitary representation of a particular decomposition """ - matrices = ({"x": qi.sqx, "z": qi.msqz}[c] for c in decomposition) - output = reduce(np.dot, matrices, np.eye(2, dtype=complex)) - return normalize_global_phase(output) - - -def get_unitaries(): - """ The Clifford group """ - return [compose_u(d) for d in decompositions] - - -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(qi.hermitian_conjugate(u), unitaries) for u in unitaries]) - - -def get_times_table(unitaries): - """ Construct the times-table """ - return np.array([[find_clifford(u.dot(v), unitaries) for v in unitaries] - for u in tqdm(unitaries, desc="Building times-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) - 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, :] = normalize_global_phase(np.dot(kp, state).T) - return state_table - - -def get_cz_table(unitaries): - """ Compute the lookup table for the CZ (A&B eq. 9) """ - # This is the set of Cliffords which commute with CZ - commuters = (qi.id, qi.px, qi.pz, qi.ph, qi.hermitian_conjugate(qi.ph)) - commuters = [find_clifford(u, unitaries) for u in commuters] - - # Get a cached state table - state_table = get_state_table(unitaries) - - # And now build the CZ table - cz_table = np.zeros((2, 24, 24, 3)) - rows = list(it.product([0, 1], it.combinations(range(24), 2))) # CZ is symmetric so we only need combinations - for bond, (c1, c2) in tqdm(rows, desc="Building CZ table"): - newbond, c1p, c2p = find_cz(bond, c1, c2, commuters, state_table) - cz_table[bond, c1, c2] = [newbond, c1p, c2p] - cz_table[bond, c2, c1] = [newbond, c2p, c1p] - return cz_table - - -if __name__ == "__main__": - # Spend time building the tables - 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) - - # Write it all to disk - where = tempfile.gettempdir() - 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)