def _convert_one(self, op: ops.Operation) -> ops.OP_TREE: # Check if this is a CZ # Only keep partial CZ gates if allow_partial_czs if (isinstance(op, ops.GateOperation) and isinstance(op.gate, ops.Rot11Gate) and (self.allow_partial_czs or op.gate.half_turns == 1)): return op # Known matrix? mat = self.extensions.try_cast(ops.KnownMatrix, op) if mat is not None and len(op.qubits) == 1: return op if mat is not None and len(op.qubits) == 2: return decompositions.two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], mat.matrix(), allow_partial_czs=False) # Provides a decomposition? composite_op = self.extensions.try_cast(ops.CompositeOperation, op) if composite_op is not None: return composite_op.default_decompose() # Just let it be? if self.ignore_failures: return op raise TypeError("Don't know how to work with {!r}. " "It isn't a 1-qubit KnownMatrix, " "a 2-qubit KnownMatrix, " "or a CompositeOperation.".format(op))
def _convert_one(self, op: ops.Operation) -> ops.OP_TREE: # Check if this is a CZ # Only keep partial CZ gates if allow_partial_czs if (isinstance(op, ops.GateOperation) and isinstance(op.gate, ops.CZPowGate) and (self.allow_partial_czs or op.gate.exponent == 1)): return op # Measurement? if ops.MeasurementGate.is_measurement(op): return op # Known matrix? mat = protocols.unitary(op, None) if mat is not None and len(op.qubits) == 1: return op if mat is not None and len(op.qubits) == 2: return decompositions.two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], mat, allow_partial_czs=False) # Provides a decomposition? decomposed = protocols.decompose_once(op, None) if decomposed is not None: return decomposed # Just let it be? if self.ignore_failures: return op raise TypeError("Don't know how to work with {!r}. " "It isn't composite or an operation with a " "known unitary effect on 1 or 2 qubits.".format(op))
def _decompose_two_qubit_unitaries(self, op: ops.Operation) -> ops.OP_TREE: # Known matrix? if len(op.qubits) == 2: mat = protocols.unitary(op, None) if mat is not None: return decompositions.two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], mat, allow_partial_czs=self.allow_partial_czs) return NotImplemented
def _convert_one(self, op: ops.Operation) -> ops.OP_TREE: # Known matrix? mat = protocols.unitary(op, None) if len(op.qubits) <= 2 else None if mat is not None and len(op.qubits) == 1: gates = single_qubit_matrix_to_native_gates(mat) return [g.on(op.qubits[0]) for g in gates] if mat is not None and len(op.qubits) == 2: return two_qubit_matrix_to_operations(op.qubits[0], op.qubits[1], mat, allow_partial_czs=True) return NotImplemented
def optimization_at(self, circuit: Circuit, index: int, op: ops.Operation ) -> Optional[optimization_pass.PointOptimizationSummary]: if len(op.qubits) != 2: return None old_operations, indices, matrix = ( self._scan_two_qubit_ops_into_matrix(circuit, index, op.qubits)) old_interaction_count = len([old_op for old_op in old_operations if len(old_op.qubits) == 2]) switch_to_new = False switch_to_new |= any(len(old_op.qubits) == 2 and not (isinstance(old_op, ops.GateOperation) and isinstance(old_op.gate, ops.CZPowGate)) for old_op in old_operations) if not self.allow_partial_czs: switch_to_new |= any(isinstance(old_op, ops.GateOperation) and isinstance(old_op.gate, ops.CZPowGate) and old_op.gate.exponent != 1 for old_op in old_operations) # This point cannot be optimized using this method if not switch_to_new and old_interaction_count <= 1: return None # Find a max-3-cz construction. new_operations = decompositions.two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], matrix, self.allow_partial_czs, self.tolerance) new_interaction_count = len([new_op for new_op in new_operations if len(new_op.qubits) == 2]) switch_to_new |= new_interaction_count < old_interaction_count if not switch_to_new: return None return optimization_pass.PointOptimizationSummary( clear_span=max(indices) + 1 - index, clear_qubits=op.qubits, new_operations=new_operations)
def optimization_at(self, circuit: circuits.Circuit, index: int, op: ops.Operation ) -> Optional[circuits.PointOptimizationSummary]: if len(op.qubits) != 2: return None old_operations, indices, matrix = ( self._scan_two_qubit_ops_into_matrix(circuit, index, op.qubits)) # Find a max-3-cz construction. new_operations = decompositions.two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], matrix, self.allow_partial_czs, self.tolerance) old_interaction_count = len([old_op for old_op in old_operations if len(old_op.qubits) == 2]) new_interaction_count = len([new_op for new_op in new_operations if len(new_op.qubits) == 2]) switch_to_new = False switch_to_new |= new_interaction_count < old_interaction_count switch_to_new |= any(not xmon_gates.XmonGate.is_xmon_op(old_op) for old_op in old_operations) if not self.allow_partial_czs: switch_to_new |= any(isinstance(old_op, ops.GateOperation) and isinstance(old_op.gate, xmon_gates.Exp11Gate) and old_op.gate.half_turns != 1 for old_op in old_operations) if not switch_to_new: return None converter = convert_to_xmon_gates.ConvertToXmonGates() new_xmon_operations = [converter.convert(new_op) for new_op in new_operations] return circuits.PointOptimizationSummary( clear_span=max(indices) + 1 - index, clear_qubits=op.qubits, new_operations=new_xmon_operations)
def _convert_one(self, op: ops.Operation) -> ops.OP_TREE: # Maybe we know how to wrap it? if isinstance(op, ops.GateOperation): xmon = xmon_gate_ext.try_cast(XmonGate, op.gate) # type: ignore if xmon is not None: return xmon.on(*op.qubits) # Known matrix? mat = protocols.unitary(op, None) if len(op.qubits) <= 2 else None if mat is not None and len(op.qubits) == 1: gates = single_qubit_matrix_to_native_gates(mat) return [g.on(op.qubits[0]) for g in gates] if mat is not None and len(op.qubits) == 2: return two_qubit_matrix_to_operations(op.qubits[0], op.qubits[1], mat, allow_partial_czs=True) return NotImplemented
def optimization_at( self, circuit: circuits.Circuit, index: int, op: ops.Operation) -> Optional[circuits.PointOptimizationSummary]: if len(op.qubits) != 2: return None old_operations, indices, matrix = ( self._scan_two_qubit_ops_into_matrix(circuit, index, op.qubits)) # Find a max-3-cz construction. new_operations = decompositions.two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], matrix, self.allow_partial_czs, self.tolerance) old_interaction_count = len( [old_op for old_op in old_operations if len(old_op.qubits) == 2]) new_interaction_count = len( [new_op for new_op in new_operations if len(new_op.qubits) == 2]) switch_to_new = False switch_to_new |= new_interaction_count < old_interaction_count switch_to_new |= any(not xmon_gates.XmonGate.is_xmon_op(old_op) for old_op in old_operations) if not self.allow_partial_czs: switch_to_new |= any( isinstance(old_op, ops.GateOperation) and isinstance(old_op.gate, xmon_gates.Exp11Gate) and old_op.gate.half_turns != 1 for old_op in old_operations) if not switch_to_new: return None converter = convert_to_xmon_gates.ConvertToXmonGates() new_xmon_operations = [ converter.convert(new_op) for new_op in new_operations ] return circuits.PointOptimizationSummary( clear_span=max(indices) + 1 - index, clear_qubits=op.qubits, new_operations=new_xmon_operations)
def intercept_decompose_func(self, op: Union[ops.Operation, circuits.Circuit] ) -> ops.OP_TREE: if not isinstance(op, ops.Operation): return NotImplemented # Drop measurements. if ops.MeasurementGate.is_measurement(op): return [] # Immediately completely decompose two qubit unitary operations. if len(op.qubits) == 2: m = protocols.unitary(op, None) if m is not None: return decompositions.two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], mat=m, allow_partial_czs=False ) # Fallback to default. return NotImplemented
def _convert_one(self, op: ops.Operation) -> ops.OP_TREE: # Already supported? if isinstance(op, ops.GateOperation) and isinstance(op.gate, XmonGate): return op # Maybe we know how to wrap it? if isinstance(op, ops.GateOperation): xmon = self.extensions.try_cast(XmonGate, op.gate) if xmon is not None: return xmon.on(*op.qubits) # Known matrix? mat = self.extensions.try_cast(ops.KnownMatrix, op) if mat is not None and len(op.qubits) == 1: gates = single_qubit_matrix_to_native_gates(mat.matrix()) return [g.on(op.qubits[0]) for g in gates] if mat is not None and len(op.qubits) == 2: return two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], mat.matrix(), allow_partial_czs=True) # Provides a decomposition? composite_op = self.extensions.try_cast(ops.CompositeOperation, op) if composite_op is not None: return composite_op.default_decompose() # Just let it be? if self.ignore_failures: return op raise TypeError("Don't know how to work with {!r}. " "It isn't a GateOperation with an XmonGate, " "a 1-qubit KnownMatrix, " "a 2-qubit KnownMatrix, " "or a CompositeOperation.".format(op))
def _convert_one(self, op: ops.Operation) -> ops.OP_TREE: # Already supported? if isinstance(op, ops.GateOperation) and isinstance(op.gate, XmonGate): return op # Maybe we know how to wrap it? if isinstance(op, ops.GateOperation): xmon = self.extensions.try_cast(XmonGate, op.gate) if xmon is not None: return xmon.on(*op.qubits) # Known matrix? mat = self.extensions.try_cast(ops.KnownMatrix, op) if mat is not None and len(op.qubits) == 1: gates = single_qubit_matrix_to_native_gates(mat.matrix()) return [g.on(op.qubits[0]) for g in gates] if mat is not None and len(op.qubits) == 2: return two_qubit_matrix_to_operations(op.qubits[0], op.qubits[1], mat.matrix(), allow_partial_czs=True) # Provides a decomposition? composite_op = self.extensions.try_cast(ops.CompositeOperation, op) if composite_op is not None: return composite_op.default_decompose() # Just let it be? if self.ignore_failures: return op raise TypeError("Don't know how to work with {!r}. " "It isn't a GateOperation with an XmonGate, " "a 1-qubit KnownMatrix, " "a 2-qubit KnownMatrix, " "or a CompositeOperation.".format(op))
def _convert_one(self, op: ops.Operation) -> ops.OP_TREE: # Already supported? if XmonGate.is_supported_op(op): return op # Maybe we know how to wrap it? if isinstance(op, ops.GateOperation): xmon = xmon_gate_ext.try_cast(XmonGate, op.gate) # type: ignore if xmon is not None: return xmon.on(*op.qubits) # Known matrix? mat = protocols.unitary(op, None) if len(op.qubits) <= 2 else None if mat is not None and len(op.qubits) == 1: gates = single_qubit_matrix_to_native_gates(mat) return [g.on(op.qubits[0]) for g in gates] if mat is not None and len(op.qubits) == 2: return two_qubit_matrix_to_operations(op.qubits[0], op.qubits[1], mat, allow_partial_czs=True) # Provides a decomposition? composite_op = xmon_gate_ext.try_cast( # type: ignore ops.CompositeOperation, op) if composite_op is not None: return composite_op.default_decompose() # Just let it be? if self.ignore_failures: return op raise TypeError("Don't know how to work with {!r}. " "It isn't a GateOperation with an XmonGate, " "a 1 or 2 qubit gate with a known unitary, " "or a CompositeOperation.".format(op))