def _write_operations(self, op_tree: ops.OP_TREE, output: Callable[[str], None], output_line_gap: Callable[[int], None], top=True) -> None: for op in ops.flatten_op_tree(op_tree): qasm_op = extension.try_cast( # type: ignore ops.QasmConvertibleOperation, op) if qasm_op is not None: out = qasm_op.known_qasm_output(self.args) if out is not None: output(out) continue if isinstance(op, ops.GateOperation): comment = 'Gate: {!s}'.format(op.gate) else: comment = 'Operation: {!s}'.format(op) comp_op = extension.try_cast( # type: ignore ops.CompositeOperation, op) if comp_op is not None: if top: output_line_gap(1) output('// {}\n'.format(comment)) self._write_operations(comp_op.default_decompose(), output, output_line_gap, top=False) if top: output_line_gap(1) continue mat = protocols.unitary(op, None) if len(op.qubits) <= 2 else None if mat is not None and len(op.qubits) == 1: u_op = QasmUGate.from_matrix(mat).on(*op.qubits) if top: output_line_gap(1) output('// {}\n'.format(comment)) output(cast(str, u_op.known_qasm_output(self.args))) if top: output_line_gap(1) continue if mat is not None and len(op.qubits) == 2: u_op = QasmTwoQubitGate.from_matrix(mat).on(*op.qubits) if top: output_line_gap(1) output('// {}\n'.format(comment)) self._write_operations((u_op, ), output, output_line_gap, top=False) if top: output_line_gap(1) continue raise ValueError( 'Cannot output operation as QASM: {!r}'.format(op))
def _convert_one(self, op: ops.Operation) -> ops.OP_TREE: # Don't change if it's already a SingleQubitCliffordGate if (isinstance(op, ops.GateOperation) and isinstance(op.gate, ops.SingleQubitCliffordGate)): return op # Single qubit gate with known matrix? if len(op.qubits) == 1: mat = protocols.unitary(op, None) if mat is not None: cliff_op = self._matrix_to_clifford_op(mat, op.qubits[0]) if cliff_op is not None: return cliff_op if self.ignore_failures: return op raise ValueError('Single qubit operation is not in the ' 'Clifford group: {!r}'.format(op)) # Provides a decomposition? composite_op = extension.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 CompositeOperation or a 1-qubit operation " "with a known unitary effect.".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.Rot11Gate) and (self.allow_partial_czs or op.gate.half_turns == 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? composite_op = extension.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 CompositeOperation or an operation with a " "known unitary effect on 1 or 2 qubits.".format(op))
def decompose_depth(*operations, d=1): if d <= 0: yield from operations return for op in ops.flatten_op_tree(operations): composite_op = extension.try_cast(ops.CompositeOperation, op) if composite_op is not None: yield from decompose_depth(composite_op.default_decompose(), d=d-1) else: yield op
def inverse(val: Any, default: Any = RaiseTypeErrorIfNotProvided) -> Any: """Returns the inverse `val**-1` of the given value, if defined. An object can define an inverse by defining a __pow__(self, exponent) method that returns something besides NotImplemented when given the exponent -1. The inverse of iterables is by default defined to be the iterable's items, each inverted, in reverse order. Args: val: The value (or iterable of invertable values) to invert. default: Determines the fallback behavior when `val` doesn't have an inverse defined. If `default` is not set, a TypeError is raised. If `default` is set to a value, that value is returned. Returns: If `val` has a __pow__ method that returns something besides NotImplemented when given an exponent of -1, that result is returned. Otherwise, if `val` is iterable, the result is a tuple with the same items as `val` but in reverse order and with each item inverted. Otherwise, if a `default` argument was specified, it is returned. Raises: TypeError: `val` doesn't have a __pow__ method, or that method returned NotImplemented when given -1. Furthermore `val` isn't an iterable containing invertible items. Also, no `default` argument was specified. """ # TODO: remove this compatibility shim when ReversibleEffect is gone. from cirq import extension, ops reversible = extension.try_cast(ops.ReversibleEffect, val) if reversible is not None: return reversible.inverse() # Check if object defines an inverse via __pow__. raiser = getattr(val, '__pow__', None) result = NotImplemented if raiser is None else raiser(-1) if result is not NotImplemented: return result # Maybe it's an iterable of invertable items? # Note: we avoid str because 'a'[0] == 'a', which creates an infinite loop. if isinstance(val, collections.Iterable) and not isinstance(val, str): unique_indicator = [] results = tuple(inverse(e, unique_indicator) for e in val) if all(e is not unique_indicator for e in results): return results[::-1] # Can't invert. if default is not RaiseTypeErrorIfNotProvided: return default raise TypeError( "object of type '{}' isn't invertable. " "It has no __pow__ method (or the method returned NotImplemented) " "and it isn't an iterable of invertable objects.".format(type(val)))
def _decompose(self, op: ops.Operation) -> ops.OP_TREE: """Recursively decompose composite gates into an OP_TREE of gates.""" skip = self.no_decomp(op) if skip and (skip is not NotImplemented): return op composite_op = extension.try_cast( # type: ignore ops.CompositeOperation, op) if composite_op is None: return op op_iter = ops.flatten_op_tree(composite_op.default_decompose()) return (self._decompose(op) for op in op_iter)
def _group_interchangeable_qubits( self ) -> Tuple[Union[raw_types.QubitId, Tuple[ int, FrozenSet[raw_types.QubitId]]], ...]: cast_gate = extension.try_cast(gate_features.InterchangeableQubitsGate, self.gate) if cast_gate is None: return self.qubits groups = {} # type: Dict[int, List[raw_types.QubitId]] for i, q in enumerate(self.qubits): k = cast_gate.qubit_index_to_equivalence_group_key(i) if k not in groups: groups[k] = [] groups[k].append(q) return tuple(sorted((k, frozenset(v)) for k, v in groups.items()))
def _group_interchangeable_qubits(self) -> Tuple[ Union[raw_types.QubitId, Tuple[int, FrozenSet[raw_types.QubitId]]], ...]: cast_gate = extension.try_cast(gate_features.InterchangeableQubitsGate, self.gate) if cast_gate is None: return self.qubits groups = {} # type: Dict[int, List[raw_types.QubitId]] for i, q in enumerate(self.qubits): k = cast_gate.qubit_index_to_equivalence_group_key(i) if k not in groups: groups[k] = [] groups[k].append(q) return tuple(sorted((k, frozenset(v)) for k, v in groups.items()))
def unitary( val: Any, default: TDefault = RaiseTypeErrorIfNotProvided ) -> Union[np.ndarray, TDefault]: """Returns a unitary matrix describing the given value. Args: val: The value to describe with a unitary matrix. default: Determines the fallback behavior when `val` doesn't have a unitary matrix. If `default` is not set, a TypeError is raised. If default is set to a value, that value is returned. Returns: If `val` has a _unitary_ method and its result is not NotImplemented, that result is returned. Otherwise, if a default value was specified, the default value is returned. Raises: TypeError: `val` doesn't have a _unitary_ method (or that method returned NotImplemented) and also no default value was specified. """ getter = getattr(val, '_unitary_', None) result = NotImplemented if getter is None else getter() # Temporary compatibility shim for classes using KnownMatrix. if result is NotImplemented: known = extension.try_cast(KnownMatrix, val) result = NotImplemented if known is None else known.matrix() if result is not NotImplemented: return result if default is not RaiseTypeErrorIfNotProvided: return default if getter is None: raise TypeError("object of type '{}' " "has no _unitary_ method.".format(type(val))) raise TypeError("object of type '{}' does have a _unitary_ method, " "but it returned NotImplemented.".format(type(val)))