Example #1
0
def assert_has_consistent_apply_unitary(val: Any,
                                        *,
                                        qubit_count: Optional[int] = None,
                                        atol: float = 1e-8) -> None:
    """Tests whether a value's _apply_unitary_ is correct.

    Contrasts the effects of the value's `_apply_unitary_` with the
    matrix returned by the value's `_unitary_` method.

    Args:
        val: The value under test. Should have a `__pow__` method.
        qubit_count: Usually inferred. The number of qubits the value acts on.
            This argument isn't needed if the gate has a unitary matrix or
            implements `cirq.SingleQubitGate`/`cirq.TwoQubitGate`/
            `cirq.ThreeQubitGate`.
        atol: Absolute error tolerance.
    """

    expected = protocols.unitary(val, default=None)

    qubit_counts = [
        qubit_count,
        # Only fall back to using the unitary size if num_qubits or qid_shape
        # protocols are not defined.
        protocols.num_qubits(val,
                             default=expected.shape[0].bit_length() -
                             1 if expected is not None else None),
        _infer_qubit_count(val)
    ]
    qubit_counts = [e for e in qubit_counts if e is not None]
    if not qubit_counts:
        raise NotImplementedError(
            'Failed to infer qubit count of <{!r}>. Specify it.'.format(val))
    assert len(set(qubit_counts)) == 1, (
        'Inconsistent qubit counts from different methods: {}'.format(
            qubit_counts))
    n = cast(int, qubit_counts[0])
    qid_shape = protocols.qid_shape(val, default=(2, ) * n)

    eye = linalg.eye_tensor((2, ) + qid_shape, dtype=np.complex128)
    actual = protocols.apply_unitary(
        unitary_value=val,
        args=protocols.ApplyUnitaryArgs(target_tensor=eye,
                                        available_buffer=np.ones_like(eye) *
                                        float('nan'),
                                        axes=list(range(1, n + 1))),
        default=None)

    # If you don't have a unitary, you shouldn't be able to apply a unitary.
    if expected is None:
        assert actual is None
    else:
        expected = np.kron(np.eye(2), expected)

    # If you applied a unitary, it should match the one you say you have.
    if actual is not None:
        np.testing.assert_allclose(actual.reshape((np.prod(
            (2, ) + qid_shape, dtype=int), ) * 2),
                                   expected,
                                   atol=atol)
 def _unitary_(self) -> Union[np.ndarray, NotImplementedType]:
     sub_matrix = protocols.unitary(self.sub_operation, None)
     if sub_matrix is None:
         return NotImplemented
     qid_shape = protocols.qid_shape(self)
     sub_n = len(qid_shape) - len(self.controls)
     tensor = linalg.eye_tensor(qid_shape, dtype=sub_matrix.dtype)
     sub_tensor = sub_matrix.reshape(qid_shape[len(self.controls):] * 2)
     for control_vals in itertools.product(*self.control_values):
         active = (*(v for v in control_vals), *(slice(None), ) * sub_n) * 2
         tensor[active] = sub_tensor
     return tensor.reshape((np.prod(qid_shape, dtype=int), ) * 2)
Example #3
0
def assert_has_consistent_apply_unitary(val: Any,
                                        *,
                                        atol: float = 1e-8) -> None:
    """Tests whether a value's _apply_unitary_ is correct.

    Contrasts the effects of the value's `_apply_unitary_` with the
    matrix returned by the value's `_unitary_` method.

    Args:
        val: The value under test. Should have a `__pow__` method.
        atol: Absolute error tolerance.
    """
    # pylint: disable=unused-variable
    __tracebackhide__ = True
    # pylint: enable=unused-variable

    _assert_apply_unitary_works_when_axes_transposed(val, atol=atol)

    expected = protocols.unitary(val, default=None)

    qid_shape = protocols.qid_shape(val)

    eye = linalg.eye_tensor((2, ) + qid_shape, dtype=np.complex128)
    actual = protocols.apply_unitary(
        unitary_value=val,
        args=protocols.ApplyUnitaryArgs(target_tensor=eye,
                                        available_buffer=np.ones_like(eye) *
                                        float('nan'),
                                        axes=list(range(1,
                                                        len(qid_shape) + 1))),
        default=None)

    # If you don't have a unitary, you shouldn't be able to apply a unitary.
    if expected is None:
        assert actual is None
    else:
        expected = np.kron(np.eye(2), expected)

    # If you applied a unitary, it should match the one you say you have.
    if actual is not None:
        np.testing.assert_allclose(actual.reshape((np.prod(
            (2, ) + qid_shape, dtype=int), ) * 2),
                                   expected,
                                   atol=atol)
Example #4
0
def _strat_unitary_from_decompose(val: Any) -> Optional[np.ndarray]:
    """Attempts to compute a value's unitary via its _decompose_ method."""
    # Check if there's a decomposition.
    operations, qubits, val_qid_shape = (
        _try_decompose_into_operations_and_qubits(val))
    if operations is None:
        return NotImplemented

    # Apply sub-operations' unitary effects to an identity matrix.
    state = linalg.eye_tensor(val_qid_shape, dtype=np.complex128)
    buffer = np.empty_like(state)
    result = apply_unitaries(
        operations, qubits,
        ApplyUnitaryArgs(state, buffer, range(len(val_qid_shape))), None)

    # Package result.
    if result is None:
        return None
    state_len = np.prod(val_qid_shape, dtype=int)
    return result.reshape((state_len, state_len))
Example #5
0
def _strat_unitary_from_apply_unitary(val: Any) -> Optional[np.ndarray]:
    """Attempts to compute a value's unitary via its _apply_unitary_ method."""
    # Check for the magic method.
    method = getattr(val, '_apply_unitary_', None)
    if method is None:
        return NotImplemented

    # Get the qid_shape.
    val_qid_shape = qid_shape_protocol.qid_shape(val, None)
    if val_qid_shape is None:
        return NotImplemented

    # Apply unitary effect to an identity matrix.
    state = linalg.eye_tensor(val_qid_shape, dtype=np.complex128)
    buffer = np.empty_like(state)
    result = method(ApplyUnitaryArgs(state, buffer, range(len(val_qid_shape))))

    if result is NotImplemented or result is None:
        return result
    state_len = np.prod(val_qid_shape, dtype=int)
    return result.reshape((state_len, state_len))