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.

clifford.py 2.6KB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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 format_action(action):
  25. return "".join("{}{}".format("+" if s>=0 else "-", p) for s, p in action)
  26. # Some two-qubit matrices
  27. i = matrix(eye(2, dtype=complex))
  28. px = matrix([[0, 1], [1, 0]], dtype=complex)
  29. py = matrix([[0, -1j], [1j, 0]], dtype=complex)
  30. pz = matrix([[1, 0], [0, -1]], dtype=complex)
  31. h = matrix([[1, 1], [1, -1]], dtype=complex) / sqrt(2)
  32. p = matrix([[1, 0], [0, 1j]], dtype=complex)
  33. paulis = (px, py, pz)
  34. # More two-qubit matrices
  35. s_rotations = [i, p, p*p, p*p*p]
  36. s_names = ["i", "p", "pp", "ppp"]
  37. c_rotations = [i, h, h*p, h*p*p, h*p*p*p, h*p*p*h]
  38. c_names = ["i", "h", "hp", "hpp", "hppp", "hpph"]
  39. # Build the table of VOPs according to Anders (verbatim from thesis)
  40. table = (("a", "xyz", +1), ("b", "yxz", -1), ("c", "zyx", -1),
  41. ("d", "xzy", -1), ("e", "yzx", +1), ("f", "zxy", +1))
  42. # Build a big ol lookup table
  43. vop_names = []
  44. vop_actions = []
  45. vop_gates = [None]*24
  46. vop_unitaries = [None]*24
  47. for label, permutation, sign in table:
  48. for column, operator in zip("ixyz", "i"+permutation):
  49. effect = [((sign if (p==column or column=="i") else -sign), p)
  50. for p in permutation]
  51. vop_names.append(label+operator)
  52. vop_actions.append(format_action(effect))
  53. for s, sn in zip(s_rotations, s_names):
  54. for c, cn in zip(c_rotations, c_names):
  55. u = s*c
  56. action = format_action(identify_pauli(u*p*u.H) for p in paulis)
  57. index = vop_actions.index(action)
  58. vop_gates[index] = sn+cn
  59. vop_unitaries[index] = u
  60. # Add some more useful lookups