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.9KB

  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. # Some two-qubit matrices
  39. i = matrix(eye(2, dtype=complex))
  40. h = matrix([[1, 1], [1, -1]], dtype=complex) / sqrt(2)
  41. p = matrix([[1, 0], [0, 1j]], dtype=complex)
  42. # Basic single-qubit gates
  43. s_gates = (("i", i), ("p", p), ("pp", p * p), ("ppp", p * p * p))
  44. c_gates = [("i", i), ("h", h), ("hp", h * p), ("hpp", h * p * p),
  45. ("hppp", h * p * p * p), ("hpph", h * p * p * h)]
  46. # Build the table of VOPs according to Anders (verbatim from thesis)
  47. table = (("a", "xyz", +1), ("b", "yxz", -1), ("c", "zyx", -1),
  48. ("d", "xzy", -1), ("e", "yzx", +1), ("f", "zxy", +1))
  49. # Build a big ol lookup table
  50. vop_names = []
  51. vop_actions = []
  52. vop_gates = [None] * 24
  53. vop_unitaries = [None] * 24
  54. for label, permutation, sign in table:
  55. for column, operator in zip("ixyz", "i" + permutation):
  56. effect = [((sign if (p == column or column == "i") else -sign), p)
  57. for p in permutation]
  58. vop_names.append(column + label) # think we can dump "operator"
  59. vop_actions.append(format_action(effect))
  60. for s_name, s_gate in s_gates:
  61. for c_name, c_gate in c_gates:
  62. u = s_gate * c_gate
  63. action = format_action(get_action(u))
  64. index = vop_actions.index(action)
  65. vop_gates[index] = s_name + c_name
  66. vop_unitaries[index] = u
  67. # Add some more useful lookups
  68. vop_by_name = {n: {"name":n, "index": i, "action": a, "gates": g, "unitary": u}
  69. for n, i, a, g, u in zip(vop_names, xrange(24), vop_actions, vop_gates, vop_unitaries)}
  70. vop_by_action = {a: {"name": n, "index": i, "action":a, "gates": g, "unitary": u}
  71. for n, i, a, g, u in zip(vop_names, xrange(24), vop_actions, vop_gates, vop_unitaries)}
  72. names, unitaries = [], []
  73. for c_name, c_gate in c_gates:
  74. for s_name, s_gate in s_gates:
  75. names.append(s_name+c_name)
  76. unitaries.append(s_gate * c_gate)
  77. print s_gate * c_gate.round(2)
  78. print
  79. i = matrix(eye(2, dtype=complex))
  80. px = matrix([[0, 1], [1, 0]], dtype=complex)
  81. py = matrix([[0, -1j], [1j, 0]], dtype=complex)
  82. pz = matrix([[1, 0], [0, -1]], dtype=complex)
  83. h = matrix([[1, 1], [1, -1]], dtype=complex) / sqrt(2)
  84. p = matrix([[1, 0], [0, 1j]], dtype=complex)
  85. #for m in i, px, py, pz:
  86. #print any([allclose(x, m) for x in unitaries])