def assert_pauli_expansion_is_consistent_with_unitary(val: Any) -> None:
    """Checks Pauli expansion against unitary matrix."""
    # Check to see if the protocol is supported without doing a fallback
    # to unitary, otherwise the test is vacuous.
    method = getattr(val, '_pauli_expansion_', None)
    if method is None:
        return

    pauli_expansion = protocols.pauli_expansion(val, default=None)
    if pauli_expansion is None:
        return

    unitary = protocols.unitary(val, None)
    if unitary is None:
        return

    num_qubits = protocols.num_qubits(val,
                                      default=unitary.shape[0].bit_length() -
                                      1)
    basis = operator_spaces.kron_bases(operator_spaces.PAULI_BASIS,
                                       repeat=num_qubits)

    recovered_unitary = operator_spaces.matrix_from_basis_coefficients(
        pauli_expansion, basis)
    assert np.allclose(unitary, recovered_unitary, rtol=0, atol=1e-12)
Exemple #2
0
def pauli_expansion(
        val: Any,
        *,
        default: Union[value.LinearDict[str],
                       TDefault] = RaiseTypeErrorIfNotProvided,
        atol: float = 1e-9) -> Union[value.LinearDict[str], TDefault]:
    """Returns coefficients of the expansion of val in the Pauli basis.

    Args:
        val: The value whose Pauli expansion is to returned.
        default: Determines what happens when `val` does not have methods that
            allow Pauli expansion to be obtained (see below). If set, the value
            is returned in that case. Otherwise, TypeError is raised.
        atol: Ignore coefficients whose absolute value is smaller than this.

    Returns:
        If `val` has a _pauli_expansion_ method, then its result is returned.
        Otherwise, if `val` has a small unitary then that unitary is expanded
        in the Pauli basis and coefficients are returned. Otherwise, if default
        is set to None or other value then default is returned. Otherwise,
        TypeError is raised.

    Raises:
        TypeError if `val` has none of the methods necessary to obtain its Pauli
        expansion and no default value has been provided.
    """
    method = getattr(val, '_pauli_expansion_', None)
    expansion = NotImplemented if method is None else method()

    if expansion is not NotImplemented:
        return expansion.clean(atol=atol)

    # Don't attempt to derive the pauli expansion if this is a qudit gate
    if not all(d == 2 for d in qid_shape_protocol.qid_shape(val, default=())):
        if default is RaiseTypeErrorIfNotProvided:
            raise TypeError(
                'No Pauli expansion for object {} of type {}'.format(
                    val, type(val)))
        return default

    matrix = unitary(val, default=None)
    if matrix is None:
        if default is RaiseTypeErrorIfNotProvided:
            raise TypeError(
                'No Pauli expansion for object {} of type {}'.format(
                    val, type(val)))
        return default

    num_qubits = matrix.shape[0].bit_length() - 1
    basis = operator_spaces.kron_bases(operator_spaces.PAULI_BASIS,
                                       repeat=num_qubits)

    expansion = operator_spaces.expand_matrix_in_orthogonal_basis(
        matrix, basis)
    return expansion.clean(atol=atol)
def pauli_expansion(val: Any,
                    *,
                    default: Optional[Dict[
                        str, complex]] = RaiseTypeErrorIfNotProvided,
                    tolerance: float = 1e-9) -> Optional[Dict[str, complex]]:
    """Returns coefficients of the expansion of val in the Pauli basis.

    Args:
        val: The value whose Pauli expansion is to returned.
        default: Determines what happens when `val` does not have methods that
            allow Pauli expansion to be obtained (see below). If set, the value
            is returned in that case. Otherwise, TypeError is raised.
        tolerance: Ignore coefficients whose absolute value is smaller than
            this.

    Returns:
        If `val` has a _pauli_expansion_ method, then its result is returned.
        Otherwise, if `val` has a small unitary then that unitary is expanded
        in the Pauli basis and coefficients are returned. Otherwise, if default
        is set to None or other value then default is returned. Otherwise,
        TypeError is raised.

    Raises:
        TypeError if `val` has none of the methods necessary to obtain its Pauli
        expansion and no default value has been provided.
    """
    method = getattr(val, '_pauli_expansion_', None)
    expansion = NotImplemented if method is None else method()

    if expansion is not NotImplemented:
        return _filter_coefficients(expansion, tolerance)

    matrix = unitary(val, default=None)
    if matrix is None:
        if default is RaiseTypeErrorIfNotProvided:
            raise TypeError(
                'No Pauli expansion for object {} of type {}'.format(
                    val, type(val)))
        return default

    num_qubits = matrix.shape[0].bit_length() - 1
    basis = operator_spaces.kron_bases(operator_spaces.PAULI_BASIS,
                                       repeat=num_qubits)

    expansion = operator_spaces.expand_matrix_in_orthogonal_basis(
        matrix, basis)
    return _filter_coefficients(expansion, tolerance)
def assert_pauli_expansion_is_consistent_with_unitary(val: Any) -> None:
    """Checks Pauli expansion against unitary matrix."""
    pauli_expansion = protocols.pauli_expansion(val, default=None)
    if pauli_expansion is None:
        return

    unitary = protocols.unitary(val, None)
    if unitary is None:
        return

    num_qubits = unitary.shape[0].bit_length() - 1
    basis = operator_spaces.kron_bases(operator_spaces.PAULI_BASIS,
                                       repeat=num_qubits)

    recovered_unitary = operator_spaces.matrix_from_basis_coefficients(
        pauli_expansion, basis)
    assert np.allclose(unitary, recovered_unitary, rtol=0, atol=1e-12)