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. 14from typing import List, Optional 15 16import cirq 17 18 19class ConvertToXmonGates(cirq.PointOptimizer): 20 """Attempts to convert strange gates into XmonGates. 21 22 First, checks if the given operation is already a native xmon operation. 23 24 Second, checks if the operation has a known unitary. If so, and the gate 25 is a 1-qubit or 2-qubit gate, then performs circuit synthesis of the 26 operation. 27 28 Third, attempts to `cirq.decompose` to the operation. 29 30 Fourth, if ignore_failures is set, gives up and returns the gate unchanged. 31 Otherwise raises a TypeError. 32 """ 33 34 def __init__(self, ignore_failures=False) -> None: 35 """Inits ConvertToXmonGates. 36 37 Args: 38 ignore_failures: If set, gates that fail to convert are forwarded 39 unchanged. If not set, conversion failures raise a TypeError. 40 """ 41 super().__init__() 42 self.ignore_failures = ignore_failures 43 44 def _convert_one(self, op: cirq.Operation) -> cirq.OP_TREE: 45 # Known matrix? 46 mat = cirq.unitary(op, None) if len(op.qubits) <= 2 else None 47 if mat is not None and len(op.qubits) == 1: 48 gates = cirq.single_qubit_matrix_to_phased_x_z(mat) 49 return [g.on(op.qubits[0]) for g in gates] 50 if mat is not None and len(op.qubits) == 2: 51 return cirq.two_qubit_matrix_to_operations( 52 op.qubits[0], op.qubits[1], mat, allow_partial_czs=True, clean_operations=False 53 ) 54 55 return NotImplemented 56 57 def _is_native_xmon_op(self, op: cirq.Operation) -> bool: 58 """Check if the gate within an operation is a native xmon gate. 59 60 Args: 61 op: Input operation. 62 63 Returns: 64 True if the operation is native to the xmon, false otherwise. 65 """ 66 from cirq_google.devices import XmonDevice 67 68 return op.gate is not None and XmonDevice.is_supported_gate(op.gate) 69 70 def convert(self, op: cirq.Operation) -> List[cirq.Operation]: 71 def on_stuck_raise(bad): 72 return TypeError( 73 "Don't know how to work with {!r}. " 74 "It isn't a native xmon operation, " 75 "a 1 or 2 qubit gate with a known unitary, " 76 "or composite.".format(bad) 77 ) 78 79 return cirq.decompose( 80 op, 81 keep=self._is_native_xmon_op, 82 intercepting_decomposer=self._convert_one, 83 on_stuck_raise=None if self.ignore_failures else on_stuck_raise, 84 ) 85 86 def optimization_at( 87 self, circuit: cirq.Circuit, index: int, op: cirq.Operation 88 ) -> Optional[cirq.PointOptimizationSummary]: 89 if op.gate is None: 90 return None 91 92 converted = self.convert(op) 93 if len(converted) == 1 and converted[0] is op: 94 return None 95 96 return cirq.PointOptimizationSummary( 97 clear_span=1, new_operations=converted, clear_qubits=op.qubits 98 ) 99