qasm.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. """
  2. qasm.py - Functions to parse a set of qasm commands into a SymPy Circuit.
  3. Examples taken from Chuang's page: http://www.media.mit.edu/quanta/qasm2circ/
  4. The code returns a circuit and an associated list of labels.
  5. >>> from sympy.physics.quantum.qasm import Qasm
  6. >>> q = Qasm('qubit q0', 'qubit q1', 'h q0', 'cnot q0,q1')
  7. >>> q.get_circuit()
  8. CNOT(1,0)*H(1)
  9. >>> q = Qasm('qubit q0', 'qubit q1', 'cnot q0,q1', 'cnot q1,q0', 'cnot q0,q1')
  10. >>> q.get_circuit()
  11. CNOT(1,0)*CNOT(0,1)*CNOT(1,0)
  12. """
  13. __all__ = [
  14. 'Qasm',
  15. ]
  16. from sympy.physics.quantum.gate import H, CNOT, X, Z, CGate, CGateS, SWAP, S, T,CPHASE
  17. from sympy.physics.quantum.circuitplot import Mz
  18. def read_qasm(lines):
  19. return Qasm(*lines.splitlines())
  20. def read_qasm_file(filename):
  21. return Qasm(*open(filename).readlines())
  22. def prod(c):
  23. p = 1
  24. for ci in c:
  25. p *= ci
  26. return p
  27. def flip_index(i, n):
  28. """Reorder qubit indices from largest to smallest.
  29. >>> from sympy.physics.quantum.qasm import flip_index
  30. >>> flip_index(0, 2)
  31. 1
  32. >>> flip_index(1, 2)
  33. 0
  34. """
  35. return n-i-1
  36. def trim(line):
  37. """Remove everything following comment # characters in line.
  38. >>> from sympy.physics.quantum.qasm import trim
  39. >>> trim('nothing happens here')
  40. 'nothing happens here'
  41. >>> trim('something #happens here')
  42. 'something '
  43. """
  44. if '#' not in line:
  45. return line
  46. return line.split('#')[0]
  47. def get_index(target, labels):
  48. """Get qubit labels from the rest of the line,and return indices
  49. >>> from sympy.physics.quantum.qasm import get_index
  50. >>> get_index('q0', ['q0', 'q1'])
  51. 1
  52. >>> get_index('q1', ['q0', 'q1'])
  53. 0
  54. """
  55. nq = len(labels)
  56. return flip_index(labels.index(target), nq)
  57. def get_indices(targets, labels):
  58. return [get_index(t, labels) for t in targets]
  59. def nonblank(args):
  60. for line in args:
  61. line = trim(line)
  62. if line.isspace():
  63. continue
  64. yield line
  65. return
  66. def fullsplit(line):
  67. words = line.split()
  68. rest = ' '.join(words[1:])
  69. return fixcommand(words[0]), [s.strip() for s in rest.split(',')]
  70. def fixcommand(c):
  71. """Fix Qasm command names.
  72. Remove all of forbidden characters from command c, and
  73. replace 'def' with 'qdef'.
  74. """
  75. forbidden_characters = ['-']
  76. c = c.lower()
  77. for char in forbidden_characters:
  78. c = c.replace(char, '')
  79. if c == 'def':
  80. return 'qdef'
  81. return c
  82. def stripquotes(s):
  83. """Replace explicit quotes in a string.
  84. >>> from sympy.physics.quantum.qasm import stripquotes
  85. >>> stripquotes("'S'") == 'S'
  86. True
  87. >>> stripquotes('"S"') == 'S'
  88. True
  89. >>> stripquotes('S') == 'S'
  90. True
  91. """
  92. s = s.replace('"', '') # Remove second set of quotes?
  93. s = s.replace("'", '')
  94. return s
  95. class Qasm:
  96. """Class to form objects from Qasm lines
  97. >>> from sympy.physics.quantum.qasm import Qasm
  98. >>> q = Qasm('qubit q0', 'qubit q1', 'h q0', 'cnot q0,q1')
  99. >>> q.get_circuit()
  100. CNOT(1,0)*H(1)
  101. >>> q = Qasm('qubit q0', 'qubit q1', 'cnot q0,q1', 'cnot q1,q0', 'cnot q0,q1')
  102. >>> q.get_circuit()
  103. CNOT(1,0)*CNOT(0,1)*CNOT(1,0)
  104. """
  105. def __init__(self, *args, **kwargs):
  106. self.defs = {}
  107. self.circuit = []
  108. self.labels = []
  109. self.inits = {}
  110. self.add(*args)
  111. self.kwargs = kwargs
  112. def add(self, *lines):
  113. for line in nonblank(lines):
  114. command, rest = fullsplit(line)
  115. if self.defs.get(command): #defs come first, since you can override built-in
  116. function = self.defs.get(command)
  117. indices = self.indices(rest)
  118. if len(indices) == 1:
  119. self.circuit.append(function(indices[0]))
  120. else:
  121. self.circuit.append(function(indices[:-1], indices[-1]))
  122. elif hasattr(self, command):
  123. function = getattr(self, command)
  124. function(*rest)
  125. else:
  126. print("Function %s not defined. Skipping" % command)
  127. def get_circuit(self):
  128. return prod(reversed(self.circuit))
  129. def get_labels(self):
  130. return list(reversed(self.labels))
  131. def plot(self):
  132. from sympy.physics.quantum.circuitplot import CircuitPlot
  133. circuit, labels = self.get_circuit(), self.get_labels()
  134. CircuitPlot(circuit, len(labels), labels=labels, inits=self.inits)
  135. def qubit(self, arg, init=None):
  136. self.labels.append(arg)
  137. if init: self.inits[arg] = init
  138. def indices(self, args):
  139. return get_indices(args, self.labels)
  140. def index(self, arg):
  141. return get_index(arg, self.labels)
  142. def nop(self, *args):
  143. pass
  144. def x(self, arg):
  145. self.circuit.append(X(self.index(arg)))
  146. def z(self, arg):
  147. self.circuit.append(Z(self.index(arg)))
  148. def h(self, arg):
  149. self.circuit.append(H(self.index(arg)))
  150. def s(self, arg):
  151. self.circuit.append(S(self.index(arg)))
  152. def t(self, arg):
  153. self.circuit.append(T(self.index(arg)))
  154. def measure(self, arg):
  155. self.circuit.append(Mz(self.index(arg)))
  156. def cnot(self, a1, a2):
  157. self.circuit.append(CNOT(*self.indices([a1, a2])))
  158. def swap(self, a1, a2):
  159. self.circuit.append(SWAP(*self.indices([a1, a2])))
  160. def cphase(self, a1, a2):
  161. self.circuit.append(CPHASE(*self.indices([a1, a2])))
  162. def toffoli(self, a1, a2, a3):
  163. i1, i2, i3 = self.indices([a1, a2, a3])
  164. self.circuit.append(CGateS((i1, i2), X(i3)))
  165. def cx(self, a1, a2):
  166. fi, fj = self.indices([a1, a2])
  167. self.circuit.append(CGate(fi, X(fj)))
  168. def cz(self, a1, a2):
  169. fi, fj = self.indices([a1, a2])
  170. self.circuit.append(CGate(fi, Z(fj)))
  171. def defbox(self, *args):
  172. print("defbox not supported yet. Skipping: ", args)
  173. def qdef(self, name, ncontrols, symbol):
  174. from sympy.physics.quantum.circuitplot import CreateOneQubitGate, CreateCGate
  175. ncontrols = int(ncontrols)
  176. command = fixcommand(name)
  177. symbol = stripquotes(symbol)
  178. if ncontrols > 0:
  179. self.defs[command] = CreateCGate(symbol)
  180. else:
  181. self.defs[command] = CreateOneQubitGate(symbol)