|
- #!/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
-
- 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")
-
-
- 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_with_replacement(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)
|