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.

85 lignes
3.2KB

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. """
  4. Generates and enumerates the 24 elements of the local Clifford group
  5. Following the prescription of Anders (thesis pg. 26):
  6. > Table 2.1: The 24 elements of the local Clifford group. The row index (here called the “sign symbol”) shows how the operator
  7. > U permutes the Pauli operators σ = X, Y, Z under the conjugation σ = ±UσU† . The column index (the “permutation
  8. > symbol”) indicates the sign obtained under the conjugation: For operators U in the I column it is the sign of the permutation
  9. > (indicated on the left). For elements in the X, Y and Z columns, it is this sign only if the conjugated Pauli operator is the one
  10. > indicated by the column header and the opposite sign otherwise.
  11. """
  12. # TODO:
  13. # - check that we re-generate the table
  14. # - do conjugation
  15. # - do times table
  16. # - write tests
  17. from numpy import *
  18. def identify_pauli(m):
  19. """ Given a signed Pauli matrix, name it. """
  20. for sign in (+1, -1):
  21. for pauli_label, pauli in zip("xyz", paulis):
  22. if allclose(sign * pauli, m):
  23. return sign, pauli_label
  24. def get_action(u):
  25. """ What does this unitary operator do to the Paulis? """
  26. return [identify_pauli(u * p * u.H) for p in paulis]
  27. def format_action(action):
  28. """ Format an action as a string """
  29. return "".join("{}{}".format("+" if s >= 0 else "-", p) for s, p in action)
  30. # Some two-qubit matrices
  31. i = matrix(eye(2, dtype=complex))
  32. px = matrix([[0, 1], [1, 0]], dtype=complex)
  33. py = matrix([[0, -1j], [1j, 0]], dtype=complex)
  34. pz = matrix([[1, 0], [0, -1]], dtype=complex)
  35. h = matrix([[1, 1], [1, -1]], dtype=complex) / sqrt(2)
  36. p = matrix([[1, 0], [0, 1j]], dtype=complex)
  37. paulis = (px, py, pz)
  38. # Basic single-qubit gates
  39. s_gates = (("i", i), ("p", p), ("pp", p * p), ("ppp", p * p * p))
  40. c_gates = [("i", i), ("h", h), ("hp", h * p), ("hpp", h * p * p),
  41. ("hppp", h * p * p * p), ("hpph", h * p * p * h)]
  42. # Build the table of VOPs according to Anders (verbatim from thesis)
  43. table = (("a", "xyz", +1), ("b", "yxz", -1), ("c", "zyx", -1),
  44. ("d", "xzy", -1), ("e", "yzx", +1), ("f", "zxy", +1))
  45. # Build a big ol lookup table
  46. vop_names = []
  47. vop_actions = []
  48. vop_gates = [None] * 24
  49. vop_unitaries = [None] * 24
  50. for label, permutation, sign in table:
  51. for column, operator in zip("ixyz", "i" + permutation):
  52. effect = [((sign if (p == column or column == "i") else -sign), p)
  53. for p in permutation]
  54. vop_names.append(column + label) # think we can dump "operator"
  55. vop_actions.append(format_action(effect))
  56. for s_name, s_gate in s_gates:
  57. for c_name, c_gate in c_gates:
  58. u = s_gate * c_gate
  59. action = format_action(get_action(u))
  60. index = vop_actions.index(action)
  61. vop_gates[index] = s_name + c_name
  62. vop_unitaries[index] = u
  63. # Add some more useful lookups
  64. vop_by_name = {n: {"name":n, "index": i, "action": a, "gates": g, "unitary": u}
  65. for n, i, a, g, u in zip(vop_names, xrange(24), vop_actions, vop_gates, vop_unitaries)}
  66. vop_by_action = {a: {"name": n, "index": i, "action":a, "gates": g, "unitary": u}
  67. for n, i, a, g, u in zip(vop_names, xrange(24), vop_actions, vop_gates, vop_unitaries)}