Anders and Briegel in Python
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
3.5KB

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. """
  4. This program generates lookup tables
  5. """
  6. import qi
  7. import numpy as np
  8. from tqdm import tqdm
  9. from functools import reduce
  10. import itertools as it
  11. DECOMPOSITIONS = ("xxxx", "xx", "zzxx", "zz", "zxx", "z", "zzz", "xxz",
  12. "xzx", "xzxxx", "xzzzx", "xxxzx", "xzz", "zzx", "xxx", "x",
  13. "zzzx", "xxzx", "zx", "zxxx", "xxxz", "xzzz", "xz", "xzxx")
  14. def find_clifford(needle, haystack):
  15. """ Find the index of a given u within a list of unitaries, up to a global phase """
  16. for i, t in enumerate(haystack):
  17. for phase in range(8):
  18. if np.allclose(t, np.exp(1j * phase * np.pi / 4.) * needle):
  19. return i
  20. raise IndexError
  21. def find_cz(bond, c1, c2, commuters, state_table):
  22. """ Find the output of a CZ operation """
  23. # Figure out the target state
  24. state = qi.bond if bond else qi.nobond
  25. target = qi.cz.dot(state_table[bond, c1, c2])
  26. # Choose the sets to search over
  27. s1 = commuters if c1 in commuters else xrange(24)
  28. s2 = commuters if c2 in commuters else xrange(24)
  29. # Find a match
  30. for bond, c1p, c2p in it.product([0, 1], s1, s2):
  31. trial = state_table[bond, c1p, c2p]
  32. for phase in range(8):
  33. if np.allclose(target, np.exp(1j * phase * np.pi / 4.) * trial):
  34. return bond, c1p, c2p
  35. # Didn't find anything - this should never happen
  36. raise IndexError
  37. def compose_u(decomposition):
  38. """ Get the unitary representation of a particular decomposition """
  39. matrices = ({"x": qi.sqx, "z": qi.msqz}[c] for c in decomposition)
  40. return reduce(np.dot, matrices, np.matrix(np.eye(2, dtype=complex)))
  41. def get_unitaries(decompositions):
  42. """ The Clifford group """
  43. return [compose_u(d) for d in decompositions]
  44. def hermitian_conjugate(u):
  45. """ Get the hermitian conjugate """
  46. return np.conjugate(np.transpose(u))
  47. def get_conjugation_table(unitaries):
  48. """ Construct the conjugation table """
  49. return np.array([find_clifford(hermitian_conjugate(u), unitaries) for u in unitaries])
  50. def get_times_table(unitaries):
  51. """ Construct the times-table """
  52. return np.array([[find_clifford(u.dot(v), unitaries) for v in unitaries]
  53. for u in tqdm(unitaries)])
  54. def get_state_table():
  55. """ Cache a table of state to speed up a little bit """
  56. state_table = np.zeros((2, 24, 24, 4), dtype=complex)
  57. for bond, i, j in it.product([0, 1], range(24), range(24)):
  58. state = qi.bond if bond else qi.nobond
  59. kp = np.kron(unitaries[i], unitaries[j])
  60. state_table[bond, i, j,:] = np.dot(kp, state).T
  61. return state_table
  62. def get_cz_table(unitaries):
  63. """ Compute the lookup table for the CZ (A&B eq. 9) """
  64. commuters = (qi.id, qi.px, qi.pz, qi.ph, hermitian_conjugate(qi.ph))
  65. commuters = [find_clifford(u, unitaries) for u in commuters]
  66. state_table = get_state_table()
  67. cz_table = np.zeros((2, 24, 24, 3))
  68. for bond, c1, c2 in tqdm(list(it.product([0, 1], range(24), range(24)))):
  69. cz_table[bond, c1, c2] = find_cz(bond, c1, c2, commuters, state_table)
  70. return cz_table
  71. if __name__ == '__main__':
  72. unitaries = get_unitaries(DECOMPOSITIONS)
  73. conjugation_table = get_conjugation_table(unitaries)
  74. times_table = get_times_table(unitaries)
  75. cz_table = get_cz_table(unitaries)
  76. np.save("tables/unitaries.npy", unitaries)
  77. np.save("tables/conjugation_table.npy", conjugation_table)
  78. np.save("tables/times_table.npy", times_table)
  79. np.save("cz_table.npy", cz_table)