Anders and Briegel in Python
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

221 lignes
7.6KB

  1. """
  2. This program computes lookup tables and stores them as tables.py and tables.js
  3. # TODO: clifford naming discrepancy
  4. """
  5. from __future__ import absolute_import
  6. from __future__ import print_function
  7. import numpy as np
  8. import itertools as it
  9. from functools import reduce
  10. from os.path import dirname, join, split
  11. import json
  12. from . import qi, clifford
  13. from six.moves import range
  14. DECOMPOSITIONS = (
  15. "xxxx", "xx", "zzxx", "zz", "zxx", "z", "zzz", "xxz", "xzx", "xzxxx", "xzzzx",
  16. "xxxzx", "xzz", "zzx", "xxx", "x", "zzzx", "xxzx", "zx", "zxxx", "xxxz", "xzzz", "xz", "xzxx")
  17. PY_TEMPLATE = """\
  18. import numpy as np
  19. # Define lookup tables
  20. ir2 = 1/np.sqrt(2)
  21. decompositions = {decompositions}
  22. conjugation_table = np.array({conjugation_table}, dtype=int)
  23. times_table = np.array({times_table}, dtype=int)
  24. cz_table = np.array({cz_table}, dtype=int)
  25. by_name = {by_name}
  26. measurement_table = np.array({measurement_table}, dtype=int)
  27. unitaries_real = np.array({unitaries_real}, dtype=complex)
  28. unitaries_imag = np.array({unitaries_imag}, dtype=complex)
  29. # Reconstruct
  30. unitaries = unitaries_real + 1j*unitaries_imag
  31. """
  32. def find_clifford(needle, haystack):
  33. """ Find the index of a given u within a list of unitaries, up to a global phase """
  34. needle = qi.normalize_global_phase(needle)
  35. for i, t in enumerate(haystack):
  36. if np.allclose(t, needle):
  37. return i
  38. raise IndexError
  39. def find_cz(bond, c1, c2, commuters, state_table):
  40. """ Find the output of a CZ operation """
  41. # Figure out the target state
  42. target = qi.cz.dot(state_table[bond, c1, c2])
  43. target = qi.normalize_global_phase(target)
  44. # Choose the sets to search over
  45. s1 = commuters if c1 in commuters else list(range(24))
  46. s2 = commuters if c2 in commuters else list(range(24))
  47. # Find a match
  48. for bondp, c1p, c2p in it.product([0, 1], s1, s2):
  49. if np.allclose(target, state_table[bondp, c1p, c2p]):
  50. return bondp, c1p, c2p
  51. # Didn't find anything - this should never happen
  52. raise IndexError
  53. def compose_u(decomposition):
  54. """ Get the unitary representation of a particular decomposition """
  55. matrices = ({"x": qi.msqx, "z": qi.sqz}[c] for c in decomposition)
  56. output = reduce(np.dot, matrices, np.eye(2, dtype=complex))
  57. return qi.normalize_global_phase(output)
  58. def get_unitaries():
  59. """ The Clifford group """
  60. return [compose_u(d) for d in DECOMPOSITIONS]
  61. def get_by_name(unitaries, conjugation_table):
  62. """ Get a lookup table of cliffords by name """
  63. a = {name: find_clifford(u, unitaries)
  64. for name, u in list(qi.by_name.items())}
  65. a.update({key + "_h": conjugation_table[value]
  66. for key, value in list(a.items())})
  67. a.update({clifford.get_name(i): i for i in range(24)})
  68. a.update({i: i for i in range(24)})
  69. return a
  70. def get_conjugation_table(unitaries):
  71. """ Construct the conjugation table """
  72. return np.array([find_clifford(qi.hermitian_conjugate(u), unitaries) for u in unitaries], dtype=int)
  73. def get_times_table(unitaries):
  74. """ Construct the times-table """
  75. return np.array([[find_clifford(u.dot(v), unitaries) for v in unitaries]
  76. for u in unitaries], dtype=int)
  77. def get_state_table(unitaries):
  78. """ Cache a table of state to speed up a little bit """
  79. state_table = np.zeros((2, 24, 24, 4), dtype=complex)
  80. params = list(it.product([0, 1], list(range(24)), list(range(24))))
  81. for bond, i, j in params:
  82. state = qi.bond if bond else qi.nobond
  83. kp = np.kron(unitaries[i], unitaries[j])
  84. state_table[bond, i, j, :] = qi.normalize_global_phase(
  85. np.dot(kp, state).T)
  86. return state_table
  87. def get_measurement_entry(operator, unitary):
  88. """
  89. Any Clifford group unitary will map an operator A in {I, X, Y, Z}
  90. to an operator B in +-{I, X, Y, Z}. This finds that mapping.
  91. """
  92. matrices = ({"x": qi.msqx, "z": qi.sqz}[c]
  93. for c in DECOMPOSITIONS[unitary])
  94. unitary = reduce(np.dot, matrices, np.eye(2, dtype=complex))
  95. operator = qi.operators[operator]
  96. new_operator = reduce(np.dot,
  97. (unitary, operator, qi.hermitian_conjugate(unitary)))
  98. for i, o in enumerate(qi.operators):
  99. if np.allclose(o, new_operator):
  100. return i, 1
  101. elif np.allclose(o, -new_operator):
  102. return i, -1
  103. raise IndexError
  104. def get_measurement_table():
  105. """
  106. Compute a table of transform * operation * transform^dagger
  107. This is pretty unintelligible right now, we should probably compute the phase from unitaries instead
  108. """
  109. measurement_table = np.zeros((4, 24, 2), dtype=int)
  110. for operator, unitary in it.product(list(range(4)), list(range(24))):
  111. measurement_table[operator, unitary] = get_measurement_entry(
  112. operator, unitary)
  113. return measurement_table
  114. def get_commuters(unitaries):
  115. """ Get the indeces of gates which commute with CZ """
  116. commuters = (qi.id, qi.pz, qi.ph, qi.hermitian_conjugate(qi.ph))
  117. return [find_clifford(u, unitaries) for u in commuters]
  118. def get_cz_table(unitaries):
  119. """ Compute the lookup table for the CZ (A&B eq. 9) """
  120. # Get a cached state table and a list of gates which commute with CZ
  121. commuters = get_commuters(unitaries)
  122. state_table = get_state_table(unitaries)
  123. # And now build the CZ table
  124. cz_table = np.zeros((2, 24, 24, 3), dtype=int)
  125. rows = list(
  126. it.product([0, 1], it.combinations_with_replacement(list(range(24)), 2)))
  127. # CZ is symmetric so we only need combinations
  128. for bond, (c1, c2) in rows:
  129. newbond, c1p, c2p = find_cz(
  130. bond, c1, c2, commuters, state_table)
  131. cz_table[bond, c1, c2] = [newbond, c1p, c2p]
  132. cz_table[bond, c2, c1] = [newbond, c2p, c1p]
  133. return cz_table
  134. def get_display_table(unitaries):
  135. """ Used to display VOPs in a human readable style """
  136. for u in unitaries:
  137. c = qi.CircuitModel(1)
  138. c.act_local_rotation(0, u)
  139. state = c.state.round(2)
  140. print(("{:.2f}, {:.2f}".format(state[0][0], state[1][0])))
  141. def compute_everything():
  142. """ Compute all lookup tables """
  143. unitaries = get_unitaries()
  144. conjugation_table = get_conjugation_table(unitaries)
  145. return {"decompositions": DECOMPOSITIONS,
  146. "unitaries": unitaries,
  147. "by_name": get_by_name(unitaries, conjugation_table),
  148. "conjugation_table": conjugation_table,
  149. "times_table": get_times_table(unitaries),
  150. "cz_table": get_cz_table(unitaries),
  151. "measurement_table": get_measurement_table()}
  152. def human_readable(data):
  153. """ Format the data """
  154. unitaries = np.array(data["unitaries"])
  155. return {"decompositions": json.dumps(DECOMPOSITIONS),
  156. "unitaries_real": json.dumps(unitaries.real.round(5).tolist()).replace("0.70711", "ir2"),
  157. "unitaries_imag": json.dumps(unitaries.imag.round(5).tolist()).replace("0.70711", "ir2"),
  158. "conjugation_table": json.dumps(data["conjugation_table"].tolist()),
  159. "times_table": json.dumps(data["times_table"].tolist()),
  160. "cz_table": json.dumps(data["cz_table"].tolist()),
  161. "by_name": json.dumps(data["by_name"]),
  162. "measurement_table": json.dumps(data["measurement_table"].tolist())}
  163. def write_python(data):
  164. """ Write the tables to a python module """
  165. path = join(dirname(__file__), "tables.py")
  166. content = PY_TEMPLATE.format(**data)
  167. with open(path, "w") as f:
  168. f.write(content)
  169. if __name__ == '__main__':
  170. get_display_table(get_unitaries())
  171. data = compute_everything()
  172. data = human_readable(data)
  173. write_python(data)