We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ParallelGateOperation has wrong unitary
The unitary returned by `ParallelGateOperation._unitary_()` is incorrect. For example, for XX it returns a 4x4 singular (hence non-unitary) matrix and for XXX it returns a rectangular 16x4 matrix.

Unit tests don't check internal consistency of the operation.

```
In [1]: import cirq

In [2]: q0, q1, q2 = cirq.LineQubit.range(3)

In [3]: xx = cirq.ParallelGateOperation(cirq.X, (q0, q1))

In [4]: xxx = cirq.ParallelGateOperation(cirq.X, (q0, q1, q2))

In [5]: cirq.unitary(cirq.Circuit.from_ops(cirq.decompose(xx)))
Out[5]: 
array([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
       [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],
       [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
       [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])

In [6]: cirq.unitary(xx)
Out[6]: 
array([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],
       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])

In [7]: cirq.unitary(cirq.Circuit.from_ops(cirq.decompose(xxx)))
Out[7]: 
array([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])

In [8]: cirq.unitary(xxx)
Out[8]: 
array([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],
       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],
       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])

In [9]: cirq.unitary(cirq.Circuit.from_ops(cirq.decompose(xxx))).shape
Out[9]: (8, 8)

In [10]: cirq.unitary(xxx).shape
Out[10]: (16, 4)
```

Found when trying to use the operation in a new unit test for #1612.

--- 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/ops/parallel_gate_operation.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 
16 from typing import Sequence, Tuple, Union, TYPE_CHECKING, Any
17 
18 import numpy as np
19 
20 from cirq import protocols, value
21 from cirq.ops import raw_types, op_tree
22 from cirq.type_workarounds import NotImplementedType
23 
24 if TYPE_CHECKING:
25     # pylint: disable=unused-import
26     from typing import Dict, List
27 
28 
29 @value.value_equality
30 class ParallelGateOperation(raw_types.Operation):
31     """An application of several copies of a gate to a group of qubits."""
32 
33     def __init__(self,
34                  gate: raw_types.Gate,
35                  qubits: Sequence[raw_types.Qid]) -> None:
36         """
37         Args:
38             gate: the gate to apply
39             qubits: lists of lists of qubits to apply the gate to.
40         """
41         if gate.num_qubits() != 1:
42             raise ValueError("gate must be a single qubit gate")
43         if len(set(qubits)) != len(qubits):
44             raise ValueError("repeated qubits are not allowed")
45         for qubit in qubits:
46             gate.validate_args([qubit])
47         self._gate = gate
48         self._qubits = tuple(qubits)
49 
50     @property
51     def gate(self) -> raw_types.Gate:
52         """The single qubit gate applied by the operation."""
53         return self._gate
54 
55     @property
56     def qubits(self) -> Tuple[raw_types.Qid, ...]:
57         """The qubits targeted by the operation."""
58         return self._qubits
59 
60     def with_qubits(self,
61                     *new_qubits: raw_types.Qid) -> 'ParallelGateOperation':
62         """ParallelGateOperation with same the gate but new qubits"""
63         return ParallelGateOperation(self.gate, new_qubits)
64 
65     def with_gate(self, new_gate: raw_types.Gate) -> 'ParallelGateOperation':
66         """ParallelGateOperation with same qubits but a new gate"""
67         return ParallelGateOperation(new_gate, self.qubits)
68 
69     def __repr__(self):
70         return 'cirq.ParallelGateOperation(gate={!r}, qubits={!r})'.format(
71             self.gate,
72             list(self.qubits))
73 
74     def __str__(self):
75         return '{}({})'.format(self.gate,
76                                ', '.join(str(e) for e in self.qubits))
77 
78     def _value_equality_values_(self):
79         return self.gate, frozenset(self.qubits)
80 
81     def _decompose_(self) -> op_tree.OP_TREE:
82         """List of gate operations that correspond to applying the single qubit
83            gate to each of the target qubits individually
84         """
85         return [self.gate.on(qubit) for qubit in self.qubits]
86 
87     def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs
88                         ) -> Union[np.ndarray, None, NotImplementedType]:
89         """Replicates the logic the simulators use to apply the equivalent
90            sequence of GateOperations
91         """
92         state = args.target_tensor
93         buffer = args.available_buffer
94         for axis in args.axes:
95             result = protocols.apply_unitary(self.gate,
96                                              protocols.ApplyUnitaryArgs(
97                                                  state,
98                                                  buffer,
99                                                  (axis,)),
100                                              default=NotImplemented)
101 
102             if result is buffer:
103                 buffer = state
104 
105             state = result
106 
107         return state
108 
109     def _has_unitary_(self) -> bool:
110         return protocols.has_unitary(self.gate)
111 
112     def _unitary_(self) -> Union[np.ndarray, NotImplementedType]:
113         # Obtain the unitary for the single qubit gate
114         single_unitary = protocols.unitary(self.gate, NotImplemented)
115 
116         # Make sure we actually have a matrix
117         if single_unitary is NotImplemented:
118             return single_unitary
119 
120         # Create a unitary which corresponds to applying the single qubit
121         # unitary to each qubit. This will blow up memory fast.
122         unitary = single_unitary
123         for _ in range(len(self.qubits) - 1):
124             unitary = np.outer(unitary, single_unitary)
125 
126         return unitary
127 
128     def _is_parameterized_(self) -> bool:
129         return protocols.is_parameterized(self.gate)
130 
131     def _resolve_parameters_(self, resolver):
132         resolved_gate = protocols.resolve_parameters(self.gate, resolver)
133         return self.with_gate(resolved_gate)
134 
135     def _circuit_diagram_info_(self,
136                                args: protocols.CircuitDiagramInfoArgs
137                                ) -> protocols.CircuitDiagramInfo:
138         diagram_info = protocols.circuit_diagram_info(self.gate,
139                                                       args,
140                                                       NotImplemented)
141         if diagram_info == NotImplemented:
142             return diagram_info
143 
144         # Include symbols for every qubit instead of just one
145         symbol = diagram_info.wire_symbols[0]
146         wire_symbols = (symbol,) * len(self.qubits)
147 
148         return protocols.CircuitDiagramInfo(wire_symbols=wire_symbols,
149                                             exponent=diagram_info.exponent,
150                                             connected=False)
151 
152     def _phase_by_(self, phase_turns: float,
153                    qubit_index: int) -> 'ParallelGateOperation':
154         phased_gate = protocols.phase_by(self._gate, phase_turns, qubit_index,
155                                          default=None)
156         if phased_gate is None:
157             return NotImplemented
158         return self.with_gate(phased_gate)
159 
160     def __pow__(self, exponent: Any) -> 'ParallelGateOperation':
161         """Raise gate to a power, then reapply to the same qubits.
162 
163         Only works if the gate implements cirq.ExtrapolatableEffect.
164 
165         For extrapolatable gate G this means the following two are equivalent:
166 
167             (G ** 1.5)(qubit)  or  G(qubit) ** 1.5
168 
169         Args:
170             exponent: The amount to scale the gate's effect by.
171 
172         Returns:
173             A new operation on the same qubits with the scaled gate.
174         """
175         new_gate = protocols.pow(self.gate,
176                                  exponent,
177                                  NotImplemented)
178         if new_gate is NotImplemented:
179             return NotImplemented
180         return self.with_gate(new_gate)
181
```
--- 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/ops/parallel_gate_operation.py b/cirq/ops/parallel_gate_operation.py
--- a/cirq/ops/parallel_gate_operation.py
+++ b/cirq/ops/parallel_gate_operation.py
@@ -121,7 +121,7 @@
         # unitary to each qubit. This will blow up memory fast.
         unitary = single_unitary
         for _ in range(len(self.qubits) - 1):
-            unitary = np.outer(unitary, single_unitary)
+            unitary = np.kron(unitary, single_unitary)
 
         return unitary
 
@@ -149,14 +149,6 @@
                                             exponent=diagram_info.exponent,
                                             connected=False)
 
-    def _phase_by_(self, phase_turns: float,
-                   qubit_index: int) -> 'ParallelGateOperation':
-        phased_gate = protocols.phase_by(self._gate, phase_turns, qubit_index,
-                                         default=None)
-        if phased_gate is None:
-            return NotImplemented
-        return self.with_gate(phased_gate)
-
     def __pow__(self, exponent: Any) -> 'ParallelGateOperation':
         """Raise gate to a power, then reapply to the same qubits.

{"golden_diff": "diff --git a/cirq/ops/parallel_gate_operation.py b/cirq/ops/parallel_gate_operation.py\n--- a/cirq/ops/parallel_gate_operation.py\n+++ b/cirq/ops/parallel_gate_operation.py\n@@ -121,7 +121,7 @@\n         # unitary to each qubit. This will blow up memory fast.\n         unitary = single_unitary\n         for _ in range(len(self.qubits) - 1):\n-            unitary = np.outer(unitary, single_unitary)\n+            unitary = np.kron(unitary, single_unitary)\n \n         return unitary\n \n@@ -149,14 +149,6 @@\n                                             exponent=diagram_info.exponent,\n                                             connected=False)\n \n-    def _phase_by_(self, phase_turns: float,\n-                   qubit_index: int) -> 'ParallelGateOperation':\n-        phased_gate = protocols.phase_by(self._gate, phase_turns, qubit_index,\n-                                         default=None)\n-        if phased_gate is None:\n-            return NotImplemented\n-        return self.with_gate(phased_gate)\n-\n     def __pow__(self, exponent: Any) -> 'ParallelGateOperation':\n         \"\"\"Raise gate to a power, then reapply to the same qubits.\n", "issue": "ParallelGateOperation has wrong unitary\nThe unitary returned by `ParallelGateOperation._unitary_()` is incorrect. For example, for XX it returns a 4x4 singular (hence non-unitary) matrix and for XXX it returns a rectangular 16x4 matrix.\r\n\r\nUnit tests don't check internal consistency of the operation.\r\n\r\n```\r\nIn [1]: import cirq\r\n\r\nIn [2]: q0, q1, q2 = cirq.LineQubit.range(3)\r\n\r\nIn [3]: xx = cirq.ParallelGateOperation(cirq.X, (q0, q1))\r\n\r\nIn [4]: xxx = cirq.ParallelGateOperation(cirq.X, (q0, q1, q2))\r\n\r\nIn [5]: cirq.unitary(cirq.Circuit.from_ops(cirq.decompose(xx)))\r\nOut[5]: \r\narray([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\r\n       [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],\r\n       [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\r\n       [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])\r\n\r\nIn [6]: cirq.unitary(xx)\r\nOut[6]: \r\narray([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],\r\n       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])\r\n\r\nIn [7]: cirq.unitary(cirq.Circuit.from_ops(cirq.decompose(xxx)))\r\nOut[7]: \r\narray([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])\r\n\r\nIn [8]: cirq.unitary(xxx)\r\nOut[8]: \r\narray([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],\r\n       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],\r\n       [0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\r\n       [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])\r\n\r\nIn [9]: cirq.unitary(cirq.Circuit.from_ops(cirq.decompose(xxx))).shape\r\nOut[9]: (8, 8)\r\n\r\nIn [10]: cirq.unitary(xxx).shape\r\nOut[10]: (16, 4)\r\n```\r\n\r\nFound when trying to use the operation in a new unit test for #1612.\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\nfrom typing import Sequence, Tuple, Union, TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom cirq import protocols, value\nfrom cirq.ops import raw_types, op_tree\nfrom cirq.type_workarounds import NotImplementedType\n\nif TYPE_CHECKING:\n    # pylint: disable=unused-import\n    from typing import Dict, List\n\n\n@value.value_equality\nclass ParallelGateOperation(raw_types.Operation):\n    \"\"\"An application of several copies of a gate to a group of qubits.\"\"\"\n\n    def __init__(self,\n                 gate: raw_types.Gate,\n                 qubits: Sequence[raw_types.Qid]) -> None:\n        \"\"\"\n        Args:\n            gate: the gate to apply\n            qubits: lists of lists of qubits to apply the gate to.\n        \"\"\"\n        if gate.num_qubits() != 1:\n            raise ValueError(\"gate must be a single qubit gate\")\n        if len(set(qubits)) != len(qubits):\n            raise ValueError(\"repeated qubits are not allowed\")\n        for qubit in qubits:\n            gate.validate_args([qubit])\n        self._gate = gate\n        self._qubits = tuple(qubits)\n\n    @property\n    def gate(self) -> raw_types.Gate:\n        \"\"\"The single qubit gate applied by the operation.\"\"\"\n        return self._gate\n\n    @property\n    def qubits(self) -> Tuple[raw_types.Qid, ...]:\n        \"\"\"The qubits targeted by the operation.\"\"\"\n        return self._qubits\n\n    def with_qubits(self,\n                    *new_qubits: raw_types.Qid) -> 'ParallelGateOperation':\n        \"\"\"ParallelGateOperation with same the gate but new qubits\"\"\"\n        return ParallelGateOperation(self.gate, new_qubits)\n\n    def with_gate(self, new_gate: raw_types.Gate) -> 'ParallelGateOperation':\n        \"\"\"ParallelGateOperation with same qubits but a new gate\"\"\"\n        return ParallelGateOperation(new_gate, self.qubits)\n\n    def __repr__(self):\n        return 'cirq.ParallelGateOperation(gate={!r}, qubits={!r})'.format(\n            self.gate,\n            list(self.qubits))\n\n    def __str__(self):\n        return '{}({})'.format(self.gate,\n                               ', '.join(str(e) for e in self.qubits))\n\n    def _value_equality_values_(self):\n        return self.gate, frozenset(self.qubits)\n\n    def _decompose_(self) -> op_tree.OP_TREE:\n        \"\"\"List of gate operations that correspond to applying the single qubit\n           gate to each of the target qubits individually\n        \"\"\"\n        return [self.gate.on(qubit) for qubit in self.qubits]\n\n    def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs\n                        ) -> Union[np.ndarray, None, NotImplementedType]:\n        \"\"\"Replicates the logic the simulators use to apply the equivalent\n           sequence of GateOperations\n        \"\"\"\n        state = args.target_tensor\n        buffer = args.available_buffer\n        for axis in args.axes:\n            result = protocols.apply_unitary(self.gate,\n                                             protocols.ApplyUnitaryArgs(\n                                                 state,\n                                                 buffer,\n                                                 (axis,)),\n                                             default=NotImplemented)\n\n            if result is buffer:\n                buffer = state\n\n            state = result\n\n        return state\n\n    def _has_unitary_(self) -> bool:\n        return protocols.has_unitary(self.gate)\n\n    def _unitary_(self) -> Union[np.ndarray, NotImplementedType]:\n        # Obtain the unitary for the single qubit gate\n        single_unitary = protocols.unitary(self.gate, NotImplemented)\n\n        # Make sure we actually have a matrix\n        if single_unitary is NotImplemented:\n            return single_unitary\n\n        # Create a unitary which corresponds to applying the single qubit\n        # unitary to each qubit. This will blow up memory fast.\n        unitary = single_unitary\n        for _ in range(len(self.qubits) - 1):\n            unitary = np.outer(unitary, single_unitary)\n\n        return unitary\n\n    def _is_parameterized_(self) -> bool:\n        return protocols.is_parameterized(self.gate)\n\n    def _resolve_parameters_(self, resolver):\n        resolved_gate = protocols.resolve_parameters(self.gate, resolver)\n        return self.with_gate(resolved_gate)\n\n    def _circuit_diagram_info_(self,\n                               args: protocols.CircuitDiagramInfoArgs\n                               ) -> protocols.CircuitDiagramInfo:\n        diagram_info = protocols.circuit_diagram_info(self.gate,\n                                                      args,\n                                                      NotImplemented)\n        if diagram_info == NotImplemented:\n            return diagram_info\n\n        # Include symbols for every qubit instead of just one\n        symbol = diagram_info.wire_symbols[0]\n        wire_symbols = (symbol,) * len(self.qubits)\n\n        return protocols.CircuitDiagramInfo(wire_symbols=wire_symbols,\n                                            exponent=diagram_info.exponent,\n                                            connected=False)\n\n    def _phase_by_(self, phase_turns: float,\n                   qubit_index: int) -> 'ParallelGateOperation':\n        phased_gate = protocols.phase_by(self._gate, phase_turns, qubit_index,\n                                         default=None)\n        if phased_gate is None:\n            return NotImplemented\n        return self.with_gate(phased_gate)\n\n    def __pow__(self, exponent: Any) -> 'ParallelGateOperation':\n        \"\"\"Raise gate to a power, then reapply to the same qubits.\n\n        Only works if the gate implements cirq.ExtrapolatableEffect.\n\n        For extrapolatable gate G this means the following two are equivalent:\n\n            (G ** 1.5)(qubit)  or  G(qubit) ** 1.5\n\n        Args:\n            exponent: The amount to scale the gate's effect by.\n\n        Returns:\n            A new operation on the same qubits with the scaled gate.\n        \"\"\"\n        new_gate = protocols.pow(self.gate,\n                                 exponent,\n                                 NotImplemented)\n        if new_gate is NotImplemented:\n            return NotImplemented\n        return self.with_gate(new_gate)\n", "path": "cirq/ops/parallel_gate_operation.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\nfrom typing import Sequence, Tuple, Union, TYPE_CHECKING, Any\n\nimport numpy as np\n\nfrom cirq import protocols, value\nfrom cirq.ops import raw_types, op_tree\nfrom cirq.type_workarounds import NotImplementedType\n\nif TYPE_CHECKING:\n    # pylint: disable=unused-import\n    from typing import Dict, List\n\n\n@value.value_equality\nclass ParallelGateOperation(raw_types.Operation):\n    \"\"\"An application of several copies of a gate to a group of qubits.\"\"\"\n\n    def __init__(self,\n                 gate: raw_types.Gate,\n                 qubits: Sequence[raw_types.Qid]) -> None:\n        \"\"\"\n        Args:\n            gate: the gate to apply\n            qubits: lists of lists of qubits to apply the gate to.\n        \"\"\"\n        if gate.num_qubits() != 1:\n            raise ValueError(\"gate must be a single qubit gate\")\n        if len(set(qubits)) != len(qubits):\n            raise ValueError(\"repeated qubits are not allowed\")\n        for qubit in qubits:\n            gate.validate_args([qubit])\n        self._gate = gate\n        self._qubits = tuple(qubits)\n\n    @property\n    def gate(self) -> raw_types.Gate:\n        \"\"\"The single qubit gate applied by the operation.\"\"\"\n        return self._gate\n\n    @property\n    def qubits(self) -> Tuple[raw_types.Qid, ...]:\n        \"\"\"The qubits targeted by the operation.\"\"\"\n        return self._qubits\n\n    def with_qubits(self,\n                    *new_qubits: raw_types.Qid) -> 'ParallelGateOperation':\n        \"\"\"ParallelGateOperation with same the gate but new qubits\"\"\"\n        return ParallelGateOperation(self.gate, new_qubits)\n\n    def with_gate(self, new_gate: raw_types.Gate) -> 'ParallelGateOperation':\n        \"\"\"ParallelGateOperation with same qubits but a new gate\"\"\"\n        return ParallelGateOperation(new_gate, self.qubits)\n\n    def __repr__(self):\n        return 'cirq.ParallelGateOperation(gate={!r}, qubits={!r})'.format(\n            self.gate,\n            list(self.qubits))\n\n    def __str__(self):\n        return '{}({})'.format(self.gate,\n                               ', '.join(str(e) for e in self.qubits))\n\n    def _value_equality_values_(self):\n        return self.gate, frozenset(self.qubits)\n\n    def _decompose_(self) -> op_tree.OP_TREE:\n        \"\"\"List of gate operations that correspond to applying the single qubit\n           gate to each of the target qubits individually\n        \"\"\"\n        return [self.gate.on(qubit) for qubit in self.qubits]\n\n    def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs\n                        ) -> Union[np.ndarray, None, NotImplementedType]:\n        \"\"\"Replicates the logic the simulators use to apply the equivalent\n           sequence of GateOperations\n        \"\"\"\n        state = args.target_tensor\n        buffer = args.available_buffer\n        for axis in args.axes:\n            result = protocols.apply_unitary(self.gate,\n                                             protocols.ApplyUnitaryArgs(\n                                                 state,\n                                                 buffer,\n                                                 (axis,)),\n                                             default=NotImplemented)\n\n            if result is buffer:\n                buffer = state\n\n            state = result\n\n        return state\n\n    def _has_unitary_(self) -> bool:\n        return protocols.has_unitary(self.gate)\n\n    def _unitary_(self) -> Union[np.ndarray, NotImplementedType]:\n        # Obtain the unitary for the single qubit gate\n        single_unitary = protocols.unitary(self.gate, NotImplemented)\n\n        # Make sure we actually have a matrix\n        if single_unitary is NotImplemented:\n            return single_unitary\n\n        # Create a unitary which corresponds to applying the single qubit\n        # unitary to each qubit. This will blow up memory fast.\n        unitary = single_unitary\n        for _ in range(len(self.qubits) - 1):\n            unitary = np.kron(unitary, single_unitary)\n\n        return unitary\n\n    def _is_parameterized_(self) -> bool:\n        return protocols.is_parameterized(self.gate)\n\n    def _resolve_parameters_(self, resolver):\n        resolved_gate = protocols.resolve_parameters(self.gate, resolver)\n        return self.with_gate(resolved_gate)\n\n    def _circuit_diagram_info_(self,\n                               args: protocols.CircuitDiagramInfoArgs\n                               ) -> protocols.CircuitDiagramInfo:\n        diagram_info = protocols.circuit_diagram_info(self.gate,\n                                                      args,\n                                                      NotImplemented)\n        if diagram_info == NotImplemented:\n            return diagram_info\n\n        # Include symbols for every qubit instead of just one\n        symbol = diagram_info.wire_symbols[0]\n        wire_symbols = (symbol,) * len(self.qubits)\n\n        return protocols.CircuitDiagramInfo(wire_symbols=wire_symbols,\n                                            exponent=diagram_info.exponent,\n                                            connected=False)\n\n    def __pow__(self, exponent: Any) -> 'ParallelGateOperation':\n        \"\"\"Raise gate to a power, then reapply to the same qubits.\n\n        Only works if the gate implements cirq.ExtrapolatableEffect.\n\n        For extrapolatable gate G this means the following two are equivalent:\n\n            (G ** 1.5)(qubit)  or  G(qubit) ** 1.5\n\n        Args:\n            exponent: The amount to scale the gate's effect by.\n\n        Returns:\n            A new operation on the same qubits with the scaled gate.\n        \"\"\"\n        new_gate = protocols.pow(self.gate,\n                                 exponent,\n                                 NotImplemented)\n        if new_gate is NotImplemented:\n            return NotImplemented\n        return self.with_gate(new_gate)\n", "path": "cirq/ops/parallel_gate_operation.py"}]}