Example #1
0
    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))
Example #2
0
    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))
Example #4
0
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
Example #5
0
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)))
Example #6
0
 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)
Example #7
0
    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()))
Example #8
0
    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()))
Example #9
0
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)))