We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
For QASM of decomposed circuits add comment
I noticed that if I export CCZ into qasm, I get the h, ccx, h operations with no leading comment saying that they correspond to a CCZ. I'm pretty sure this used to happen.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `cirq/circuits/qasm_output.py`
Content:
```
1 # Copyright 2018 The Cirq Developers
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     https://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 """Utility classes for representing QASM."""
16 
17 from typing import Callable, Dict, Optional, Sequence, Set, Tuple, Union, TYPE_CHECKING
18 
19 import re
20 import numpy as np
21 
22 from cirq import ops, linalg, protocols, value
23 
24 if TYPE_CHECKING:
25     import cirq
26 
27 
28 @value.value_equality(approximate=True)
29 class QasmUGate(ops.SingleQubitGate):
30     def __init__(self, theta, phi, lmda) -> None:
31         """A QASM gate representing any single qubit unitary with a series of
32         three rotations, Z, Y, and Z.
33 
34         The angles are normalized to the range [0, 2) half_turns.
35 
36         Args:
37             theta: Half turns to rotate about Y (applied second).
38             phi: Half turns to rotate about Z (applied last).
39             lmda: Half turns to rotate about Z (applied first).
40         """
41         self.lmda = lmda % 2
42         self.theta = theta % 2
43         self.phi = phi % 2
44 
45     @staticmethod
46     def from_matrix(mat: np.array) -> 'QasmUGate':
47         pre_phase, rotation, post_phase = linalg.deconstruct_single_qubit_matrix_into_angles(mat)
48         return QasmUGate(
49             rotation / np.pi,
50             post_phase / np.pi,
51             pre_phase / np.pi,
52         )
53 
54     def _has_unitary_(self):
55         return True
56 
57     def _qasm_(self, qubits: Tuple['cirq.Qid', ...], args: 'cirq.QasmArgs') -> str:
58         args.validate_version('2.0')
59         return args.format(
60             'u3({0:half_turns},{1:half_turns},{2:half_turns}) {3};\n',
61             self.theta,
62             self.phi,
63             self.lmda,
64             qubits[0],
65         )
66 
67     def __repr__(self) -> str:
68         return (
69             f'cirq.circuits.qasm_output.QasmUGate('
70             f'theta={self.theta!r}, '
71             f'phi={self.phi!r}, '
72             f'lmda={self.lmda})'
73         )
74 
75     def _decompose_(self, qubits):
76         q = qubits[0]
77         return [
78             ops.rz(self.lmda * np.pi).on(q),
79             ops.ry(self.theta * np.pi).on(q),
80             ops.rz(self.phi * np.pi).on(q),
81         ]
82 
83     def _value_equality_values_(self):
84         return self.lmda, self.theta, self.phi
85 
86 
87 @value.value_equality
88 class QasmTwoQubitGate(ops.TwoQubitGate):
89     def __init__(self, kak: linalg.KakDecomposition) -> None:
90         """A two qubit gate represented in QASM by the KAK decomposition.
91 
92         All angles are in half turns.  Assumes a canonicalized KAK
93         decomposition.
94 
95         Args:
96             kak: KAK decomposition of the two-qubit gate.
97         """
98         self.kak = kak
99 
100     def _value_equality_values_(self):
101         return self.kak
102 
103     @staticmethod
104     def from_matrix(mat: np.array, atol=1e-8) -> 'QasmTwoQubitGate':
105         """Creates a QasmTwoQubitGate from the given matrix.
106 
107         Args:
108             mat: The unitary matrix of the two qubit gate.
109             atol: Absolute error tolerance when decomposing.
110 
111         Returns:
112             A QasmTwoQubitGate implementing the matrix.
113         """
114         kak = linalg.kak_decomposition(mat, atol=atol)
115         return QasmTwoQubitGate(kak)
116 
117     def _unitary_(self):
118         return protocols.unitary(self.kak)
119 
120     def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE':
121         q0, q1 = qubits
122         x, y, z = self.kak.interaction_coefficients
123         a = x * -2 / np.pi + 0.5
124         b = y * -2 / np.pi + 0.5
125         c = z * -2 / np.pi + 0.5
126 
127         b0, b1 = self.kak.single_qubit_operations_before
128         yield QasmUGate.from_matrix(b0).on(q0)
129         yield QasmUGate.from_matrix(b1).on(q1)
130 
131         yield ops.X(q0) ** 0.5
132         yield ops.CNOT(q0, q1)
133         yield ops.X(q0) ** a
134         yield ops.Y(q1) ** b
135         yield ops.CNOT(q1, q0)
136         yield ops.X(q1) ** -0.5
137         yield ops.Z(q1) ** c
138         yield ops.CNOT(q0, q1)
139 
140         a0, a1 = self.kak.single_qubit_operations_after
141         yield QasmUGate.from_matrix(a0).on(q0)
142         yield QasmUGate.from_matrix(a1).on(q1)
143 
144     def __repr__(self) -> str:
145         return 'cirq.circuits.qasm_output.QasmTwoQubitGate({!r})'.format(self.kak)
146 
147 
148 class QasmOutput:
149     """Representation of a circuit in QASM (quantum assembly) format.
150 
151     Please note that the QASM importer is in an experimental state and
152     currently only supports a subset of the full OpenQASM spec.
153     Amongst others, classical control, arbitrary gate definitions,
154     and even some of the gates that don't have a one-to-one representation
155     in Cirq, are not yet supported.
156 
157     QASM output can be saved to a file using the save method.
158     """
159 
160     valid_id_re = re.compile(r'[a-z][a-zA-Z0-9_]*\Z')
161 
162     def __init__(
163         self,
164         operations: 'cirq.OP_TREE',
165         qubits: Tuple['cirq.Qid', ...],
166         header: str = '',
167         precision: int = 10,
168         version: str = '2.0',
169     ) -> None:
170         self.operations = tuple(ops.flatten_to_ops(operations))
171         self.qubits = qubits
172         self.header = header
173         self.measurements = tuple(
174             op for op in self.operations if isinstance(op.gate, ops.MeasurementGate)
175         )
176         meas_key_id_map, meas_comments = self._generate_measurement_ids()
177         self.meas_comments = meas_comments
178         qubit_id_map = self._generate_qubit_ids()
179         self.args = protocols.QasmArgs(
180             precision=precision,
181             version=version,
182             qubit_id_map=qubit_id_map,
183             meas_key_id_map=meas_key_id_map,
184         )
185 
186     def _generate_measurement_ids(self) -> Tuple[Dict[str, str], Dict[str, Optional[str]]]:
187         # Pick an id for the creg that will store each measurement
188         meas_key_id_map = {}  # type: Dict[str, str]
189         meas_comments = {}  # type: Dict[str, Optional[str]]
190         meas_i = 0
191         for meas in self.measurements:
192             key = protocols.measurement_key(meas)
193             if key in meas_key_id_map:
194                 continue
195             meas_id = 'm_{}'.format(key)
196             if self.is_valid_qasm_id(meas_id):
197                 meas_comments[key] = None
198             else:
199                 meas_id = 'm{}'.format(meas_i)
200                 meas_i += 1
201                 meas_comments[key] = ' '.join(key.split('\n'))
202             meas_key_id_map[key] = meas_id
203         return meas_key_id_map, meas_comments
204 
205     def _generate_qubit_ids(self) -> Dict['cirq.Qid', str]:
206         return {qubit: 'q[{}]'.format(i) for i, qubit in enumerate(self.qubits)}
207 
208     def is_valid_qasm_id(self, id_str: str) -> bool:
209         """Test if id_str is a valid id in QASM grammar."""
210         return self.valid_id_re.match(id_str) != None
211 
212     def save(self, path: Union[str, bytes, int]) -> None:
213         """Write QASM output to a file specified by path."""
214         with open(path, 'w') as f:
215 
216             def write(s: str) -> None:
217                 f.write(s)
218 
219             self._write_qasm(write)
220 
221     def __str__(self) -> str:
222         """Return QASM output as a string."""
223         output = []
224         self._write_qasm(lambda s: output.append(s))
225         return ''.join(output)
226 
227     def _write_qasm(self, output_func: Callable[[str], None]) -> None:
228         self.args.validate_version('2.0')
229 
230         # Generate nice line spacing
231         line_gap = [0]
232 
233         def output_line_gap(n):
234             line_gap[0] = max(line_gap[0], n)
235 
236         def output(text):
237             if line_gap[0] > 0:
238                 output_func('\n' * line_gap[0])
239                 line_gap[0] = 0
240             output_func(text)
241 
242         # Comment header
243         if self.header:
244             for line in self.header.split('\n'):
245                 output(('// ' + line).rstrip() + '\n')
246             output('\n')
247 
248         # Version
249         output('OPENQASM 2.0;\n')
250         output('include "qelib1.inc";\n')
251         output_line_gap(2)
252 
253         # Function definitions
254         # None yet
255 
256         # Register definitions
257         # Qubit registers
258         output('// Qubits: [{}]\n'.format(', '.join(map(str, self.qubits))))
259         if len(self.qubits) > 0:
260             output('qreg q[{}];\n'.format(len(self.qubits)))
261         # Classical registers
262         # Pick an id for the creg that will store each measurement
263         already_output_keys: Set[str] = set()
264         for meas in self.measurements:
265             key = protocols.measurement_key(meas)
266             if key in already_output_keys:
267                 continue
268             already_output_keys.add(key)
269             meas_id = self.args.meas_key_id_map[key]
270             comment = self.meas_comments[key]
271             if comment is None:
272                 output('creg {}[{}];\n'.format(meas_id, len(meas.qubits)))
273             else:
274                 output(
275                     'creg {}[{}];  // Measurement: {}\n'.format(meas_id, len(meas.qubits), comment)
276                 )
277         output_line_gap(2)
278 
279         # Operations
280         self._write_operations(self.operations, output, output_line_gap)
281 
282     def _write_operations(
283         self,
284         op_tree: 'cirq.OP_TREE',
285         output: Callable[[str], None],
286         output_line_gap: Callable[[int], None],
287     ) -> None:
288         def keep(op: 'cirq.Operation') -> bool:
289             return protocols.qasm(op, args=self.args, default=None) is not None
290 
291         def fallback(op):
292             if len(op.qubits) not in [1, 2]:
293                 return NotImplemented
294 
295             mat = protocols.unitary(op, None)
296             if mat is None:
297                 return NotImplemented
298 
299             if len(op.qubits) == 1:
300                 return QasmUGate.from_matrix(mat).on(*op.qubits)
301             return QasmTwoQubitGate.from_matrix(mat).on(*op.qubits)
302 
303         def on_stuck(bad_op):
304             return ValueError('Cannot output operation as QASM: {!r}'.format(bad_op))
305 
306         for main_op in ops.flatten_op_tree(op_tree):
307             decomposed = protocols.decompose(
308                 main_op, keep=keep, fallback_decomposer=fallback, on_stuck_raise=on_stuck
309             )
310 
311             should_annotate = decomposed != [main_op]
312             if should_annotate:
313                 output_line_gap(1)
314                 if isinstance(main_op, ops.GateOperation):
315                     x = str(main_op.gate).replace('\n', '\n //')
316                     output('// Gate: {!s}\n'.format(x))
317                 else:
318                     x = str(main_op).replace('\n', '\n //')
319                     output('// Operation: {!s}\n'.format(x))
320 
321             for decomposed_op in decomposed:
322                 output(protocols.qasm(decomposed_op, args=self.args))
323 
324             if should_annotate:
325                 output_line_gap(1)
326
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/cirq/circuits/qasm_output.py b/cirq/circuits/qasm_output.py
--- a/cirq/circuits/qasm_output.py
+++ b/cirq/circuits/qasm_output.py
@@ -308,7 +308,9 @@
                 main_op, keep=keep, fallback_decomposer=fallback, on_stuck_raise=on_stuck
             )
 
-            should_annotate = decomposed != [main_op]
+            qasms = [protocols.qasm(op, args=self.args) for op in decomposed]
+
+            should_annotate = decomposed != [main_op] or qasms[0].count('\n') > 1
             if should_annotate:
                 output_line_gap(1)
                 if isinstance(main_op, ops.GateOperation):
@@ -318,8 +320,8 @@
                     x = str(main_op).replace('\n', '\n //')
                     output('// Operation: {!s}\n'.format(x))
 
-            for decomposed_op in decomposed:
-                output(protocols.qasm(decomposed_op, args=self.args))
+            for qasm in qasms:
+                output(qasm)
 
             if should_annotate:
                 output_line_gap(1)

{"golden_diff": "diff --git a/cirq/circuits/qasm_output.py b/cirq/circuits/qasm_output.py\n--- a/cirq/circuits/qasm_output.py\n+++ b/cirq/circuits/qasm_output.py\n@@ -308,7 +308,9 @@\n                 main_op, keep=keep, fallback_decomposer=fallback, on_stuck_raise=on_stuck\n             )\n \n-            should_annotate = decomposed != [main_op]\n+            qasms = [protocols.qasm(op, args=self.args) for op in decomposed]\n+\n+            should_annotate = decomposed != [main_op] or qasms[0].count('\\n') > 1\n             if should_annotate:\n                 output_line_gap(1)\n                 if isinstance(main_op, ops.GateOperation):\n@@ -318,8 +320,8 @@\n                     x = str(main_op).replace('\\n', '\\n //')\n                     output('// Operation: {!s}\\n'.format(x))\n \n-            for decomposed_op in decomposed:\n-                output(protocols.qasm(decomposed_op, args=self.args))\n+            for qasm in qasms:\n+                output(qasm)\n \n             if should_annotate:\n                 output_line_gap(1)\n", "issue": "For QASM of decomposed circuits add comment\nI noticed that if I export CCZ into qasm, I get the h, ccx, h operations with no leading comment saying that they correspond to a CCZ. I'm pretty sure this used to happen.\n", "before_files": [{"content": "# Copyright 2018 The Cirq Developers\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Utility classes for representing QASM.\"\"\"\n\nfrom typing import Callable, Dict, Optional, Sequence, Set, Tuple, Union, TYPE_CHECKING\n\nimport re\nimport numpy as np\n\nfrom cirq import ops, linalg, protocols, value\n\nif TYPE_CHECKING:\n    import cirq\n\n\n@value.value_equality(approximate=True)\nclass QasmUGate(ops.SingleQubitGate):\n    def __init__(self, theta, phi, lmda) -> None:\n        \"\"\"A QASM gate representing any single qubit unitary with a series of\n        three rotations, Z, Y, and Z.\n\n        The angles are normalized to the range [0, 2) half_turns.\n\n        Args:\n            theta: Half turns to rotate about Y (applied second).\n            phi: Half turns to rotate about Z (applied last).\n            lmda: Half turns to rotate about Z (applied first).\n        \"\"\"\n        self.lmda = lmda % 2\n        self.theta = theta % 2\n        self.phi = phi % 2\n\n    @staticmethod\n    def from_matrix(mat: np.array) -> 'QasmUGate':\n        pre_phase, rotation, post_phase = linalg.deconstruct_single_qubit_matrix_into_angles(mat)\n        return QasmUGate(\n            rotation / np.pi,\n            post_phase / np.pi,\n            pre_phase / np.pi,\n        )\n\n    def _has_unitary_(self):\n        return True\n\n    def _qasm_(self, qubits: Tuple['cirq.Qid', ...], args: 'cirq.QasmArgs') -> str:\n        args.validate_version('2.0')\n        return args.format(\n            'u3({0:half_turns},{1:half_turns},{2:half_turns}) {3};\\n',\n            self.theta,\n            self.phi,\n            self.lmda,\n            qubits[0],\n        )\n\n    def __repr__(self) -> str:\n        return (\n            f'cirq.circuits.qasm_output.QasmUGate('\n            f'theta={self.theta!r}, '\n            f'phi={self.phi!r}, '\n            f'lmda={self.lmda})'\n        )\n\n    def _decompose_(self, qubits):\n        q = qubits[0]\n        return [\n            ops.rz(self.lmda * np.pi).on(q),\n            ops.ry(self.theta * np.pi).on(q),\n            ops.rz(self.phi * np.pi).on(q),\n        ]\n\n    def _value_equality_values_(self):\n        return self.lmda, self.theta, self.phi\n\n\n@value.value_equality\nclass QasmTwoQubitGate(ops.TwoQubitGate):\n    def __init__(self, kak: linalg.KakDecomposition) -> None:\n        \"\"\"A two qubit gate represented in QASM by the KAK decomposition.\n\n        All angles are in half turns.  Assumes a canonicalized KAK\n        decomposition.\n\n        Args:\n            kak: KAK decomposition of the two-qubit gate.\n        \"\"\"\n        self.kak = kak\n\n    def _value_equality_values_(self):\n        return self.kak\n\n    @staticmethod\n    def from_matrix(mat: np.array, atol=1e-8) -> 'QasmTwoQubitGate':\n        \"\"\"Creates a QasmTwoQubitGate from the given matrix.\n\n        Args:\n            mat: The unitary matrix of the two qubit gate.\n            atol: Absolute error tolerance when decomposing.\n\n        Returns:\n            A QasmTwoQubitGate implementing the matrix.\n        \"\"\"\n        kak = linalg.kak_decomposition(mat, atol=atol)\n        return QasmTwoQubitGate(kak)\n\n    def _unitary_(self):\n        return protocols.unitary(self.kak)\n\n    def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE':\n        q0, q1 = qubits\n        x, y, z = self.kak.interaction_coefficients\n        a = x * -2 / np.pi + 0.5\n        b = y * -2 / np.pi + 0.5\n        c = z * -2 / np.pi + 0.5\n\n        b0, b1 = self.kak.single_qubit_operations_before\n        yield QasmUGate.from_matrix(b0).on(q0)\n        yield QasmUGate.from_matrix(b1).on(q1)\n\n        yield ops.X(q0) ** 0.5\n        yield ops.CNOT(q0, q1)\n        yield ops.X(q0) ** a\n        yield ops.Y(q1) ** b\n        yield ops.CNOT(q1, q0)\n        yield ops.X(q1) ** -0.5\n        yield ops.Z(q1) ** c\n        yield ops.CNOT(q0, q1)\n\n        a0, a1 = self.kak.single_qubit_operations_after\n        yield QasmUGate.from_matrix(a0).on(q0)\n        yield QasmUGate.from_matrix(a1).on(q1)\n\n    def __repr__(self) -> str:\n        return 'cirq.circuits.qasm_output.QasmTwoQubitGate({!r})'.format(self.kak)\n\n\nclass QasmOutput:\n    \"\"\"Representation of a circuit in QASM (quantum assembly) format.\n\n    Please note that the QASM importer is in an experimental state and\n    currently only supports a subset of the full OpenQASM spec.\n    Amongst others, classical control, arbitrary gate definitions,\n    and even some of the gates that don't have a one-to-one representation\n    in Cirq, are not yet supported.\n\n    QASM output can be saved to a file using the save method.\n    \"\"\"\n\n    valid_id_re = re.compile(r'[a-z][a-zA-Z0-9_]*\\Z')\n\n    def __init__(\n        self,\n        operations: 'cirq.OP_TREE',\n        qubits: Tuple['cirq.Qid', ...],\n        header: str = '',\n        precision: int = 10,\n        version: str = '2.0',\n    ) -> None:\n        self.operations = tuple(ops.flatten_to_ops(operations))\n        self.qubits = qubits\n        self.header = header\n        self.measurements = tuple(\n            op for op in self.operations if isinstance(op.gate, ops.MeasurementGate)\n        )\n        meas_key_id_map, meas_comments = self._generate_measurement_ids()\n        self.meas_comments = meas_comments\n        qubit_id_map = self._generate_qubit_ids()\n        self.args = protocols.QasmArgs(\n            precision=precision,\n            version=version,\n            qubit_id_map=qubit_id_map,\n            meas_key_id_map=meas_key_id_map,\n        )\n\n    def _generate_measurement_ids(self) -> Tuple[Dict[str, str], Dict[str, Optional[str]]]:\n        # Pick an id for the creg that will store each measurement\n        meas_key_id_map = {}  # type: Dict[str, str]\n        meas_comments = {}  # type: Dict[str, Optional[str]]\n        meas_i = 0\n        for meas in self.measurements:\n            key = protocols.measurement_key(meas)\n            if key in meas_key_id_map:\n                continue\n            meas_id = 'm_{}'.format(key)\n            if self.is_valid_qasm_id(meas_id):\n                meas_comments[key] = None\n            else:\n                meas_id = 'm{}'.format(meas_i)\n                meas_i += 1\n                meas_comments[key] = ' '.join(key.split('\\n'))\n            meas_key_id_map[key] = meas_id\n        return meas_key_id_map, meas_comments\n\n    def _generate_qubit_ids(self) -> Dict['cirq.Qid', str]:\n        return {qubit: 'q[{}]'.format(i) for i, qubit in enumerate(self.qubits)}\n\n    def is_valid_qasm_id(self, id_str: str) -> bool:\n        \"\"\"Test if id_str is a valid id in QASM grammar.\"\"\"\n        return self.valid_id_re.match(id_str) != None\n\n    def save(self, path: Union[str, bytes, int]) -> None:\n        \"\"\"Write QASM output to a file specified by path.\"\"\"\n        with open(path, 'w') as f:\n\n            def write(s: str) -> None:\n                f.write(s)\n\n            self._write_qasm(write)\n\n    def __str__(self) -> str:\n        \"\"\"Return QASM output as a string.\"\"\"\n        output = []\n        self._write_qasm(lambda s: output.append(s))\n        return ''.join(output)\n\n    def _write_qasm(self, output_func: Callable[[str], None]) -> None:\n        self.args.validate_version('2.0')\n\n        # Generate nice line spacing\n        line_gap = [0]\n\n        def output_line_gap(n):\n            line_gap[0] = max(line_gap[0], n)\n\n        def output(text):\n            if line_gap[0] > 0:\n                output_func('\\n' * line_gap[0])\n                line_gap[0] = 0\n            output_func(text)\n\n        # Comment header\n        if self.header:\n            for line in self.header.split('\\n'):\n                output(('// ' + line).rstrip() + '\\n')\n            output('\\n')\n\n        # Version\n        output('OPENQASM 2.0;\\n')\n        output('include \"qelib1.inc\";\\n')\n        output_line_gap(2)\n\n        # Function definitions\n        # None yet\n\n        # Register definitions\n        # Qubit registers\n        output('// Qubits: [{}]\\n'.format(', '.join(map(str, self.qubits))))\n        if len(self.qubits) > 0:\n            output('qreg q[{}];\\n'.format(len(self.qubits)))\n        # Classical registers\n        # Pick an id for the creg that will store each measurement\n        already_output_keys: Set[str] = set()\n        for meas in self.measurements:\n            key = protocols.measurement_key(meas)\n            if key in already_output_keys:\n                continue\n            already_output_keys.add(key)\n            meas_id = self.args.meas_key_id_map[key]\n            comment = self.meas_comments[key]\n            if comment is None:\n                output('creg {}[{}];\\n'.format(meas_id, len(meas.qubits)))\n            else:\n                output(\n                    'creg {}[{}];  // Measurement: {}\\n'.format(meas_id, len(meas.qubits), comment)\n                )\n        output_line_gap(2)\n\n        # Operations\n        self._write_operations(self.operations, output, output_line_gap)\n\n    def _write_operations(\n        self,\n        op_tree: 'cirq.OP_TREE',\n        output: Callable[[str], None],\n        output_line_gap: Callable[[int], None],\n    ) -> None:\n        def keep(op: 'cirq.Operation') -> bool:\n            return protocols.qasm(op, args=self.args, default=None) is not None\n\n        def fallback(op):\n            if len(op.qubits) not in [1, 2]:\n                return NotImplemented\n\n            mat = protocols.unitary(op, None)\n            if mat is None:\n                return NotImplemented\n\n            if len(op.qubits) == 1:\n                return QasmUGate.from_matrix(mat).on(*op.qubits)\n            return QasmTwoQubitGate.from_matrix(mat).on(*op.qubits)\n\n        def on_stuck(bad_op):\n            return ValueError('Cannot output operation as QASM: {!r}'.format(bad_op))\n\n        for main_op in ops.flatten_op_tree(op_tree):\n            decomposed = protocols.decompose(\n                main_op, keep=keep, fallback_decomposer=fallback, on_stuck_raise=on_stuck\n            )\n\n            should_annotate = decomposed != [main_op]\n            if should_annotate:\n                output_line_gap(1)\n                if isinstance(main_op, ops.GateOperation):\n                    x = str(main_op.gate).replace('\\n', '\\n //')\n                    output('// Gate: {!s}\\n'.format(x))\n                else:\n                    x = str(main_op).replace('\\n', '\\n //')\n                    output('// Operation: {!s}\\n'.format(x))\n\n            for decomposed_op in decomposed:\n                output(protocols.qasm(decomposed_op, args=self.args))\n\n            if should_annotate:\n                output_line_gap(1)\n", "path": "cirq/circuits/qasm_output.py"}], "after_files": [{"content": "# Copyright 2018 The Cirq Developers\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Utility classes for representing QASM.\"\"\"\n\nfrom typing import Callable, Dict, Optional, Sequence, Set, Tuple, Union, TYPE_CHECKING\n\nimport re\nimport numpy as np\n\nfrom cirq import ops, linalg, protocols, value\n\nif TYPE_CHECKING:\n    import cirq\n\n\n@value.value_equality(approximate=True)\nclass QasmUGate(ops.SingleQubitGate):\n    def __init__(self, theta, phi, lmda) -> None:\n        \"\"\"A QASM gate representing any single qubit unitary with a series of\n        three rotations, Z, Y, and Z.\n\n        The angles are normalized to the range [0, 2) half_turns.\n\n        Args:\n            theta: Half turns to rotate about Y (applied second).\n            phi: Half turns to rotate about Z (applied last).\n            lmda: Half turns to rotate about Z (applied first).\n        \"\"\"\n        self.lmda = lmda % 2\n        self.theta = theta % 2\n        self.phi = phi % 2\n\n    @staticmethod\n    def from_matrix(mat: np.array) -> 'QasmUGate':\n        pre_phase, rotation, post_phase = linalg.deconstruct_single_qubit_matrix_into_angles(mat)\n        return QasmUGate(\n            rotation / np.pi,\n            post_phase / np.pi,\n            pre_phase / np.pi,\n        )\n\n    def _has_unitary_(self):\n        return True\n\n    def _qasm_(self, qubits: Tuple['cirq.Qid', ...], args: 'cirq.QasmArgs') -> str:\n        args.validate_version('2.0')\n        return args.format(\n            'u3({0:half_turns},{1:half_turns},{2:half_turns}) {3};\\n',\n            self.theta,\n            self.phi,\n            self.lmda,\n            qubits[0],\n        )\n\n    def __repr__(self) -> str:\n        return (\n            f'cirq.circuits.qasm_output.QasmUGate('\n            f'theta={self.theta!r}, '\n            f'phi={self.phi!r}, '\n            f'lmda={self.lmda})'\n        )\n\n    def _decompose_(self, qubits):\n        q = qubits[0]\n        return [\n            ops.rz(self.lmda * np.pi).on(q),\n            ops.ry(self.theta * np.pi).on(q),\n            ops.rz(self.phi * np.pi).on(q),\n        ]\n\n    def _value_equality_values_(self):\n        return self.lmda, self.theta, self.phi\n\n\n@value.value_equality\nclass QasmTwoQubitGate(ops.TwoQubitGate):\n    def __init__(self, kak: linalg.KakDecomposition) -> None:\n        \"\"\"A two qubit gate represented in QASM by the KAK decomposition.\n\n        All angles are in half turns.  Assumes a canonicalized KAK\n        decomposition.\n\n        Args:\n            kak: KAK decomposition of the two-qubit gate.\n        \"\"\"\n        self.kak = kak\n\n    def _value_equality_values_(self):\n        return self.kak\n\n    @staticmethod\n    def from_matrix(mat: np.array, atol=1e-8) -> 'QasmTwoQubitGate':\n        \"\"\"Creates a QasmTwoQubitGate from the given matrix.\n\n        Args:\n            mat: The unitary matrix of the two qubit gate.\n            atol: Absolute error tolerance when decomposing.\n\n        Returns:\n            A QasmTwoQubitGate implementing the matrix.\n        \"\"\"\n        kak = linalg.kak_decomposition(mat, atol=atol)\n        return QasmTwoQubitGate(kak)\n\n    def _unitary_(self):\n        return protocols.unitary(self.kak)\n\n    def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE':\n        q0, q1 = qubits\n        x, y, z = self.kak.interaction_coefficients\n        a = x * -2 / np.pi + 0.5\n        b = y * -2 / np.pi + 0.5\n        c = z * -2 / np.pi + 0.5\n\n        b0, b1 = self.kak.single_qubit_operations_before\n        yield QasmUGate.from_matrix(b0).on(q0)\n        yield QasmUGate.from_matrix(b1).on(q1)\n\n        yield ops.X(q0) ** 0.5\n        yield ops.CNOT(q0, q1)\n        yield ops.X(q0) ** a\n        yield ops.Y(q1) ** b\n        yield ops.CNOT(q1, q0)\n        yield ops.X(q1) ** -0.5\n        yield ops.Z(q1) ** c\n        yield ops.CNOT(q0, q1)\n\n        a0, a1 = self.kak.single_qubit_operations_after\n        yield QasmUGate.from_matrix(a0).on(q0)\n        yield QasmUGate.from_matrix(a1).on(q1)\n\n    def __repr__(self) -> str:\n        return 'cirq.circuits.qasm_output.QasmTwoQubitGate({!r})'.format(self.kak)\n\n\nclass QasmOutput:\n    \"\"\"Representation of a circuit in QASM (quantum assembly) format.\n\n    Please note that the QASM importer is in an experimental state and\n    currently only supports a subset of the full OpenQASM spec.\n    Amongst others, classical control, arbitrary gate definitions,\n    and even some of the gates that don't have a one-to-one representation\n    in Cirq, are not yet supported.\n\n    QASM output can be saved to a file using the save method.\n    \"\"\"\n\n    valid_id_re = re.compile(r'[a-z][a-zA-Z0-9_]*\\Z')\n\n    def __init__(\n        self,\n        operations: 'cirq.OP_TREE',\n        qubits: Tuple['cirq.Qid', ...],\n        header: str = '',\n        precision: int = 10,\n        version: str = '2.0',\n    ) -> None:\n        self.operations = tuple(ops.flatten_to_ops(operations))\n        self.qubits = qubits\n        self.header = header\n        self.measurements = tuple(\n            op for op in self.operations if isinstance(op.gate, ops.MeasurementGate)\n        )\n        meas_key_id_map, meas_comments = self._generate_measurement_ids()\n        self.meas_comments = meas_comments\n        qubit_id_map = self._generate_qubit_ids()\n        self.args = protocols.QasmArgs(\n            precision=precision,\n            version=version,\n            qubit_id_map=qubit_id_map,\n            meas_key_id_map=meas_key_id_map,\n        )\n\n    def _generate_measurement_ids(self) -> Tuple[Dict[str, str], Dict[str, Optional[str]]]:\n        # Pick an id for the creg that will store each measurement\n        meas_key_id_map = {}  # type: Dict[str, str]\n        meas_comments = {}  # type: Dict[str, Optional[str]]\n        meas_i = 0\n        for meas in self.measurements:\n            key = protocols.measurement_key(meas)\n            if key in meas_key_id_map:\n                continue\n            meas_id = 'm_{}'.format(key)\n            if self.is_valid_qasm_id(meas_id):\n                meas_comments[key] = None\n            else:\n                meas_id = 'm{}'.format(meas_i)\n                meas_i += 1\n                meas_comments[key] = ' '.join(key.split('\\n'))\n            meas_key_id_map[key] = meas_id\n        return meas_key_id_map, meas_comments\n\n    def _generate_qubit_ids(self) -> Dict['cirq.Qid', str]:\n        return {qubit: 'q[{}]'.format(i) for i, qubit in enumerate(self.qubits)}\n\n    def is_valid_qasm_id(self, id_str: str) -> bool:\n        \"\"\"Test if id_str is a valid id in QASM grammar.\"\"\"\n        return self.valid_id_re.match(id_str) != None\n\n    def save(self, path: Union[str, bytes, int]) -> None:\n        \"\"\"Write QASM output to a file specified by path.\"\"\"\n        with open(path, 'w') as f:\n\n            def write(s: str) -> None:\n                f.write(s)\n\n            self._write_qasm(write)\n\n    def __str__(self) -> str:\n        \"\"\"Return QASM output as a string.\"\"\"\n        output = []\n        self._write_qasm(lambda s: output.append(s))\n        return ''.join(output)\n\n    def _write_qasm(self, output_func: Callable[[str], None]) -> None:\n        self.args.validate_version('2.0')\n\n        # Generate nice line spacing\n        line_gap = [0]\n\n        def output_line_gap(n):\n            line_gap[0] = max(line_gap[0], n)\n\n        def output(text):\n            if line_gap[0] > 0:\n                output_func('\\n' * line_gap[0])\n                line_gap[0] = 0\n            output_func(text)\n\n        # Comment header\n        if self.header:\n            for line in self.header.split('\\n'):\n                output(('// ' + line).rstrip() + '\\n')\n            output('\\n')\n\n        # Version\n        output('OPENQASM 2.0;\\n')\n        output('include \"qelib1.inc\";\\n')\n        output_line_gap(2)\n\n        # Function definitions\n        # None yet\n\n        # Register definitions\n        # Qubit registers\n        output('// Qubits: [{}]\\n'.format(', '.join(map(str, self.qubits))))\n        if len(self.qubits) > 0:\n            output('qreg q[{}];\\n'.format(len(self.qubits)))\n        # Classical registers\n        # Pick an id for the creg that will store each measurement\n        already_output_keys: Set[str] = set()\n        for meas in self.measurements:\n            key = protocols.measurement_key(meas)\n            if key in already_output_keys:\n                continue\n            already_output_keys.add(key)\n            meas_id = self.args.meas_key_id_map[key]\n            comment = self.meas_comments[key]\n            if comment is None:\n                output('creg {}[{}];\\n'.format(meas_id, len(meas.qubits)))\n            else:\n                output(\n                    'creg {}[{}];  // Measurement: {}\\n'.format(meas_id, len(meas.qubits), comment)\n                )\n        output_line_gap(2)\n\n        # Operations\n        self._write_operations(self.operations, output, output_line_gap)\n\n    def _write_operations(\n        self,\n        op_tree: 'cirq.OP_TREE',\n        output: Callable[[str], None],\n        output_line_gap: Callable[[int], None],\n    ) -> None:\n        def keep(op: 'cirq.Operation') -> bool:\n            return protocols.qasm(op, args=self.args, default=None) is not None\n\n        def fallback(op):\n            if len(op.qubits) not in [1, 2]:\n                return NotImplemented\n\n            mat = protocols.unitary(op, None)\n            if mat is None:\n                return NotImplemented\n\n            if len(op.qubits) == 1:\n                return QasmUGate.from_matrix(mat).on(*op.qubits)\n            return QasmTwoQubitGate.from_matrix(mat).on(*op.qubits)\n\n        def on_stuck(bad_op):\n            return ValueError('Cannot output operation as QASM: {!r}'.format(bad_op))\n\n        for main_op in ops.flatten_op_tree(op_tree):\n            decomposed = protocols.decompose(\n                main_op, keep=keep, fallback_decomposer=fallback, on_stuck_raise=on_stuck\n            )\n\n            qasms = [protocols.qasm(op, args=self.args) for op in decomposed]\n\n            should_annotate = decomposed != [main_op] or qasms[0].count('\\n') > 1\n            if should_annotate:\n                output_line_gap(1)\n                if isinstance(main_op, ops.GateOperation):\n                    x = str(main_op.gate).replace('\\n', '\\n //')\n                    output('// Gate: {!s}\\n'.format(x))\n                else:\n                    x = str(main_op).replace('\\n', '\\n //')\n                    output('// Operation: {!s}\\n'.format(x))\n\n            for qasm in qasms:\n                output(qasm)\n\n            if should_annotate:\n                output_line_gap(1)\n", "path": "cirq/circuits/qasm_output.py"}]}