prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Make ControlledGate work with gates that only provide a decomposition
  The following should work:
  
  ```
  import cirq
  
  
  class G(cirq.TwoQubitGate):
      def _decompose_(self, qubits):
          a, b = qubits
          yield cirq.X(a)**0.5
          yield cirq.H(b)
          yield cirq.CZ(a, b)
  
  
  cg = cirq.ControlledGate(G())
  x, y, z = cirq.LineQubit.range(3)
  c = cirq.Circuit.from_ops(cg(x, y, z))
  print(c.to_unitary_matrix())
  ```
  
  but currently it raises an exception:
  
  ```
  Operation without a known matrix or decomposition: cirq.ControlledGate(sub_gate=[...G...].on(cirq.LineQubit(0), cirq.LineQubit(1), cirq.LineQubit(2))
  ```
  
  because `ControlledGate` doesn't have a `_decompose_` method. This issue is to add that method.
  
  --- 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/controlled_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, Union
  16 
  17 import numpy as np
  18 
  19 from cirq import linalg, protocols, value
  20 from cirq.ops import raw_types, controlled_operation as cop
  21 from cirq.type_workarounds import NotImplementedType
  22 
  23 
  24 @value.value_equality
  25 class ControlledGate(raw_types.Gate):
  26     """Augments existing gates with a control qubit."""
  27 
  28     def __init__(self, sub_gate: raw_types.Gate) -> None:
  29         """Initializes the controlled gate.
  30 
  31         Args:
  32             sub_gate: The gate to add a control qubit to.
  33         """
  34         self.sub_gate = sub_gate
  35 
  36     def num_qubits(self) -> int:
  37         return self.sub_gate.num_qubits() + 1
  38 
  39     def _decompose_(self, qubits):
  40         result = protocols.decompose_once_with_qubits(self.sub_gate,
  41                                                       qubits[1:],
  42                                                       NotImplemented)
  43         if result is NotImplemented:
  44             return NotImplemented
  45 
  46         return [cop.ControlledOperation(qubits[0], op) for op in result]
  47 
  48     def validate_args(self, qubits) -> None:
  49         if len(qubits) < 1:
  50             raise ValueError('No control qubit specified.')
  51         self.sub_gate.validate_args(qubits[1:])
  52 
  53     def _value_equality_values_(self):
  54         return self.sub_gate
  55 
  56     def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs) -> np.ndarray:
  57         control = args.axes[0]
  58         rest = args.axes[1:]
  59         active = linalg.slice_for_qubits_equal_to([control], 1)
  60         sub_axes = [r - int(r > control) for r in rest]
  61         target_view = args.target_tensor[active]
  62         buffer_view = args.available_buffer[active]
  63         result = protocols.apply_unitary(
  64             self.sub_gate,
  65             protocols.ApplyUnitaryArgs(
  66                 target_view,
  67                 buffer_view,
  68                 sub_axes),
  69             default=NotImplemented)
  70 
  71         if result is NotImplemented:
  72             return NotImplemented
  73 
  74         if result is target_view:
  75             return args.target_tensor
  76 
  77         if result is buffer_view:
  78             inactive = linalg.slice_for_qubits_equal_to([control], 0)
  79             args.available_buffer[inactive] = args.target_tensor[inactive]
  80             return args.available_buffer
  81 
  82         # HACK: assume they didn't somehow escape the slice view and edit the
  83         # rest of target_tensor.
  84         args.target_tensor[active] = result
  85         return args.target_tensor
  86 
  87     def _has_unitary_(self) -> bool:
  88         return protocols.has_unitary(self.sub_gate)
  89 
  90     def _unitary_(self) -> Union[np.ndarray, NotImplementedType]:
  91         sub_matrix = protocols.unitary(self.sub_gate, None)
  92         if sub_matrix is None:
  93             return NotImplemented
  94         return linalg.block_diag(np.eye(sub_matrix.shape[0]), sub_matrix)
  95 
  96     def __pow__(self, exponent: Any) -> 'ControlledGate':
  97         new_sub_gate = protocols.pow(self.sub_gate,
  98                                      exponent,
  99                                      NotImplemented)
  100         if new_sub_gate is NotImplemented:
  101             return NotImplemented
  102         return ControlledGate(new_sub_gate)
  103 
  104     def _is_parameterized_(self):
  105         return protocols.is_parameterized(self.sub_gate)
  106 
  107     def _resolve_parameters_(self, param_resolver):
  108         new_sub_gate = protocols.resolve_parameters(self.sub_gate,
  109                                                     param_resolver)
  110         return ControlledGate(new_sub_gate)
  111 
  112     def _trace_distance_bound_(self):
  113         return protocols.trace_distance_bound(self.sub_gate)
  114 
  115     def _circuit_diagram_info_(self,
  116                                args: protocols.CircuitDiagramInfoArgs
  117                                ) -> protocols.CircuitDiagramInfo:
  118         sub_info = protocols.circuit_diagram_info(self.sub_gate, args, None)
  119         if sub_info is None:
  120             return NotImplemented
  121         return protocols.CircuitDiagramInfo(
  122             wire_symbols=('@',) + sub_info.wire_symbols,
  123             exponent=sub_info.exponent)
  124 
  125     def __str__(self):
  126         return 'C' + str(self.sub_gate)
  127 
  128     def __repr__(self):
  129         return 'cirq.ControlledGate(sub_gate={!r})'.format(self.sub_gate)
  130 
  131
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/cirq/ops/controlled_gate.py b/cirq/ops/controlled_gate.py
  --- a/cirq/ops/controlled_gate.py
  +++ b/cirq/ops/controlled_gate.py
  @@ -115,7 +115,18 @@
       def _circuit_diagram_info_(self,
                                  args: protocols.CircuitDiagramInfoArgs
                                  ) -> protocols.CircuitDiagramInfo:
  -        sub_info = protocols.circuit_diagram_info(self.sub_gate, args, None)
  +        sub_args = protocols.CircuitDiagramInfoArgs(
  +            known_qubit_count=(args.known_qubit_count - 1
  +                               if args.known_qubit_count is not None else None),
  +            known_qubits=(args.known_qubits[1:]
  +                          if args.known_qubits is not None else None),
  +            use_unicode_characters=args.use_unicode_characters,
  +            precision=args.precision,
  +            qubit_map=args.qubit_map
  +        )
  +        sub_info = protocols.circuit_diagram_info(self.sub_gate,
  +                                                  sub_args,
  +                                                  None)
           if sub_info is None:
               return NotImplemented
           return protocols.CircuitDiagramInfo(
  
verification_info: {"golden_diff": "diff --git a/cirq/ops/controlled_gate.py b/cirq/ops/controlled_gate.py\n--- a/cirq/ops/controlled_gate.py\n+++ b/cirq/ops/controlled_gate.py\n@@ -115,7 +115,18 @@\n     def _circuit_diagram_info_(self,\n                                args: protocols.CircuitDiagramInfoArgs\n                                ) -> protocols.CircuitDiagramInfo:\n-        sub_info = protocols.circuit_diagram_info(self.sub_gate, args, None)\n+        sub_args = protocols.CircuitDiagramInfoArgs(\n+            known_qubit_count=(args.known_qubit_count - 1\n+                               if args.known_qubit_count is not None else None),\n+            known_qubits=(args.known_qubits[1:]\n+                          if args.known_qubits is not None else None),\n+            use_unicode_characters=args.use_unicode_characters,\n+            precision=args.precision,\n+            qubit_map=args.qubit_map\n+        )\n+        sub_info = protocols.circuit_diagram_info(self.sub_gate,\n+                                                  sub_args,\n+                                                  None)\n         if sub_info is None:\n             return NotImplemented\n         return protocols.CircuitDiagramInfo(\n", "issue": "Make ControlledGate work with gates that only provide a decomposition\nThe following should work:\r\n\r\n```\r\nimport cirq\r\n\r\n\r\nclass G(cirq.TwoQubitGate):\r\n    def _decompose_(self, qubits):\r\n        a, b = qubits\r\n        yield cirq.X(a)**0.5\r\n        yield cirq.H(b)\r\n        yield cirq.CZ(a, b)\r\n\r\n\r\ncg = cirq.ControlledGate(G())\r\nx, y, z = cirq.LineQubit.range(3)\r\nc = cirq.Circuit.from_ops(cg(x, y, z))\r\nprint(c.to_unitary_matrix())\r\n```\r\n\r\nbut currently it raises an exception:\r\n\r\n```\r\nOperation without a known matrix or decomposition: cirq.ControlledGate(sub_gate=[...G...].on(cirq.LineQubit(0), cirq.LineQubit(1), cirq.LineQubit(2))\r\n```\r\n\r\nbecause `ControlledGate` doesn't have a `_decompose_` method. This issue is to add that method.\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, Union\n\nimport numpy as np\n\nfrom cirq import linalg, protocols, value\nfrom cirq.ops import raw_types, controlled_operation as cop\nfrom cirq.type_workarounds import NotImplementedType\n\n\n@value.value_equality\nclass ControlledGate(raw_types.Gate):\n    \"\"\"Augments existing gates with a control qubit.\"\"\"\n\n    def __init__(self, sub_gate: raw_types.Gate) -> None:\n        \"\"\"Initializes the controlled gate.\n\n        Args:\n            sub_gate: The gate to add a control qubit to.\n        \"\"\"\n        self.sub_gate = sub_gate\n\n    def num_qubits(self) -> int:\n        return self.sub_gate.num_qubits() + 1\n\n    def _decompose_(self, qubits):\n        result = protocols.decompose_once_with_qubits(self.sub_gate,\n                                                      qubits[1:],\n                                                      NotImplemented)\n        if result is NotImplemented:\n            return NotImplemented\n\n        return [cop.ControlledOperation(qubits[0], op) for op in result]\n\n    def validate_args(self, qubits) -> None:\n        if len(qubits) < 1:\n            raise ValueError('No control qubit specified.')\n        self.sub_gate.validate_args(qubits[1:])\n\n    def _value_equality_values_(self):\n        return self.sub_gate\n\n    def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs) -> np.ndarray:\n        control = args.axes[0]\n        rest = args.axes[1:]\n        active = linalg.slice_for_qubits_equal_to([control], 1)\n        sub_axes = [r - int(r > control) for r in rest]\n        target_view = args.target_tensor[active]\n        buffer_view = args.available_buffer[active]\n        result = protocols.apply_unitary(\n            self.sub_gate,\n            protocols.ApplyUnitaryArgs(\n                target_view,\n                buffer_view,\n                sub_axes),\n            default=NotImplemented)\n\n        if result is NotImplemented:\n            return NotImplemented\n\n        if result is target_view:\n            return args.target_tensor\n\n        if result is buffer_view:\n            inactive = linalg.slice_for_qubits_equal_to([control], 0)\n            args.available_buffer[inactive] = args.target_tensor[inactive]\n            return args.available_buffer\n\n        # HACK: assume they didn't somehow escape the slice view and edit the\n        # rest of target_tensor.\n        args.target_tensor[active] = result\n        return args.target_tensor\n\n    def _has_unitary_(self) -> bool:\n        return protocols.has_unitary(self.sub_gate)\n\n    def _unitary_(self) -> Union[np.ndarray, NotImplementedType]:\n        sub_matrix = protocols.unitary(self.sub_gate, None)\n        if sub_matrix is None:\n            return NotImplemented\n        return linalg.block_diag(np.eye(sub_matrix.shape[0]), sub_matrix)\n\n    def __pow__(self, exponent: Any) -> 'ControlledGate':\n        new_sub_gate = protocols.pow(self.sub_gate,\n                                     exponent,\n                                     NotImplemented)\n        if new_sub_gate is NotImplemented:\n            return NotImplemented\n        return ControlledGate(new_sub_gate)\n\n    def _is_parameterized_(self):\n        return protocols.is_parameterized(self.sub_gate)\n\n    def _resolve_parameters_(self, param_resolver):\n        new_sub_gate = protocols.resolve_parameters(self.sub_gate,\n                                                    param_resolver)\n        return ControlledGate(new_sub_gate)\n\n    def _trace_distance_bound_(self):\n        return protocols.trace_distance_bound(self.sub_gate)\n\n    def _circuit_diagram_info_(self,\n                               args: protocols.CircuitDiagramInfoArgs\n                               ) -> protocols.CircuitDiagramInfo:\n        sub_info = protocols.circuit_diagram_info(self.sub_gate, args, None)\n        if sub_info is None:\n            return NotImplemented\n        return protocols.CircuitDiagramInfo(\n            wire_symbols=('@',) + sub_info.wire_symbols,\n            exponent=sub_info.exponent)\n\n    def __str__(self):\n        return 'C' + str(self.sub_gate)\n\n    def __repr__(self):\n        return 'cirq.ControlledGate(sub_gate={!r})'.format(self.sub_gate)\n\n", "path": "cirq/ops/controlled_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, Union\n\nimport numpy as np\n\nfrom cirq import linalg, protocols, value\nfrom cirq.ops import raw_types, controlled_operation as cop\nfrom cirq.type_workarounds import NotImplementedType\n\n\n@value.value_equality\nclass ControlledGate(raw_types.Gate):\n    \"\"\"Augments existing gates with a control qubit.\"\"\"\n\n    def __init__(self, sub_gate: raw_types.Gate) -> None:\n        \"\"\"Initializes the controlled gate.\n\n        Args:\n            sub_gate: The gate to add a control qubit to.\n        \"\"\"\n        self.sub_gate = sub_gate\n\n    def num_qubits(self) -> int:\n        return self.sub_gate.num_qubits() + 1\n\n    def _decompose_(self, qubits):\n        result = protocols.decompose_once_with_qubits(self.sub_gate,\n                                                      qubits[1:],\n                                                      NotImplemented)\n        if result is NotImplemented:\n            return NotImplemented\n\n        return [cop.ControlledOperation(qubits[0], op) for op in result]\n\n    def validate_args(self, qubits) -> None:\n        if len(qubits) < 1:\n            raise ValueError('No control qubit specified.')\n        self.sub_gate.validate_args(qubits[1:])\n\n    def _value_equality_values_(self):\n        return self.sub_gate\n\n    def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs) -> np.ndarray:\n        control = args.axes[0]\n        rest = args.axes[1:]\n        active = linalg.slice_for_qubits_equal_to([control], 1)\n        sub_axes = [r - int(r > control) for r in rest]\n        target_view = args.target_tensor[active]\n        buffer_view = args.available_buffer[active]\n        result = protocols.apply_unitary(\n            self.sub_gate,\n            protocols.ApplyUnitaryArgs(\n                target_view,\n                buffer_view,\n                sub_axes),\n            default=NotImplemented)\n\n        if result is NotImplemented:\n            return NotImplemented\n\n        if result is target_view:\n            return args.target_tensor\n\n        if result is buffer_view:\n            inactive = linalg.slice_for_qubits_equal_to([control], 0)\n            args.available_buffer[inactive] = args.target_tensor[inactive]\n            return args.available_buffer\n\n        # HACK: assume they didn't somehow escape the slice view and edit the\n        # rest of target_tensor.\n        args.target_tensor[active] = result\n        return args.target_tensor\n\n    def _has_unitary_(self) -> bool:\n        return protocols.has_unitary(self.sub_gate)\n\n    def _unitary_(self) -> Union[np.ndarray, NotImplementedType]:\n        sub_matrix = protocols.unitary(self.sub_gate, None)\n        if sub_matrix is None:\n            return NotImplemented\n        return linalg.block_diag(np.eye(sub_matrix.shape[0]), sub_matrix)\n\n    def __pow__(self, exponent: Any) -> 'ControlledGate':\n        new_sub_gate = protocols.pow(self.sub_gate,\n                                     exponent,\n                                     NotImplemented)\n        if new_sub_gate is NotImplemented:\n            return NotImplemented\n        return ControlledGate(new_sub_gate)\n\n    def _is_parameterized_(self):\n        return protocols.is_parameterized(self.sub_gate)\n\n    def _resolve_parameters_(self, param_resolver):\n        new_sub_gate = protocols.resolve_parameters(self.sub_gate,\n                                                    param_resolver)\n        return ControlledGate(new_sub_gate)\n\n    def _trace_distance_bound_(self):\n        return protocols.trace_distance_bound(self.sub_gate)\n\n    def _circuit_diagram_info_(self,\n                               args: protocols.CircuitDiagramInfoArgs\n                               ) -> protocols.CircuitDiagramInfo:\n        sub_args = protocols.CircuitDiagramInfoArgs(\n            known_qubit_count=(args.known_qubit_count - 1\n                               if args.known_qubit_count is not None else None),\n            known_qubits=(args.known_qubits[1:]\n                          if args.known_qubits is not None else None),\n            use_unicode_characters=args.use_unicode_characters,\n            precision=args.precision,\n            qubit_map=args.qubit_map\n        )\n        sub_info = protocols.circuit_diagram_info(self.sub_gate,\n                                                  sub_args,\n                                                  None)\n        if sub_info is None:\n            return NotImplemented\n        return protocols.CircuitDiagramInfo(\n            wire_symbols=('@',) + sub_info.wire_symbols,\n            exponent=sub_info.exponent)\n\n    def __str__(self):\n        return 'C' + str(self.sub_gate)\n\n    def __repr__(self):\n        return 'cirq.ControlledGate(sub_gate={!r})'.format(self.sub_gate)\n\n", "path": "cirq/ops/controlled_gate.py"}]}