We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Should Circuit#append be chainable?
It seems like a common pattern to want to do
circuit = Circuit().append(o1).append([o2, o3])
?

--- 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/circuit.py`
Content:
```
1 # Copyright 2018 Google LLC
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 """The circuit data structure for the sequenced phase."""
16 
17 import itertools
18 
19 from typing import Iterable, List, Optional, Set
20 
21 from cirq import ops
22 from cirq.circuits.insert_strategy import InsertStrategy
23 from cirq.circuits.moment import Moment
24 from cirq.ops import QubitId
25 
26 
27 class Circuit(object):
28     """A mutable list of groups of operations to apply to some qubits."""
29 
30     def __init__(self, moments: Iterable[Moment] = ()):
31         """Initializes a circuit.
32 
33         Args:
34             moments: The initial list of moments defining the circuit.
35         """
36         self.moments = list(moments)
37 
38     def __eq__(self, other):
39         if not isinstance(other, type(self)):
40             return NotImplemented
41         return self.moments == other.moments
42 
43     def __ne__(self, other):
44         return not self == other
45 
46     __hash__ = None
47 
48     def _first_moment_operating_on(self, qubits: Iterable[ops.QubitId],
49                                    indices: Iterable[int]) -> Optional[int]:
50         qubits = frozenset(qubits)
51         for m in indices:
52             if self._has_op_at(m, qubits):
53                 return m
54         return None
55 
56     def next_moment_operating_on(self,
57                                  qubits: Iterable[ops.QubitId],
58                                  start_moment_index: int = 0,
59                                  max_distance: int = None) -> Optional[int]:
60         """Finds the index of the next moment that touches the given qubits.
61 
62         Args:
63             qubits: We're looking for operations affecting any of these qubits.
64             start_moment_index: The starting point of the search.
65             max_distance: The number of moments (starting from the start index
66                 and moving forward) to check. Defaults to no limit.
67 
68         Returns:
69             None if there is no matching moment, otherwise the index of the
70             earliest matching moment.
71 
72         Raises:
73           ValueError: negative max_distance.
74         """
75         if max_distance is None:
76             max_distance = float('inf')
77         elif max_distance < 0:
78             raise ValueError('Negative max_distance: {}'.format(max_distance))
79 
80         # Don't bother searching indices past the end of the list.
81         max_distance = int(
82             min(max_distance, len(self.moments) - start_moment_index))
83 
84         return self._first_moment_operating_on(
85             qubits,
86             range(start_moment_index, start_moment_index + max_distance))
87 
88     def prev_moment_operating_on(
89             self,
90             qubits: List[ops.QubitId],
91             end_moment_index: Optional[int] = None,
92             max_distance: Optional[int] = None) -> Optional[int]:
93         """Finds the index of the next moment that touches the given qubits.
94 
95         Args:
96             qubits: We're looking for operations affecting any of these qubits.
97             end_moment_index: The moment index just after the starting point of
98                 the reverse search. Defaults to the length of the list of
99                 moments.
100             max_distance: The number of moments (starting just before from the
101                 end index and moving backward) to check. Defaults to no limit.
102 
103         Returns:
104             None if there is no matching moment, otherwise the index of the
105             latest matching moment.
106 
107         Raises:
108             ValueError: negative max_distance.
109         """
110         if max_distance is None:
111             max_distance = float('inf')
112         elif max_distance < 0:
113             raise ValueError('Negative max_distance: {}'.format(max_distance))
114 
115         if end_moment_index is None:
116             end_moment_index = len(self.moments)
117 
118         # Don't bother searching indices past the start of the list.
119         max_distance = min(end_moment_index, max_distance)
120 
121         # Don't bother searching indices past the end of the list.
122         if end_moment_index > len(self.moments):
123             d = end_moment_index - len(self.moments)
124             end_moment_index -= d
125             max_distance -= d
126         if max_distance <= 0:
127             return None
128 
129         return self._first_moment_operating_on(qubits,
130                                                (end_moment_index - k - 1
131                                                 for k in range(max_distance)))
132 
133     def operation_at(self, qubit: ops.QubitId,
134                      moment_index: int) -> Optional[ops.Operation]:
135         """Finds the operation on a qubit within a moment, if any.
136 
137         Args:
138             qubit: The qubit to check for an operation on.
139             moment_index: The index of the moment to check for an operation
140                 within. Allowed to be beyond the end of the circuit.
141 
142         Returns:
143             None if there is no operation on the qubit at the given moment, or
144             else the operation.
145         """
146         if not 0 <= moment_index < len(self.moments):
147             return None
148         for op in self.moments[moment_index].operations:
149             if qubit in op.qubits:
150                 return op
151         return None
152 
153     def clear_operations_touching(self, qubits: Iterable[ops.QubitId],
154                                   moment_indices: Iterable[int]):
155         """Clears operations that are touching given qubits at given moments.
156 
157         Args:
158             qubits: The qubits to check for operations on.
159             moment_indices: The indices of moments to check for operations
160                 within.
161         """
162         qubits = frozenset(qubits)
163         for k in moment_indices:
164             if 0 <= k < len(self.moments):
165                 self.moments[k] = self.moments[k].without_operations_touching(
166                     qubits)
167 
168     def _pick_or_create_inserted_op_moment_index(
169             self, splitter_index: int, op: ops.Operation,
170             strategy: InsertStrategy) -> int:
171         """Determines and prepares where an insertion will occur.
172 
173         Args:
174             splitter_index: The index to insert at.
175             op: The operation that will be inserted.
176             strategy: The insertion strategy.
177 
178         Returns:
179             The index of the (possibly new) moment where the insertion should
180                 occur.
181 
182         Raises:
183             ValueError: Unrecognized append strategy.
184         """
185 
186         if (strategy is InsertStrategy.NEW or
187                 strategy is InsertStrategy.NEW_THEN_INLINE):
188             self.moments.insert(splitter_index, Moment())
189             return splitter_index
190 
191         if strategy is InsertStrategy.INLINE:
192             if (not self._has_op_at(splitter_index - 1, op.qubits) and
193                     0 <= splitter_index - 1 < len(self.moments)):
194                 return splitter_index - 1
195 
196             return self._pick_or_create_inserted_op_moment_index(
197                 splitter_index, op, InsertStrategy.NEW)
198 
199         if strategy is InsertStrategy.EARLIEST:
200             if not self._has_op_at(splitter_index, op.qubits):
201                 p = self.prev_moment_operating_on(op.qubits, splitter_index)
202                 return p + 1 if p is not None else 0
203 
204             return self._pick_or_create_inserted_op_moment_index(
205                 splitter_index, op, InsertStrategy.INLINE)
206 
207         raise ValueError('Unrecognized append strategy: {}'.format(strategy))
208 
209     def _has_op_at(self, moment_index, qubits):
210         return (0 <= moment_index < len(self.moments) and
211                 self.moments[moment_index].operates_on(qubits))
212 
213     def insert(
214             self,
215             index: int,
216             operation_tree: ops.OP_TREE,
217             strategy: InsertStrategy = InsertStrategy.NEW_THEN_INLINE) -> int:
218         """Inserts operations into the middle of the circuit.
219 
220         Args:
221             index: The index to insert all of the operations at.
222             operation_tree: An operation or tree of operations.
223             strategy: How to pick/create the moment to put operations into.
224 
225         Returns:
226             The insertion index that will place operations just after the
227             operations that were inserted by this method.
228 
229         Raises:
230             IndexError: Bad insertion index.
231             ValueError: Bad insertion strategy.
232         """
233         if not 0 <= index <= len(self.moments):
234             raise IndexError('Insert index out of range: {}'.format(index))
235 
236         k = index
237         for op in ops.flatten_op_tree(operation_tree):
238             p = self._pick_or_create_inserted_op_moment_index(k, op, strategy)
239             while p >= len(self.moments):
240                 self.moments.append(Moment())
241             self.moments[p] = self.moments[p].with_operation(op)
242             k = max(k, p + 1)
243             if strategy is InsertStrategy.NEW_THEN_INLINE:
244                 strategy = InsertStrategy.INLINE
245         return k
246 
247     def append(
248             self,
249             operation_tree: ops.OP_TREE,
250             strategy: InsertStrategy = InsertStrategy.NEW_THEN_INLINE):
251         """Appends operations onto the end of the circuit.
252 
253         Args:
254             operation_tree: An operation or tree of operations.
255             strategy: How to pick/create the moment to put operations into.
256         """
257         self.insert(len(self.moments), operation_tree, strategy)
258 
259     def qubits(self) -> Set[QubitId]:
260         """Returns the qubits acted upon by Operations in this circuit."""
261         return frozenset(q for m in self.moments for q in m.qubits)
262 
263     def __repr__(self):
264         moment_lines = ('\n    ' + repr(moment) for moment in self.moments)
265         return 'Circuit([{}])'.format(','.join(moment_lines))
266 
267     def __str__(self):
268         moment_lines = ('\n    ' + str(moment) for moment in self.moments)
269         return 'Circuit [{}\n]'.format(''.join(moment_lines))
270
```
--- 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/circuit.py b/cirq/circuits/circuit.py
--- a/cirq/circuits/circuit.py
+++ b/cirq/circuits/circuit.py
@@ -14,8 +14,6 @@
 
 """The circuit data structure for the sequenced phase."""
 
-import itertools
-
 from typing import Iterable, List, Optional, Set
 
 from cirq import ops
@@ -35,6 +33,23 @@
         """
         self.moments = list(moments)
 
+    @staticmethod
+    def from_ops(*operations: ops.OP_TREE,
+                 strategy: InsertStrategy = InsertStrategy.NEW_THEN_INLINE
+                 ) -> 'Circuit':
+        """Creates an empty circuit and appends the given operations.
+
+        Args:
+            operations: The operations to append to the new circuit.
+            strategy: How to append the operations.
+
+        Returns:
+            The constructed circuit containing the operations.
+        """
+        result = Circuit()
+        result.append(operations, strategy)
+        return result
+
     def __eq__(self, other):
         if not isinstance(other, type(self)):
             return NotImplemented

{"golden_diff": "diff --git a/cirq/circuits/circuit.py b/cirq/circuits/circuit.py\n--- a/cirq/circuits/circuit.py\n+++ b/cirq/circuits/circuit.py\n@@ -14,8 +14,6 @@\n \n \"\"\"The circuit data structure for the sequenced phase.\"\"\"\n \n-import itertools\n-\n from typing import Iterable, List, Optional, Set\n \n from cirq import ops\n@@ -35,6 +33,23 @@\n         \"\"\"\n         self.moments = list(moments)\n \n+    @staticmethod\n+    def from_ops(*operations: ops.OP_TREE,\n+                 strategy: InsertStrategy = InsertStrategy.NEW_THEN_INLINE\n+                 ) -> 'Circuit':\n+        \"\"\"Creates an empty circuit and appends the given operations.\n+\n+        Args:\n+            operations: The operations to append to the new circuit.\n+            strategy: How to append the operations.\n+\n+        Returns:\n+            The constructed circuit containing the operations.\n+        \"\"\"\n+        result = Circuit()\n+        result.append(operations, strategy)\n+        return result\n+\n     def __eq__(self, other):\n         if not isinstance(other, type(self)):\n             return NotImplemented\n", "issue": "Should Circuit#append be chainable?\nIt seems like a common pattern to want to do\r\ncircuit = Circuit().append(o1).append([o2, o3])\r\n?\n", "before_files": [{"content": "# Copyright 2018 Google LLC\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\"\"\"The circuit data structure for the sequenced phase.\"\"\"\n\nimport itertools\n\nfrom typing import Iterable, List, Optional, Set\n\nfrom cirq import ops\nfrom cirq.circuits.insert_strategy import InsertStrategy\nfrom cirq.circuits.moment import Moment\nfrom cirq.ops import QubitId\n\n\nclass Circuit(object):\n    \"\"\"A mutable list of groups of operations to apply to some qubits.\"\"\"\n\n    def __init__(self, moments: Iterable[Moment] = ()):\n        \"\"\"Initializes a circuit.\n\n        Args:\n            moments: The initial list of moments defining the circuit.\n        \"\"\"\n        self.moments = list(moments)\n\n    def __eq__(self, other):\n        if not isinstance(other, type(self)):\n            return NotImplemented\n        return self.moments == other.moments\n\n    def __ne__(self, other):\n        return not self == other\n\n    __hash__ = None\n\n    def _first_moment_operating_on(self, qubits: Iterable[ops.QubitId],\n                                   indices: Iterable[int]) -> Optional[int]:\n        qubits = frozenset(qubits)\n        for m in indices:\n            if self._has_op_at(m, qubits):\n                return m\n        return None\n\n    def next_moment_operating_on(self,\n                                 qubits: Iterable[ops.QubitId],\n                                 start_moment_index: int = 0,\n                                 max_distance: int = None) -> Optional[int]:\n        \"\"\"Finds the index of the next moment that touches the given qubits.\n\n        Args:\n            qubits: We're looking for operations affecting any of these qubits.\n            start_moment_index: The starting point of the search.\n            max_distance: The number of moments (starting from the start index\n                and moving forward) to check. Defaults to no limit.\n\n        Returns:\n            None if there is no matching moment, otherwise the index of the\n            earliest matching moment.\n\n        Raises:\n          ValueError: negative max_distance.\n        \"\"\"\n        if max_distance is None:\n            max_distance = float('inf')\n        elif max_distance < 0:\n            raise ValueError('Negative max_distance: {}'.format(max_distance))\n\n        # Don't bother searching indices past the end of the list.\n        max_distance = int(\n            min(max_distance, len(self.moments) - start_moment_index))\n\n        return self._first_moment_operating_on(\n            qubits,\n            range(start_moment_index, start_moment_index + max_distance))\n\n    def prev_moment_operating_on(\n            self,\n            qubits: List[ops.QubitId],\n            end_moment_index: Optional[int] = None,\n            max_distance: Optional[int] = None) -> Optional[int]:\n        \"\"\"Finds the index of the next moment that touches the given qubits.\n\n        Args:\n            qubits: We're looking for operations affecting any of these qubits.\n            end_moment_index: The moment index just after the starting point of\n                the reverse search. Defaults to the length of the list of\n                moments.\n            max_distance: The number of moments (starting just before from the\n                end index and moving backward) to check. Defaults to no limit.\n\n        Returns:\n            None if there is no matching moment, otherwise the index of the\n            latest matching moment.\n\n        Raises:\n            ValueError: negative max_distance.\n        \"\"\"\n        if max_distance is None:\n            max_distance = float('inf')\n        elif max_distance < 0:\n            raise ValueError('Negative max_distance: {}'.format(max_distance))\n\n        if end_moment_index is None:\n            end_moment_index = len(self.moments)\n\n        # Don't bother searching indices past the start of the list.\n        max_distance = min(end_moment_index, max_distance)\n\n        # Don't bother searching indices past the end of the list.\n        if end_moment_index > len(self.moments):\n            d = end_moment_index - len(self.moments)\n            end_moment_index -= d\n            max_distance -= d\n        if max_distance <= 0:\n            return None\n\n        return self._first_moment_operating_on(qubits,\n                                               (end_moment_index - k - 1\n                                                for k in range(max_distance)))\n\n    def operation_at(self, qubit: ops.QubitId,\n                     moment_index: int) -> Optional[ops.Operation]:\n        \"\"\"Finds the operation on a qubit within a moment, if any.\n\n        Args:\n            qubit: The qubit to check for an operation on.\n            moment_index: The index of the moment to check for an operation\n                within. Allowed to be beyond the end of the circuit.\n\n        Returns:\n            None if there is no operation on the qubit at the given moment, or\n            else the operation.\n        \"\"\"\n        if not 0 <= moment_index < len(self.moments):\n            return None\n        for op in self.moments[moment_index].operations:\n            if qubit in op.qubits:\n                return op\n        return None\n\n    def clear_operations_touching(self, qubits: Iterable[ops.QubitId],\n                                  moment_indices: Iterable[int]):\n        \"\"\"Clears operations that are touching given qubits at given moments.\n\n        Args:\n            qubits: The qubits to check for operations on.\n            moment_indices: The indices of moments to check for operations\n                within.\n        \"\"\"\n        qubits = frozenset(qubits)\n        for k in moment_indices:\n            if 0 <= k < len(self.moments):\n                self.moments[k] = self.moments[k].without_operations_touching(\n                    qubits)\n\n    def _pick_or_create_inserted_op_moment_index(\n            self, splitter_index: int, op: ops.Operation,\n            strategy: InsertStrategy) -> int:\n        \"\"\"Determines and prepares where an insertion will occur.\n\n        Args:\n            splitter_index: The index to insert at.\n            op: The operation that will be inserted.\n            strategy: The insertion strategy.\n\n        Returns:\n            The index of the (possibly new) moment where the insertion should\n                occur.\n\n        Raises:\n            ValueError: Unrecognized append strategy.\n        \"\"\"\n\n        if (strategy is InsertStrategy.NEW or\n                strategy is InsertStrategy.NEW_THEN_INLINE):\n            self.moments.insert(splitter_index, Moment())\n            return splitter_index\n\n        if strategy is InsertStrategy.INLINE:\n            if (not self._has_op_at(splitter_index - 1, op.qubits) and\n                    0 <= splitter_index - 1 < len(self.moments)):\n                return splitter_index - 1\n\n            return self._pick_or_create_inserted_op_moment_index(\n                splitter_index, op, InsertStrategy.NEW)\n\n        if strategy is InsertStrategy.EARLIEST:\n            if not self._has_op_at(splitter_index, op.qubits):\n                p = self.prev_moment_operating_on(op.qubits, splitter_index)\n                return p + 1 if p is not None else 0\n\n            return self._pick_or_create_inserted_op_moment_index(\n                splitter_index, op, InsertStrategy.INLINE)\n\n        raise ValueError('Unrecognized append strategy: {}'.format(strategy))\n\n    def _has_op_at(self, moment_index, qubits):\n        return (0 <= moment_index < len(self.moments) and\n                self.moments[moment_index].operates_on(qubits))\n\n    def insert(\n            self,\n            index: int,\n            operation_tree: ops.OP_TREE,\n            strategy: InsertStrategy = InsertStrategy.NEW_THEN_INLINE) -> int:\n        \"\"\"Inserts operations into the middle of the circuit.\n\n        Args:\n            index: The index to insert all of the operations at.\n            operation_tree: An operation or tree of operations.\n            strategy: How to pick/create the moment to put operations into.\n\n        Returns:\n            The insertion index that will place operations just after the\n            operations that were inserted by this method.\n\n        Raises:\n            IndexError: Bad insertion index.\n            ValueError: Bad insertion strategy.\n        \"\"\"\n        if not 0 <= index <= len(self.moments):\n            raise IndexError('Insert index out of range: {}'.format(index))\n\n        k = index\n        for op in ops.flatten_op_tree(operation_tree):\n            p = self._pick_or_create_inserted_op_moment_index(k, op, strategy)\n            while p >= len(self.moments):\n                self.moments.append(Moment())\n            self.moments[p] = self.moments[p].with_operation(op)\n            k = max(k, p + 1)\n            if strategy is InsertStrategy.NEW_THEN_INLINE:\n                strategy = InsertStrategy.INLINE\n        return k\n\n    def append(\n            self,\n            operation_tree: ops.OP_TREE,\n            strategy: InsertStrategy = InsertStrategy.NEW_THEN_INLINE):\n        \"\"\"Appends operations onto the end of the circuit.\n\n        Args:\n            operation_tree: An operation or tree of operations.\n            strategy: How to pick/create the moment to put operations into.\n        \"\"\"\n        self.insert(len(self.moments), operation_tree, strategy)\n\n    def qubits(self) -> Set[QubitId]:\n        \"\"\"Returns the qubits acted upon by Operations in this circuit.\"\"\"\n        return frozenset(q for m in self.moments for q in m.qubits)\n\n    def __repr__(self):\n        moment_lines = ('\\n    ' + repr(moment) for moment in self.moments)\n        return 'Circuit([{}])'.format(','.join(moment_lines))\n\n    def __str__(self):\n        moment_lines = ('\\n    ' + str(moment) for moment in self.moments)\n        return 'Circuit [{}\\n]'.format(''.join(moment_lines))\n", "path": "cirq/circuits/circuit.py"}], "after_files": [{"content": "# Copyright 2018 Google LLC\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\"\"\"The circuit data structure for the sequenced phase.\"\"\"\n\nfrom typing import Iterable, List, Optional, Set\n\nfrom cirq import ops\nfrom cirq.circuits.insert_strategy import InsertStrategy\nfrom cirq.circuits.moment import Moment\nfrom cirq.ops import QubitId\n\n\nclass Circuit(object):\n    \"\"\"A mutable list of groups of operations to apply to some qubits.\"\"\"\n\n    def __init__(self, moments: Iterable[Moment] = ()):\n        \"\"\"Initializes a circuit.\n\n        Args:\n            moments: The initial list of moments defining the circuit.\n        \"\"\"\n        self.moments = list(moments)\n\n    @staticmethod\n    def from_ops(*operations: ops.OP_TREE,\n                 strategy: InsertStrategy = InsertStrategy.NEW_THEN_INLINE\n                 ) -> 'Circuit':\n        \"\"\"Creates an empty circuit and appends the given operations.\n\n        Args:\n            operations: The operations to append to the new circuit.\n            strategy: How to append the operations.\n\n        Returns:\n            The constructed circuit containing the operations.\n        \"\"\"\n        result = Circuit()\n        result.append(operations, strategy)\n        return result\n\n    def __eq__(self, other):\n        if not isinstance(other, type(self)):\n            return NotImplemented\n        return self.moments == other.moments\n\n    def __ne__(self, other):\n        return not self == other\n\n    __hash__ = None\n\n    def _first_moment_operating_on(self, qubits: Iterable[ops.QubitId],\n                                   indices: Iterable[int]) -> Optional[int]:\n        qubits = frozenset(qubits)\n        for m in indices:\n            if self._has_op_at(m, qubits):\n                return m\n        return None\n\n    def next_moment_operating_on(self,\n                                 qubits: Iterable[ops.QubitId],\n                                 start_moment_index: int = 0,\n                                 max_distance: int = None) -> Optional[int]:\n        \"\"\"Finds the index of the next moment that touches the given qubits.\n\n        Args:\n            qubits: We're looking for operations affecting any of these qubits.\n            start_moment_index: The starting point of the search.\n            max_distance: The number of moments (starting from the start index\n                and moving forward) to check. Defaults to no limit.\n\n        Returns:\n            None if there is no matching moment, otherwise the index of the\n            earliest matching moment.\n\n        Raises:\n          ValueError: negative max_distance.\n        \"\"\"\n        if max_distance is None:\n            max_distance = float('inf')\n        elif max_distance < 0:\n            raise ValueError('Negative max_distance: {}'.format(max_distance))\n\n        # Don't bother searching indices past the end of the list.\n        max_distance = int(\n            min(max_distance, len(self.moments) - start_moment_index))\n\n        return self._first_moment_operating_on(\n            qubits,\n            range(start_moment_index, start_moment_index + max_distance))\n\n    def prev_moment_operating_on(\n            self,\n            qubits: List[ops.QubitId],\n            end_moment_index: Optional[int] = None,\n            max_distance: Optional[int] = None) -> Optional[int]:\n        \"\"\"Finds the index of the next moment that touches the given qubits.\n\n        Args:\n            qubits: We're looking for operations affecting any of these qubits.\n            end_moment_index: The moment index just after the starting point of\n                the reverse search. Defaults to the length of the list of\n                moments.\n            max_distance: The number of moments (starting just before from the\n                end index and moving backward) to check. Defaults to no limit.\n\n        Returns:\n            None if there is no matching moment, otherwise the index of the\n            latest matching moment.\n\n        Raises:\n            ValueError: negative max_distance.\n        \"\"\"\n        if max_distance is None:\n            max_distance = float('inf')\n        elif max_distance < 0:\n            raise ValueError('Negative max_distance: {}'.format(max_distance))\n\n        if end_moment_index is None:\n            end_moment_index = len(self.moments)\n\n        # Don't bother searching indices past the start of the list.\n        max_distance = min(end_moment_index, max_distance)\n\n        # Don't bother searching indices past the end of the list.\n        if end_moment_index > len(self.moments):\n            d = end_moment_index - len(self.moments)\n            end_moment_index -= d\n            max_distance -= d\n        if max_distance <= 0:\n            return None\n\n        return self._first_moment_operating_on(qubits,\n                                               (end_moment_index - k - 1\n                                                for k in range(max_distance)))\n\n    def operation_at(self, qubit: ops.QubitId,\n                     moment_index: int) -> Optional[ops.Operation]:\n        \"\"\"Finds the operation on a qubit within a moment, if any.\n\n        Args:\n            qubit: The qubit to check for an operation on.\n            moment_index: The index of the moment to check for an operation\n                within. Allowed to be beyond the end of the circuit.\n\n        Returns:\n            None if there is no operation on the qubit at the given moment, or\n            else the operation.\n        \"\"\"\n        if not 0 <= moment_index < len(self.moments):\n            return None\n        for op in self.moments[moment_index].operations:\n            if qubit in op.qubits:\n                return op\n        return None\n\n    def clear_operations_touching(self, qubits: Iterable[ops.QubitId],\n                                  moment_indices: Iterable[int]):\n        \"\"\"Clears operations that are touching given qubits at given moments.\n\n        Args:\n            qubits: The qubits to check for operations on.\n            moment_indices: The indices of moments to check for operations\n                within.\n        \"\"\"\n        qubits = frozenset(qubits)\n        for k in moment_indices:\n            if 0 <= k < len(self.moments):\n                self.moments[k] = self.moments[k].without_operations_touching(\n                    qubits)\n\n    def _pick_or_create_inserted_op_moment_index(\n            self, splitter_index: int, op: ops.Operation,\n            strategy: InsertStrategy) -> int:\n        \"\"\"Determines and prepares where an insertion will occur.\n\n        Args:\n            splitter_index: The index to insert at.\n            op: The operation that will be inserted.\n            strategy: The insertion strategy.\n\n        Returns:\n            The index of the (possibly new) moment where the insertion should\n                occur.\n\n        Raises:\n            ValueError: Unrecognized append strategy.\n        \"\"\"\n\n        if (strategy is InsertStrategy.NEW or\n                strategy is InsertStrategy.NEW_THEN_INLINE):\n            self.moments.insert(splitter_index, Moment())\n            return splitter_index\n\n        if strategy is InsertStrategy.INLINE:\n            if (not self._has_op_at(splitter_index - 1, op.qubits) and\n                    0 <= splitter_index - 1 < len(self.moments)):\n                return splitter_index - 1\n\n            return self._pick_or_create_inserted_op_moment_index(\n                splitter_index, op, InsertStrategy.NEW)\n\n        if strategy is InsertStrategy.EARLIEST:\n            if not self._has_op_at(splitter_index, op.qubits):\n                p = self.prev_moment_operating_on(op.qubits, splitter_index)\n                return p + 1 if p is not None else 0\n\n            return self._pick_or_create_inserted_op_moment_index(\n                splitter_index, op, InsertStrategy.INLINE)\n\n        raise ValueError('Unrecognized append strategy: {}'.format(strategy))\n\n    def _has_op_at(self, moment_index, qubits):\n        return (0 <= moment_index < len(self.moments) and\n                self.moments[moment_index].operates_on(qubits))\n\n    def insert(\n            self,\n            index: int,\n            operation_tree: ops.OP_TREE,\n            strategy: InsertStrategy = InsertStrategy.NEW_THEN_INLINE) -> int:\n        \"\"\"Inserts operations into the middle of the circuit.\n\n        Args:\n            index: The index to insert all of the operations at.\n            operation_tree: An operation or tree of operations.\n            strategy: How to pick/create the moment to put operations into.\n\n        Returns:\n            The insertion index that will place operations just after the\n            operations that were inserted by this method.\n\n        Raises:\n            IndexError: Bad insertion index.\n            ValueError: Bad insertion strategy.\n        \"\"\"\n        if not 0 <= index <= len(self.moments):\n            raise IndexError('Insert index out of range: {}'.format(index))\n\n        k = index\n        for op in ops.flatten_op_tree(operation_tree):\n            p = self._pick_or_create_inserted_op_moment_index(k, op, strategy)\n            while p >= len(self.moments):\n                self.moments.append(Moment())\n            self.moments[p] = self.moments[p].with_operation(op)\n            k = max(k, p + 1)\n            if strategy is InsertStrategy.NEW_THEN_INLINE:\n                strategy = InsertStrategy.INLINE\n        return k\n\n    def append(\n            self,\n            operation_tree: ops.OP_TREE,\n            strategy: InsertStrategy = InsertStrategy.NEW_THEN_INLINE):\n        \"\"\"Appends operations onto the end of the circuit.\n\n        Args:\n            operation_tree: An operation or tree of operations.\n            strategy: How to pick/create the moment to put operations into.\n        \"\"\"\n        self.insert(len(self.moments), operation_tree, strategy)\n\n    def qubits(self) -> Set[QubitId]:\n        \"\"\"Returns the qubits acted upon by Operations in this circuit.\"\"\"\n        return frozenset(q for m in self.moments for q in m.qubits)\n\n    def __repr__(self):\n        moment_lines = ('\\n    ' + repr(moment) for moment in self.moments)\n        return 'Circuit([{}])'.format(','.join(moment_lines))\n\n    def __str__(self):\n        moment_lines = ('\\n    ' + str(moment) for moment in self.moments)\n        return 'Circuit [{}\\n]'.format(''.join(moment_lines))\n", "path": "cirq/circuits/circuit.py"}]}