예제 #1
0
def kak_decomposition(
        mat: np.ndarray,
        rtol: float = DEFAULT_RTOL,
        atol: float = DEFAULT_ATOL) -> KakDecomposition:
    """Decomposes a 2-qubit unitary into 1-qubit ops and XX/YY/ZZ interactions.

    Args:
        mat: The 4x4 unitary matrix to decompose.
        rtol: Per-matrix-entry relative tolerance on equality.
        atol: Per-matrix-entry absolute tolerance on equality.

    Returns:
        A `cirq.KakDecomposition` canonicalized such that the interaction
        coefficients x, y, z satisfy:

            0 ≤ abs(z) ≤ y ≤ x ≤ π/4
            z ≠ -π/4

    Raises:
        ValueError: Bad matrix.
        ArithmeticError: Failed to perform the decomposition.

    References:
        'An Introduction to Cartan's KAK Decomposition for QC Programmers'
        https://arxiv.org/abs/quant-ph/0507171
    """
    magic = np.array([[1, 0, 0, 1j],
                      [0, 1j, 1, 0],
                      [0, 1j, -1, 0],
                      [1, 0, 0, -1j]]) * np.sqrt(0.5)
    gamma = np.array([[1, 1, 1, 1],
                      [1, 1, -1, -1],
                      [-1, 1, -1, 1],
                      [1, -1, -1, 1]]) * 0.25

    # Diagonalize in magic basis.
    left, d, right = (
        diagonalize.bidiagonalize_unitary_with_special_orthogonals(
            combinators.dot(np.conj(magic.T), mat, magic),
            atol=atol, rtol=rtol))

    # Recover pieces.
    a1, a0 = so4_to_magic_su2s(left.T, atol=atol, rtol=rtol)
    b1, b0 = so4_to_magic_su2s(right.T, atol=atol, rtol=rtol)
    w, x, y, z = gamma.dot(np.vstack(np.angle(d))).flatten()
    g = np.exp(1j * w)

    # Canonicalize.
    inner_cannon = kak_canonicalize_vector(x, y, z)

    b1 = np.dot(inner_cannon.single_qubit_operations_before[0], b1)
    b0 = np.dot(inner_cannon.single_qubit_operations_before[1], b0)
    a1 = np.dot(a1, inner_cannon.single_qubit_operations_after[0])
    a0 = np.dot(a0, inner_cannon.single_qubit_operations_after[1])
    return KakDecomposition(
        interaction_coefficients=inner_cannon.interaction_coefficients,
        global_phase=g * inner_cannon.global_phase,
        single_qubit_operations_before=(b1, b0),
        single_qubit_operations_after=(a1, a0))
예제 #2
0
def kak_decomposition(
    mat: np.ndarray,
    tolerance: Tolerance = Tolerance.DEFAULT
) -> Tuple[complex, Tuple[np.ndarray, np.ndarray], Tuple[float, float, float],
           Tuple[np.ndarray, np.ndarray]]:
    """Decomposes a 2-qubit unitary into 1-qubit ops and XX/YY/ZZ interactions.

    Args:
        mat: The 4x4 unitary matrix to decompose.
        tolerance: Per-matrix-entry tolerance on equality.

    Returns:
        A nested tuple (g, (a1, a0), (x, y, z), (b1, b0)) containing:

            0. A global phase factor.
            1. The pre-operation matrices to apply to the second/firs qubit.
            2. The XX/YY/ZZ weights of the non-local operation.
            3. The post-operation matrices to apply to the second/firs qubit.

        Guarantees that the x2, y2, z2 are canonicalized to satisfy:

            0 ≤ abs(z) ≤ y ≤ x ≤ π/4
            z ≠ -π/4

        Guarantees that the input matrix should approximately equal:

            g · (a1 ⊗ a0) · exp(i·(x·XX + y·YY + z·ZZ)) · (b1 ⊗ b0)

    Raises:
        ValueError: Bad matrix.
        ArithmeticError: Failed to perform the decomposition.

    References:
        'An Introduction to Cartan's KAK Decomposition for QC Programmers'
        https://arxiv.org/abs/quant-ph/0507171
    """
    magic = np.array([[1, 0, 0, 1j], [0, 1j, 1, 0], [0, 1j, -1, 0],
                      [1, 0, 0, -1j]]) * np.sqrt(0.5)
    gamma = np.array([[1, 1, 1, 1], [1, 1, -1, -1], [-1, 1, -1, 1],
                      [1, -1, -1, 1]]) * 0.25

    # Diagonalize in magic basis.
    left, d, right = (
        diagonalize.bidiagonalize_unitary_with_special_orthogonals(
            combinators.dot(np.conj(magic.T), mat, magic), tolerance))

    # Recover pieces.
    a1, a0 = so4_to_magic_su2s(left.T, tolerance)
    b1, b0 = so4_to_magic_su2s(right.T, tolerance)
    w, x, y, z = gamma.dot(np.vstack(np.angle(d))).flatten()
    g = np.exp(1j * w)

    # Canonicalize.
    g2, (c1, c0), (x2, y2, z2), (d1, d0) = kak_canonicalize_vector(x, y, z)
    return (g * g2, (a1.dot(c1), a0.dot(c0)), (x2, y2, z2), (d1.dot(b1),
                                                             d0.dot(b0)))
예제 #3
0
def kak_decomposition(mat: np.ndarray,
                      rtol: float = 1e-5,
                      atol: float = 1e-8) -> KakDecomposition:
    """Decomposes a 2-qubit unitary into 1-qubit ops and XX/YY/ZZ interactions.

    Args:
        mat: The 4x4 unitary matrix to decompose.
        rtol: Per-matrix-entry relative tolerance on equality.
        atol: Per-matrix-entry absolute tolerance on equality.

    Returns:
        A `cirq.KakDecomposition` canonicalized such that the interaction
        coefficients x, y, z satisfy:

            0 ≤ abs(z2) ≤ y2 ≤ x2 ≤ π/4
            if x2 = π/4, z2 >= 0

    Raises:
        ValueError: Bad matrix.
        ArithmeticError: Failed to perform the decomposition.

    References:
        'An Introduction to Cartan's KAK Decomposition for QC Programmers'
        https://arxiv.org/abs/quant-ph/0507171
    """
    # Diagonalize in magic basis.
    left, d, right = diagonalize.bidiagonalize_unitary_with_special_orthogonals(
        KAK_MAGIC_DAG @ mat @ KAK_MAGIC,
        atol=atol,
        rtol=rtol,
        check_preconditions=False)

    # Recover pieces.
    a1, a0 = so4_to_magic_su2s(left.T,
                               atol=atol,
                               rtol=rtol,
                               check_preconditions=False)
    b1, b0 = so4_to_magic_su2s(right.T,
                               atol=atol,
                               rtol=rtol,
                               check_preconditions=False)
    w, x, y, z = (KAK_GAMMA @ np.vstack(np.angle(d))).flatten()
    g = np.exp(1j * w)

    # Canonicalize.
    inner_cannon = kak_canonicalize_vector(x, y, z)

    b1 = np.dot(inner_cannon.single_qubit_operations_before[0], b1)
    b0 = np.dot(inner_cannon.single_qubit_operations_before[1], b0)
    a1 = np.dot(a1, inner_cannon.single_qubit_operations_after[0])
    a0 = np.dot(a0, inner_cannon.single_qubit_operations_after[1])
    return KakDecomposition(
        interaction_coefficients=inner_cannon.interaction_coefficients,
        global_phase=g * inner_cannon.global_phase,
        single_qubit_operations_before=(b1, b0),
        single_qubit_operations_after=(a1, a0))
예제 #4
0
def kak_decomposition(
    unitary_object: Union[np.ndarray, 'cirq.SupportsUnitary'],
    *,
    rtol: float = 1e-5,
    atol: float = 1e-8,
    check_preconditions: bool = True,
) -> KakDecomposition:
    """Decomposes a 2-qubit unitary into 1-qubit ops and XX/YY/ZZ interactions.

    Args:
        unitary_object: The value to decompose. Can either be a 4x4 unitary
            matrix, or an object that has a 4x4 unitary matrix (via the
            `cirq.SupportsUnitary` protocol).
        rtol: Per-matrix-entry relative tolerance on equality.
        atol: Per-matrix-entry absolute tolerance on equality.
        check_preconditions: If set, verifies that the input corresponds to a
            4x4 unitary before decomposing.

    Returns:
        A `cirq.KakDecomposition` canonicalized such that the interaction
        coefficients x, y, z satisfy:

            0 ≤ abs(z2) ≤ y2 ≤ x2 ≤ π/4
            if x2 = π/4, z2 >= 0

    Raises:
        ValueError: Bad matrix.
        ArithmeticError: Failed to perform the decomposition.

    References:
        'An Introduction to Cartan's KAK Decomposition for QC Programmers'
        https://arxiv.org/abs/quant-ph/0507171
    """
    if isinstance(unitary_object, KakDecomposition):
        return unitary_object
    if isinstance(unitary_object, np.ndarray):
        mat = unitary_object
    else:
        mat = protocols.unitary(unitary_object)
    if check_preconditions and (
            mat.shape !=
        (4, 4) or not predicates.is_unitary(mat, rtol=rtol, atol=atol)):
        raise ValueError(
            'Input must correspond to a 4x4 unitary matrix. Received matrix:\n'
            + str(mat))

    # Diagonalize in magic basis.
    left, d, right = diagonalize.bidiagonalize_unitary_with_special_orthogonals(
        KAK_MAGIC_DAG @ mat @ KAK_MAGIC,
        atol=atol,
        rtol=rtol,
        check_preconditions=False)

    # Recover pieces.
    a1, a0 = so4_to_magic_su2s(left.T,
                               atol=atol,
                               rtol=rtol,
                               check_preconditions=False)
    b1, b0 = so4_to_magic_su2s(right.T,
                               atol=atol,
                               rtol=rtol,
                               check_preconditions=False)
    w, x, y, z = (KAK_GAMMA @ np.vstack(np.angle(d))).flatten()
    g = np.exp(1j * w)

    # Canonicalize.
    inner_cannon = kak_canonicalize_vector(x, y, z)

    b1 = np.dot(inner_cannon.single_qubit_operations_before[0], b1)
    b0 = np.dot(inner_cannon.single_qubit_operations_before[1], b0)
    a1 = np.dot(a1, inner_cannon.single_qubit_operations_after[0])
    a0 = np.dot(a0, inner_cannon.single_qubit_operations_after[1])
    return KakDecomposition(
        interaction_coefficients=inner_cannon.interaction_coefficients,
        global_phase=g * inner_cannon.global_phase,
        single_qubit_operations_before=(b1, b0),
        single_qubit_operations_after=(a1, a0),
    )
예제 #5
0
def kak_decomposition(
        mat: np.ndarray,
        tolerance: Tolerance = Tolerance.DEFAULT
) -> Tuple[complex,
           Tuple[np.ndarray, np.ndarray],
           Tuple[float, float, float],
           Tuple[np.ndarray, np.ndarray]]:
    """Decomposes a 2-qubit unitary into 1-qubit ops and XX/YY/ZZ interactions.

    Args:
        mat: The 4x4 unitary matrix to decompose.
        tolerance: Per-matrix-entry tolerance on equality.

    Returns:
        A nested tuple (g, (a1, a0), (x, y, z), (b1, b0)) containing:

            0. A global phase factor.
            1. The pre-operation matrices to apply to the second/firs qubit.
            2. The XX/YY/ZZ weights of the non-local operation.
            3. The post-operation matrices to apply to the second/firs qubit.

        Guarantees that the x2, y2, z2 are canonicalized to satisfy:

            0 ≤ abs(z) ≤ y ≤ x ≤ π/4
            z ≠ -π/4

        Guarantees that the input matrix should approximately equal:

            g · (a1 ⊗ a0) · exp(i·(x·XX + y·YY + z·ZZ)) · (b1 ⊗ b0)

    Raises:
        ValueError: Bad matrix.
        ArithmeticError: Failed to perform the decomposition.

    References:
        'An Introduction to Cartan's KAK Decomposition for QC Programmers'
        https://arxiv.org/abs/quant-ph/0507171
    """
    magic = np.array([[1, 0, 0, 1j],
                    [0, 1j, 1, 0],
                    [0, 1j, -1, 0],
                    [1, 0, 0, -1j]]) * np.sqrt(0.5)
    gamma = np.array([[1, 1, 1, 1],
                    [1, 1, -1, -1],
                    [-1, 1, -1, 1],
                    [1, -1, -1, 1]]) * 0.25

    # Diagonalize in magic basis.
    left, d, right = (
        diagonalize.bidiagonalize_unitary_with_special_orthogonals(
            combinators.dot(np.conj(magic.T), mat, magic),
            tolerance))

    # Recover pieces.
    a1, a0 = so4_to_magic_su2s(left.T, tolerance)
    b1, b0 = so4_to_magic_su2s(right.T, tolerance)
    w, x, y, z = gamma.dot(np.vstack(np.angle(d))).flatten()
    g = np.exp(1j * w)

    # Canonicalize.
    g2, (c1, c0), (x2, y2, z2), (d1, d0) = kak_canonicalize_vector(x, y, z)
    return (
        g * g2,
        (a1.dot(c1), a0.dot(c0)),
        (x2, y2, z2),
        (d1.dot(b1), d0.dot(b0))
    )
예제 #6
0
def test_bidiagonalize_unitary_fails(mat):
    with pytest.raises(ValueError):
        diagonalize.bidiagonalize_unitary_with_special_orthogonals(mat)
예제 #7
0
def test_bidiagonalize_unitary_with_special_orthogonals(mat):
    p, d, q = diagonalize.bidiagonalize_unitary_with_special_orthogonals(mat)
    assert predicates.is_special_orthogonal(p)
    assert predicates.is_special_orthogonal(q)
    assert np.allclose(p.dot(mat).dot(q), np.diag(d))
    assert_bidiagonalized_by(mat, p, q)