We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
eval(repr(measurement_gate)) fails for keys of the type `'a:b:c'`
**Description of the issue**
repr(measurement_gate) prints the wrong repr when using a nested measurement key of the form `a:b:c`. This is not catched in the json serialization tests because we explicitly call `MeasurementKey.parse_serialized(key)` in the `_from_json_dict_` function of `MeasurementGate` class. 

**How to reproduce the issue**

```python
In [1]: import cirq
   ...: g = cirq.MeasurementGate(2, cirq.MeasurementKey.parse_serialized('a:b:c'))
   ...: print(g, repr(g))
   ...: eval(repr(g))
cirq.MeasurementGate(2, 'a:b:c', ()) cirq.MeasurementGate(2, 'a:b:c', ())
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-7-0da6052a742e> in <module>
      2 g = cirq.MeasurementGate(2, cirq.MeasurementKey.parse_serialized('a:b:c'))
      3 print(g, repr(g))
----> 4 eval(repr(g))

<string> in <module>

~/opt/anaconda3/envs/cirq/lib/python3.8/site-packages/cirq/ops/measurement_gate.py in __init__(self, num_qubits, key, invert_mask, qid_shape)
     66         if len(self._qid_shape) != num_qubits:
     67             raise ValueError('len(qid_shape) != num_qubits')
---> 68         self.key = key  # type: ignore
     69         self.invert_mask = invert_mask or ()
     70         if self.invert_mask is not None and len(self.invert_mask) > self.num_qubits():

~/opt/anaconda3/envs/cirq/lib/python3.8/site-packages/cirq/ops/measurement_gate.py in key(self, key)
     80             self.mkey = key
     81         else:
---> 82             self.mkey = value.MeasurementKey(name=key)
     83
     84     def _qid_shape_(self) -> Tuple[int, ...]:

~/opt/anaconda3/envs/cirq/lib/python3.8/site-packages/cirq/value/measurement_key.py in __init__(self, name, path)

~/opt/anaconda3/envs/cirq/lib/python3.8/site-packages/cirq/value/measurement_key.py in __post_init__(self)
     45             raise ValueError("Measurement key name cannot be empty")
     46         if MEASUREMENT_KEY_SEPARATOR in self.name:
---> 47             raise ValueError(
     48                 f'Invalid key name: {self.name}\n{MEASUREMENT_KEY_SEPARATOR} is not allowed in '
     49                 'MeasurementKey. If this is a nested key string, use '

ValueError: Invalid key name: a:b:c
: is not allowed in MeasurementKey. If this is a nested key string, use `MeasurementKey.parse_serialized` for correct behavior.

```

**Cirq version**
0.12.0.dev


--- 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-core/cirq/ops/measurement_gate.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 from typing import Any, Dict, Iterable, Optional, Tuple, Sequence, TYPE_CHECKING, Union
16 
17 import numpy as np
18 
19 from cirq import protocols, value
20 from cirq.ops import raw_types
21 
22 if TYPE_CHECKING:
23     import cirq
24 
25 
26 @value.value_equality
27 class MeasurementGate(raw_types.Gate):
28     """A gate that measures qubits in the computational basis.
29 
30     The measurement gate contains a key that is used to identify results
31     of measurements.
32     """
33 
34     def __init__(
35         self,
36         num_qubits: Optional[int] = None,
37         key: Union[str, value.MeasurementKey] = '',
38         invert_mask: Tuple[bool, ...] = (),
39         qid_shape: Tuple[int, ...] = None,
40     ) -> None:
41         """Inits MeasurementGate.
42 
43         Args:
44             num_qubits: The number of qubits to act upon.
45             key: The string key of the measurement.
46             invert_mask: A list of values indicating whether the corresponding
47                 qubits should be flipped. The list's length must not be longer
48                 than the number of qubits, but it is permitted to be shorter.
49                 Qubits with indices past the end of the mask are not flipped.
50             qid_shape: Specifies the dimension of each qid the measurement
51                 applies to.  The default is 2 for every qubit.
52 
53         Raises:
54             ValueError: If the length of invert_mask is greater than num_qubits.
55                 or if the length of qid_shape doesn't equal num_qubits.
56         """
57         if qid_shape is None:
58             if num_qubits is None:
59                 raise ValueError('Specify either the num_qubits or qid_shape argument.')
60             qid_shape = (2,) * num_qubits
61         elif num_qubits is None:
62             num_qubits = len(qid_shape)
63         if num_qubits == 0:
64             raise ValueError('Measuring an empty set of qubits.')
65         self._qid_shape = qid_shape
66         if len(self._qid_shape) != num_qubits:
67             raise ValueError('len(qid_shape) != num_qubits')
68         self.key = key  # type: ignore
69         self.invert_mask = invert_mask or ()
70         if self.invert_mask is not None and len(self.invert_mask) > self.num_qubits():
71             raise ValueError('len(invert_mask) > num_qubits')
72 
73     @property
74     def key(self) -> str:
75         return str(self.mkey)
76 
77     @key.setter
78     def key(self, key: Union[str, value.MeasurementKey]):
79         if isinstance(key, value.MeasurementKey):
80             self.mkey = key
81         else:
82             self.mkey = value.MeasurementKey(name=key)
83 
84     def _qid_shape_(self) -> Tuple[int, ...]:
85         return self._qid_shape
86 
87     def with_key(self, key: Union[str, value.MeasurementKey]) -> 'MeasurementGate':
88         """Creates a measurement gate with a new key but otherwise identical."""
89         if key == self.key:
90             return self
91         return MeasurementGate(
92             self.num_qubits(), key=key, invert_mask=self.invert_mask, qid_shape=self._qid_shape
93         )
94 
95     def _with_key_path_(self, path: Tuple[str, ...]):
96         return self.with_key(self.mkey._with_key_path_(path))
97 
98     def _with_measurement_key_mapping_(self, key_map: Dict[str, str]):
99         return self.with_key(protocols.with_measurement_key_mapping(self.mkey, key_map))
100 
101     def with_bits_flipped(self, *bit_positions: int) -> 'MeasurementGate':
102         """Toggles whether or not the measurement inverts various outputs."""
103         old_mask = self.invert_mask or ()
104         n = max(len(old_mask) - 1, *bit_positions) + 1
105         new_mask = [k < len(old_mask) and old_mask[k] for k in range(n)]
106         for b in bit_positions:
107             new_mask[b] = not new_mask[b]
108         return MeasurementGate(
109             self.num_qubits(), key=self.key, invert_mask=tuple(new_mask), qid_shape=self._qid_shape
110         )
111 
112     def full_invert_mask(self):
113         """Returns the invert mask for all qubits.
114 
115         If the user supplies a partial invert_mask, this returns that mask
116         padded by False.
117 
118         Similarly if no invert_mask is supplies this returns a tuple
119         of size equal to the number of qubits with all entries False.
120         """
121         mask = self.invert_mask or self.num_qubits() * (False,)
122         deficit = self.num_qubits() - len(mask)
123         mask += (False,) * deficit
124         return mask
125 
126     def _is_measurement_(self) -> bool:
127         return True
128 
129     def _measurement_key_name_(self):
130         return self.key
131 
132     def _kraus_(self):
133         size = np.prod(self._qid_shape, dtype=np.int64)
134 
135         def delta(i):
136             result = np.zeros((size, size))
137             result[i][i] = 1
138             return result
139 
140         return tuple(delta(i) for i in range(size))
141 
142     def _has_kraus_(self):
143         return True
144 
145     def _circuit_diagram_info_(
146         self, args: 'cirq.CircuitDiagramInfoArgs'
147     ) -> 'cirq.CircuitDiagramInfo':
148         symbols = ['M'] * self.num_qubits()
149 
150         # Show which output bits are negated.
151         if self.invert_mask:
152             for i, b in enumerate(self.invert_mask):
153                 if b:
154                     symbols[i] = '!M'
155 
156         # Mention the measurement key.
157         if not args.known_qubits or self.key != _default_measurement_key(args.known_qubits):
158             symbols[0] += f"('{self.key}')"
159 
160         return protocols.CircuitDiagramInfo(tuple(symbols))
161 
162     def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
163         if not all(d == 2 for d in self._qid_shape):
164             return NotImplemented
165         args.validate_version('2.0')
166         invert_mask = self.invert_mask
167         if len(invert_mask) < len(qubits):
168             invert_mask = invert_mask + (False,) * (len(qubits) - len(invert_mask))
169         lines = []
170         for i, (qubit, inv) in enumerate(zip(qubits, invert_mask)):
171             if inv:
172                 lines.append(args.format('x {0};  // Invert the following measurement\n', qubit))
173             lines.append(args.format('measure {0} -> {1:meas}[{2}];\n', qubit, self.key, i))
174         return ''.join(lines)
175 
176     def _quil_(
177         self, qubits: Tuple['cirq.Qid', ...], formatter: 'cirq.QuilFormatter'
178     ) -> Optional[str]:
179         if not all(d == 2 for d in self._qid_shape):
180             return NotImplemented
181         invert_mask = self.invert_mask
182         if len(invert_mask) < len(qubits):
183             invert_mask = invert_mask + (False,) * (len(qubits) - len(invert_mask))
184         lines = []
185         for i, (qubit, inv) in enumerate(zip(qubits, invert_mask)):
186             if inv:
187                 lines.append(
188                     formatter.format('X {0} # Inverting for following measurement\n', qubit)
189                 )
190             lines.append(formatter.format('MEASURE {0} {1:meas}[{2}]\n', qubit, self.key, i))
191         return ''.join(lines)
192 
193     def _op_repr_(self, qubits: Sequence['cirq.Qid']) -> str:
194         args = list(repr(q) for q in qubits)
195         if self.key != _default_measurement_key(qubits):
196             args.append(f'key={self.key!r}')
197         if self.invert_mask:
198             args.append(f'invert_mask={self.invert_mask!r}')
199         arg_list = ', '.join(args)
200         return f'cirq.measure({arg_list})'
201 
202     def __repr__(self):
203         qid_shape_arg = ''
204         if any(d != 2 for d in self._qid_shape):
205             qid_shape_arg = f', {self._qid_shape!r}'
206         return (
207             f'cirq.MeasurementGate('
208             f'{self.num_qubits()!r}, '
209             f'{self.key!r}, '
210             f'{self.invert_mask}'
211             f'{qid_shape_arg})'
212         )
213 
214     def _value_equality_values_(self) -> Any:
215         return self.key, self.invert_mask, self._qid_shape
216 
217     def _json_dict_(self) -> Dict[str, Any]:
218         other = {}
219         if not all(d == 2 for d in self._qid_shape):
220             other['qid_shape'] = self._qid_shape
221         return {
222             'cirq_type': self.__class__.__name__,
223             'num_qubits': len(self._qid_shape),
224             'key': self.key,
225             'invert_mask': self.invert_mask,
226             **other,
227         }
228 
229     @classmethod
230     def _from_json_dict_(cls, num_qubits, key, invert_mask, qid_shape=None, **kwargs):
231         return cls(
232             num_qubits=num_qubits,
233             key=value.MeasurementKey.parse_serialized(key),
234             invert_mask=tuple(invert_mask),
235             qid_shape=None if qid_shape is None else tuple(qid_shape),
236         )
237 
238     def _has_stabilizer_effect_(self) -> Optional[bool]:
239         return True
240 
241     def _act_on_(self, args: 'cirq.OperationTarget', qubits: Sequence['cirq.Qid']) -> bool:
242         from cirq.sim import ActOnArgs
243 
244         if not isinstance(args, ActOnArgs):
245             return NotImplemented
246         args.measure(qubits, self.key, self.full_invert_mask())
247         return True
248 
249 
250 def _default_measurement_key(qubits: Iterable[raw_types.Qid]) -> str:
251     return ','.join(str(q) for q in qubits)
252
```
--- 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-core/cirq/ops/measurement_gate.py b/cirq-core/cirq/ops/measurement_gate.py
--- a/cirq-core/cirq/ops/measurement_gate.py
+++ b/cirq-core/cirq/ops/measurement_gate.py
@@ -193,7 +193,7 @@
     def _op_repr_(self, qubits: Sequence['cirq.Qid']) -> str:
         args = list(repr(q) for q in qubits)
         if self.key != _default_measurement_key(qubits):
-            args.append(f'key={self.key!r}')
+            args.append(f'key={self.mkey!r}')
         if self.invert_mask:
             args.append(f'invert_mask={self.invert_mask!r}')
         arg_list = ', '.join(args)
@@ -206,7 +206,7 @@
         return (
             f'cirq.MeasurementGate('
             f'{self.num_qubits()!r}, '
-            f'{self.key!r}, '
+            f'{self.mkey!r}, '
             f'{self.invert_mask}'
             f'{qid_shape_arg})'
         )

{"golden_diff": "diff --git a/cirq-core/cirq/ops/measurement_gate.py b/cirq-core/cirq/ops/measurement_gate.py\n--- a/cirq-core/cirq/ops/measurement_gate.py\n+++ b/cirq-core/cirq/ops/measurement_gate.py\n@@ -193,7 +193,7 @@\n     def _op_repr_(self, qubits: Sequence['cirq.Qid']) -> str:\n         args = list(repr(q) for q in qubits)\n         if self.key != _default_measurement_key(qubits):\n-            args.append(f'key={self.key!r}')\n+            args.append(f'key={self.mkey!r}')\n         if self.invert_mask:\n             args.append(f'invert_mask={self.invert_mask!r}')\n         arg_list = ', '.join(args)\n@@ -206,7 +206,7 @@\n         return (\n             f'cirq.MeasurementGate('\n             f'{self.num_qubits()!r}, '\n-            f'{self.key!r}, '\n+            f'{self.mkey!r}, '\n             f'{self.invert_mask}'\n             f'{qid_shape_arg})'\n         )\n", "issue": "eval(repr(measurement_gate)) fails for keys of the type `'a:b:c'`\n**Description of the issue**\r\nrepr(measurement_gate) prints the wrong repr when using a nested measurement key of the form `a:b:c`. This is not catched in the json serialization tests because we explicitly call `MeasurementKey.parse_serialized(key)` in the `_from_json_dict_` function of `MeasurementGate` class. \r\n\r\n**How to reproduce the issue**\r\n\r\n```python\r\nIn [1]: import cirq\r\n   ...: g = cirq.MeasurementGate(2, cirq.MeasurementKey.parse_serialized('a:b:c'))\r\n   ...: print(g, repr(g))\r\n   ...: eval(repr(g))\r\ncirq.MeasurementGate(2, 'a:b:c', ()) cirq.MeasurementGate(2, 'a:b:c', ())\r\n---------------------------------------------------------------------------\r\nValueError                                Traceback (most recent call last)\r\n<ipython-input-7-0da6052a742e> in <module>\r\n      2 g = cirq.MeasurementGate(2, cirq.MeasurementKey.parse_serialized('a:b:c'))\r\n      3 print(g, repr(g))\r\n----> 4 eval(repr(g))\r\n\r\n<string> in <module>\r\n\r\n~/opt/anaconda3/envs/cirq/lib/python3.8/site-packages/cirq/ops/measurement_gate.py in __init__(self, num_qubits, key, invert_mask, qid_shape)\r\n     66         if len(self._qid_shape) != num_qubits:\r\n     67             raise ValueError('len(qid_shape) != num_qubits')\r\n---> 68         self.key = key  # type: ignore\r\n     69         self.invert_mask = invert_mask or ()\r\n     70         if self.invert_mask is not None and len(self.invert_mask) > self.num_qubits():\r\n\r\n~/opt/anaconda3/envs/cirq/lib/python3.8/site-packages/cirq/ops/measurement_gate.py in key(self, key)\r\n     80             self.mkey = key\r\n     81         else:\r\n---> 82             self.mkey = value.MeasurementKey(name=key)\r\n     83\r\n     84     def _qid_shape_(self) -> Tuple[int, ...]:\r\n\r\n~/opt/anaconda3/envs/cirq/lib/python3.8/site-packages/cirq/value/measurement_key.py in __init__(self, name, path)\r\n\r\n~/opt/anaconda3/envs/cirq/lib/python3.8/site-packages/cirq/value/measurement_key.py in __post_init__(self)\r\n     45             raise ValueError(\"Measurement key name cannot be empty\")\r\n     46         if MEASUREMENT_KEY_SEPARATOR in self.name:\r\n---> 47             raise ValueError(\r\n     48                 f'Invalid key name: {self.name}\\n{MEASUREMENT_KEY_SEPARATOR} is not allowed in '\r\n     49                 'MeasurementKey. If this is a nested key string, use '\r\n\r\nValueError: Invalid key name: a:b:c\r\n: is not allowed in MeasurementKey. If this is a nested key string, use `MeasurementKey.parse_serialized` for correct behavior.\r\n\r\n```\r\n\r\n**Cirq version**\r\n0.12.0.dev\r\n\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\nfrom typing import Any, Dict, Iterable, Optional, Tuple, Sequence, TYPE_CHECKING, Union\n\nimport numpy as np\n\nfrom cirq import protocols, value\nfrom cirq.ops import raw_types\n\nif TYPE_CHECKING:\n    import cirq\n\n\n@value.value_equality\nclass MeasurementGate(raw_types.Gate):\n    \"\"\"A gate that measures qubits in the computational basis.\n\n    The measurement gate contains a key that is used to identify results\n    of measurements.\n    \"\"\"\n\n    def __init__(\n        self,\n        num_qubits: Optional[int] = None,\n        key: Union[str, value.MeasurementKey] = '',\n        invert_mask: Tuple[bool, ...] = (),\n        qid_shape: Tuple[int, ...] = None,\n    ) -> None:\n        \"\"\"Inits MeasurementGate.\n\n        Args:\n            num_qubits: The number of qubits to act upon.\n            key: The string key of the measurement.\n            invert_mask: A list of values indicating whether the corresponding\n                qubits should be flipped. The list's length must not be longer\n                than the number of qubits, but it is permitted to be shorter.\n                Qubits with indices past the end of the mask are not flipped.\n            qid_shape: Specifies the dimension of each qid the measurement\n                applies to.  The default is 2 for every qubit.\n\n        Raises:\n            ValueError: If the length of invert_mask is greater than num_qubits.\n                or if the length of qid_shape doesn't equal num_qubits.\n        \"\"\"\n        if qid_shape is None:\n            if num_qubits is None:\n                raise ValueError('Specify either the num_qubits or qid_shape argument.')\n            qid_shape = (2,) * num_qubits\n        elif num_qubits is None:\n            num_qubits = len(qid_shape)\n        if num_qubits == 0:\n            raise ValueError('Measuring an empty set of qubits.')\n        self._qid_shape = qid_shape\n        if len(self._qid_shape) != num_qubits:\n            raise ValueError('len(qid_shape) != num_qubits')\n        self.key = key  # type: ignore\n        self.invert_mask = invert_mask or ()\n        if self.invert_mask is not None and len(self.invert_mask) > self.num_qubits():\n            raise ValueError('len(invert_mask) > num_qubits')\n\n    @property\n    def key(self) -> str:\n        return str(self.mkey)\n\n    @key.setter\n    def key(self, key: Union[str, value.MeasurementKey]):\n        if isinstance(key, value.MeasurementKey):\n            self.mkey = key\n        else:\n            self.mkey = value.MeasurementKey(name=key)\n\n    def _qid_shape_(self) -> Tuple[int, ...]:\n        return self._qid_shape\n\n    def with_key(self, key: Union[str, value.MeasurementKey]) -> 'MeasurementGate':\n        \"\"\"Creates a measurement gate with a new key but otherwise identical.\"\"\"\n        if key == self.key:\n            return self\n        return MeasurementGate(\n            self.num_qubits(), key=key, invert_mask=self.invert_mask, qid_shape=self._qid_shape\n        )\n\n    def _with_key_path_(self, path: Tuple[str, ...]):\n        return self.with_key(self.mkey._with_key_path_(path))\n\n    def _with_measurement_key_mapping_(self, key_map: Dict[str, str]):\n        return self.with_key(protocols.with_measurement_key_mapping(self.mkey, key_map))\n\n    def with_bits_flipped(self, *bit_positions: int) -> 'MeasurementGate':\n        \"\"\"Toggles whether or not the measurement inverts various outputs.\"\"\"\n        old_mask = self.invert_mask or ()\n        n = max(len(old_mask) - 1, *bit_positions) + 1\n        new_mask = [k < len(old_mask) and old_mask[k] for k in range(n)]\n        for b in bit_positions:\n            new_mask[b] = not new_mask[b]\n        return MeasurementGate(\n            self.num_qubits(), key=self.key, invert_mask=tuple(new_mask), qid_shape=self._qid_shape\n        )\n\n    def full_invert_mask(self):\n        \"\"\"Returns the invert mask for all qubits.\n\n        If the user supplies a partial invert_mask, this returns that mask\n        padded by False.\n\n        Similarly if no invert_mask is supplies this returns a tuple\n        of size equal to the number of qubits with all entries False.\n        \"\"\"\n        mask = self.invert_mask or self.num_qubits() * (False,)\n        deficit = self.num_qubits() - len(mask)\n        mask += (False,) * deficit\n        return mask\n\n    def _is_measurement_(self) -> bool:\n        return True\n\n    def _measurement_key_name_(self):\n        return self.key\n\n    def _kraus_(self):\n        size = np.prod(self._qid_shape, dtype=np.int64)\n\n        def delta(i):\n            result = np.zeros((size, size))\n            result[i][i] = 1\n            return result\n\n        return tuple(delta(i) for i in range(size))\n\n    def _has_kraus_(self):\n        return True\n\n    def _circuit_diagram_info_(\n        self, args: 'cirq.CircuitDiagramInfoArgs'\n    ) -> 'cirq.CircuitDiagramInfo':\n        symbols = ['M'] * self.num_qubits()\n\n        # Show which output bits are negated.\n        if self.invert_mask:\n            for i, b in enumerate(self.invert_mask):\n                if b:\n                    symbols[i] = '!M'\n\n        # Mention the measurement key.\n        if not args.known_qubits or self.key != _default_measurement_key(args.known_qubits):\n            symbols[0] += f\"('{self.key}')\"\n\n        return protocols.CircuitDiagramInfo(tuple(symbols))\n\n    def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:\n        if not all(d == 2 for d in self._qid_shape):\n            return NotImplemented\n        args.validate_version('2.0')\n        invert_mask = self.invert_mask\n        if len(invert_mask) < len(qubits):\n            invert_mask = invert_mask + (False,) * (len(qubits) - len(invert_mask))\n        lines = []\n        for i, (qubit, inv) in enumerate(zip(qubits, invert_mask)):\n            if inv:\n                lines.append(args.format('x {0};  // Invert the following measurement\\n', qubit))\n            lines.append(args.format('measure {0} -> {1:meas}[{2}];\\n', qubit, self.key, i))\n        return ''.join(lines)\n\n    def _quil_(\n        self, qubits: Tuple['cirq.Qid', ...], formatter: 'cirq.QuilFormatter'\n    ) -> Optional[str]:\n        if not all(d == 2 for d in self._qid_shape):\n            return NotImplemented\n        invert_mask = self.invert_mask\n        if len(invert_mask) < len(qubits):\n            invert_mask = invert_mask + (False,) * (len(qubits) - len(invert_mask))\n        lines = []\n        for i, (qubit, inv) in enumerate(zip(qubits, invert_mask)):\n            if inv:\n                lines.append(\n                    formatter.format('X {0} # Inverting for following measurement\\n', qubit)\n                )\n            lines.append(formatter.format('MEASURE {0} {1:meas}[{2}]\\n', qubit, self.key, i))\n        return ''.join(lines)\n\n    def _op_repr_(self, qubits: Sequence['cirq.Qid']) -> str:\n        args = list(repr(q) for q in qubits)\n        if self.key != _default_measurement_key(qubits):\n            args.append(f'key={self.key!r}')\n        if self.invert_mask:\n            args.append(f'invert_mask={self.invert_mask!r}')\n        arg_list = ', '.join(args)\n        return f'cirq.measure({arg_list})'\n\n    def __repr__(self):\n        qid_shape_arg = ''\n        if any(d != 2 for d in self._qid_shape):\n            qid_shape_arg = f', {self._qid_shape!r}'\n        return (\n            f'cirq.MeasurementGate('\n            f'{self.num_qubits()!r}, '\n            f'{self.key!r}, '\n            f'{self.invert_mask}'\n            f'{qid_shape_arg})'\n        )\n\n    def _value_equality_values_(self) -> Any:\n        return self.key, self.invert_mask, self._qid_shape\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        other = {}\n        if not all(d == 2 for d in self._qid_shape):\n            other['qid_shape'] = self._qid_shape\n        return {\n            'cirq_type': self.__class__.__name__,\n            'num_qubits': len(self._qid_shape),\n            'key': self.key,\n            'invert_mask': self.invert_mask,\n            **other,\n        }\n\n    @classmethod\n    def _from_json_dict_(cls, num_qubits, key, invert_mask, qid_shape=None, **kwargs):\n        return cls(\n            num_qubits=num_qubits,\n            key=value.MeasurementKey.parse_serialized(key),\n            invert_mask=tuple(invert_mask),\n            qid_shape=None if qid_shape is None else tuple(qid_shape),\n        )\n\n    def _has_stabilizer_effect_(self) -> Optional[bool]:\n        return True\n\n    def _act_on_(self, args: 'cirq.OperationTarget', qubits: Sequence['cirq.Qid']) -> bool:\n        from cirq.sim import ActOnArgs\n\n        if not isinstance(args, ActOnArgs):\n            return NotImplemented\n        args.measure(qubits, self.key, self.full_invert_mask())\n        return True\n\n\ndef _default_measurement_key(qubits: Iterable[raw_types.Qid]) -> str:\n    return ','.join(str(q) for q in qubits)\n", "path": "cirq-core/cirq/ops/measurement_gate.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\nfrom typing import Any, Dict, Iterable, Optional, Tuple, Sequence, TYPE_CHECKING, Union\n\nimport numpy as np\n\nfrom cirq import protocols, value\nfrom cirq.ops import raw_types\n\nif TYPE_CHECKING:\n    import cirq\n\n\n@value.value_equality\nclass MeasurementGate(raw_types.Gate):\n    \"\"\"A gate that measures qubits in the computational basis.\n\n    The measurement gate contains a key that is used to identify results\n    of measurements.\n    \"\"\"\n\n    def __init__(\n        self,\n        num_qubits: Optional[int] = None,\n        key: Union[str, value.MeasurementKey] = '',\n        invert_mask: Tuple[bool, ...] = (),\n        qid_shape: Tuple[int, ...] = None,\n    ) -> None:\n        \"\"\"Inits MeasurementGate.\n\n        Args:\n            num_qubits: The number of qubits to act upon.\n            key: The string key of the measurement.\n            invert_mask: A list of values indicating whether the corresponding\n                qubits should be flipped. The list's length must not be longer\n                than the number of qubits, but it is permitted to be shorter.\n                Qubits with indices past the end of the mask are not flipped.\n            qid_shape: Specifies the dimension of each qid the measurement\n                applies to.  The default is 2 for every qubit.\n\n        Raises:\n            ValueError: If the length of invert_mask is greater than num_qubits.\n                or if the length of qid_shape doesn't equal num_qubits.\n        \"\"\"\n        if qid_shape is None:\n            if num_qubits is None:\n                raise ValueError('Specify either the num_qubits or qid_shape argument.')\n            qid_shape = (2,) * num_qubits\n        elif num_qubits is None:\n            num_qubits = len(qid_shape)\n        if num_qubits == 0:\n            raise ValueError('Measuring an empty set of qubits.')\n        self._qid_shape = qid_shape\n        if len(self._qid_shape) != num_qubits:\n            raise ValueError('len(qid_shape) != num_qubits')\n        self.key = key  # type: ignore\n        self.invert_mask = invert_mask or ()\n        if self.invert_mask is not None and len(self.invert_mask) > self.num_qubits():\n            raise ValueError('len(invert_mask) > num_qubits')\n\n    @property\n    def key(self) -> str:\n        return str(self.mkey)\n\n    @key.setter\n    def key(self, key: Union[str, value.MeasurementKey]):\n        if isinstance(key, value.MeasurementKey):\n            self.mkey = key\n        else:\n            self.mkey = value.MeasurementKey(name=key)\n\n    def _qid_shape_(self) -> Tuple[int, ...]:\n        return self._qid_shape\n\n    def with_key(self, key: Union[str, value.MeasurementKey]) -> 'MeasurementGate':\n        \"\"\"Creates a measurement gate with a new key but otherwise identical.\"\"\"\n        if key == self.key:\n            return self\n        return MeasurementGate(\n            self.num_qubits(), key=key, invert_mask=self.invert_mask, qid_shape=self._qid_shape\n        )\n\n    def _with_key_path_(self, path: Tuple[str, ...]):\n        return self.with_key(self.mkey._with_key_path_(path))\n\n    def _with_measurement_key_mapping_(self, key_map: Dict[str, str]):\n        return self.with_key(protocols.with_measurement_key_mapping(self.mkey, key_map))\n\n    def with_bits_flipped(self, *bit_positions: int) -> 'MeasurementGate':\n        \"\"\"Toggles whether or not the measurement inverts various outputs.\"\"\"\n        old_mask = self.invert_mask or ()\n        n = max(len(old_mask) - 1, *bit_positions) + 1\n        new_mask = [k < len(old_mask) and old_mask[k] for k in range(n)]\n        for b in bit_positions:\n            new_mask[b] = not new_mask[b]\n        return MeasurementGate(\n            self.num_qubits(), key=self.key, invert_mask=tuple(new_mask), qid_shape=self._qid_shape\n        )\n\n    def full_invert_mask(self):\n        \"\"\"Returns the invert mask for all qubits.\n\n        If the user supplies a partial invert_mask, this returns that mask\n        padded by False.\n\n        Similarly if no invert_mask is supplies this returns a tuple\n        of size equal to the number of qubits with all entries False.\n        \"\"\"\n        mask = self.invert_mask or self.num_qubits() * (False,)\n        deficit = self.num_qubits() - len(mask)\n        mask += (False,) * deficit\n        return mask\n\n    def _is_measurement_(self) -> bool:\n        return True\n\n    def _measurement_key_name_(self):\n        return self.key\n\n    def _kraus_(self):\n        size = np.prod(self._qid_shape, dtype=np.int64)\n\n        def delta(i):\n            result = np.zeros((size, size))\n            result[i][i] = 1\n            return result\n\n        return tuple(delta(i) for i in range(size))\n\n    def _has_kraus_(self):\n        return True\n\n    def _circuit_diagram_info_(\n        self, args: 'cirq.CircuitDiagramInfoArgs'\n    ) -> 'cirq.CircuitDiagramInfo':\n        symbols = ['M'] * self.num_qubits()\n\n        # Show which output bits are negated.\n        if self.invert_mask:\n            for i, b in enumerate(self.invert_mask):\n                if b:\n                    symbols[i] = '!M'\n\n        # Mention the measurement key.\n        if not args.known_qubits or self.key != _default_measurement_key(args.known_qubits):\n            symbols[0] += f\"('{self.key}')\"\n\n        return protocols.CircuitDiagramInfo(tuple(symbols))\n\n    def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:\n        if not all(d == 2 for d in self._qid_shape):\n            return NotImplemented\n        args.validate_version('2.0')\n        invert_mask = self.invert_mask\n        if len(invert_mask) < len(qubits):\n            invert_mask = invert_mask + (False,) * (len(qubits) - len(invert_mask))\n        lines = []\n        for i, (qubit, inv) in enumerate(zip(qubits, invert_mask)):\n            if inv:\n                lines.append(args.format('x {0};  // Invert the following measurement\\n', qubit))\n            lines.append(args.format('measure {0} -> {1:meas}[{2}];\\n', qubit, self.key, i))\n        return ''.join(lines)\n\n    def _quil_(\n        self, qubits: Tuple['cirq.Qid', ...], formatter: 'cirq.QuilFormatter'\n    ) -> Optional[str]:\n        if not all(d == 2 for d in self._qid_shape):\n            return NotImplemented\n        invert_mask = self.invert_mask\n        if len(invert_mask) < len(qubits):\n            invert_mask = invert_mask + (False,) * (len(qubits) - len(invert_mask))\n        lines = []\n        for i, (qubit, inv) in enumerate(zip(qubits, invert_mask)):\n            if inv:\n                lines.append(\n                    formatter.format('X {0} # Inverting for following measurement\\n', qubit)\n                )\n            lines.append(formatter.format('MEASURE {0} {1:meas}[{2}]\\n', qubit, self.key, i))\n        return ''.join(lines)\n\n    def _op_repr_(self, qubits: Sequence['cirq.Qid']) -> str:\n        args = list(repr(q) for q in qubits)\n        if self.key != _default_measurement_key(qubits):\n            args.append(f'key={self.mkey!r}')\n        if self.invert_mask:\n            args.append(f'invert_mask={self.invert_mask!r}')\n        arg_list = ', '.join(args)\n        return f'cirq.measure({arg_list})'\n\n    def __repr__(self):\n        qid_shape_arg = ''\n        if any(d != 2 for d in self._qid_shape):\n            qid_shape_arg = f', {self._qid_shape!r}'\n        return (\n            f'cirq.MeasurementGate('\n            f'{self.num_qubits()!r}, '\n            f'{self.mkey!r}, '\n            f'{self.invert_mask}'\n            f'{qid_shape_arg})'\n        )\n\n    def _value_equality_values_(self) -> Any:\n        return self.key, self.invert_mask, self._qid_shape\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        other = {}\n        if not all(d == 2 for d in self._qid_shape):\n            other['qid_shape'] = self._qid_shape\n        return {\n            'cirq_type': self.__class__.__name__,\n            'num_qubits': len(self._qid_shape),\n            'key': self.key,\n            'invert_mask': self.invert_mask,\n            **other,\n        }\n\n    @classmethod\n    def _from_json_dict_(cls, num_qubits, key, invert_mask, qid_shape=None, **kwargs):\n        return cls(\n            num_qubits=num_qubits,\n            key=value.MeasurementKey.parse_serialized(key),\n            invert_mask=tuple(invert_mask),\n            qid_shape=None if qid_shape is None else tuple(qid_shape),\n        )\n\n    def _has_stabilizer_effect_(self) -> Optional[bool]:\n        return True\n\n    def _act_on_(self, args: 'cirq.OperationTarget', qubits: Sequence['cirq.Qid']) -> bool:\n        from cirq.sim import ActOnArgs\n\n        if not isinstance(args, ActOnArgs):\n            return NotImplemented\n        args.measure(qubits, self.key, self.full_invert_mask())\n        return True\n\n\ndef _default_measurement_key(qubits: Iterable[raw_types.Qid]) -> str:\n    return ','.join(str(q) for q in qubits)\n", "path": "cirq-core/cirq/ops/measurement_gate.py"}]}