Beispiel #1
0
def test_kak_decomposition_depth_partial_cz():
    a, b = cirq.LineQubit.range(2)

    # Random.
    u = cirq.testing.random_unitary(4)
    operations_with_full = cirq.two_qubit_matrix_to_cz_operations(
        a, b, u, True)
    c = cirq.Circuit(operations_with_full)
    # 3 CP, 3+1 PhasedX, 1 Z
    assert len(c) <= 8

    # Double-axis interaction.
    u = cirq.unitary(cirq.Circuit(cirq.CNOT(a, b), cirq.CNOT(b, a)))
    operations_with_part = cirq.two_qubit_matrix_to_cz_operations(
        a, b, u, True)
    c = cirq.Circuit(operations_with_part)
    # 2 CP, 2+1 PhasedX, 1 Z
    assert len(c) <= 6

    # Partial single-axis interaction.
    u = cirq.unitary(cirq.CNOT**0.1)
    operations_with_part = cirq.two_qubit_matrix_to_cz_operations(
        a, b, u, True)
    c = cirq.Circuit(operations_with_part)
    # 1 CP, 1+1 PhasedX, 1 Z
    assert len(c) <= 4

    # Full single-axis interaction.
    u = cirq.unitary(cirq.ControlledGate(cirq.Y))
    operations_with_part = cirq.two_qubit_matrix_to_cz_operations(
        a, b, u, True)
    c = cirq.Circuit(operations_with_part)
    # 1 CP, 1+1 PhasedX, 1 Z
    assert len(c) <= 4
Beispiel #2
0
def test_two_to_ops_equivalent_and_bounded_for_known_and_random(
    max_partial_cz_depth, max_full_cz_depth, effect
):
    q0 = cirq.NamedQubit('q0')
    q1 = cirq.NamedQubit('q1')

    operations_with_partial = cirq.two_qubit_matrix_to_cz_operations(q0, q1, effect, True)
    operations_with_full = cirq.two_qubit_matrix_to_cz_operations(q0, q1, effect, False)

    assert_ops_implement_unitary(q0, q1, operations_with_partial, effect)
    assert_ops_implement_unitary(q0, q1, operations_with_full, effect)

    assert_cz_depth_below(operations_with_partial, max_partial_cz_depth, False)
    assert_cz_depth_below(operations_with_full, max_full_cz_depth, True)
    def decompose_to_target_gateset(self, op: 'cirq.Operation',
                                    moment_idx: int) -> DecomposeResult:
        """Method to rewrite the given operation using gates from this gateset.

        Args:
            op: `cirq.Operation` to be rewritten using gates from this gateset.
            moment_idx: Moment index where the given operation `op` occurs in a circuit.

        Returns:
            - An equivalent `cirq.OP_TREE` implementing `op` using gates from this gateset.
            - `None` or `NotImplemented` if does not know how to decompose `op`.
        """
        # Known matrix?
        mat = cirq.unitary(op, None) if len(op.qubits) <= 2 else None
        if mat is not None and len(op.qubits) == 1:
            gates = cirq.single_qubit_matrix_to_phased_x_z(mat)
            return [g.on(op.qubits[0]) for g in gates]
        if mat is not None and len(op.qubits) == 2:
            return cirq.two_qubit_matrix_to_cz_operations(
                op.qubits[0],
                op.qubits[1],
                mat,
                allow_partial_czs=False,
                clean_operations=True)

        return NotImplemented
Beispiel #4
0
def test_kak_decomposition_depth_full_cz():
    a, b = cirq.LineQubit.range(2)

    # Random.
    u = cirq.testing.random_unitary(4)
    operations_with_full = cirq.two_qubit_matrix_to_cz_operations(
        a, b, u, False)
    c = cirq.Circuit(operations_with_full)
    # 3 CZ, 3+1 PhasedX, 1 Z
    assert len(c) <= 8

    # Double-axis interaction.
    u = cirq.unitary(cirq.Circuit(cirq.CNOT(a, b), cirq.CNOT(b, a)))
    operations_with_part = cirq.two_qubit_matrix_to_cz_operations(
        a, b, u, False)
    c = cirq.Circuit(operations_with_part)
    # 2 CZ, 2+1 PhasedX, 1 Z
    assert len(c) <= 6

    # Test unoptimized/un-cleaned length of Double-axis interaction.
    u = cirq.unitary(cirq.Circuit(cirq.CNOT(a, b), cirq.CNOT(b, a)))
    operations_with_part = cirq.two_qubit_matrix_to_cz_operations(
        a, b, u, False, 1e-8, False)
    c = cirq.Circuit(operations_with_part)
    assert len(c) > 6  # Length should be 13 with extra Pauli gates

    # Partial single-axis interaction.
    u = cirq.unitary(cirq.CNOT**0.1)
    operations_with_part = cirq.two_qubit_matrix_to_cz_operations(
        a, b, u, False)
    c = cirq.Circuit(operations_with_part)
    # 2 CZ, 2+1 PhasedX, 1 Z
    assert len(c) <= 6

    # Full single-axis interaction.
    u = cirq.unitary(cirq.ControlledGate(cirq.Y))
    operations_with_part = cirq.two_qubit_matrix_to_cz_operations(
        a, b, u, False)
    c = cirq.Circuit(operations_with_part)
    # 1 CZ, 1+1 PhasedX, 1 Z
    assert len(c) <= 4
Beispiel #5
0
    def _convert_one(self, op: cirq.Operation) -> cirq.OP_TREE:
        # Known matrix?
        mat = cirq.unitary(op, None) if len(op.qubits) <= 2 else None
        if mat is not None and len(op.qubits) == 1:
            gates = cirq.single_qubit_matrix_to_phased_x_z(mat)
            return [g.on(op.qubits[0]) for g in gates]
        if mat is not None and len(op.qubits) == 2:
            return cirq.two_qubit_matrix_to_cz_operations(
                op.qubits[0], op.qubits[1], mat, allow_partial_czs=True, clean_operations=False
            )

        return NotImplemented
Beispiel #6
0
def two_qubit_matrix_to_sycamore_operations(
    q0: cirq.Qid,
    q1: cirq.Qid,
    mat: np.ndarray,
    *,
    atol: float = 1e-8,
    clean_operations: bool = True,
) -> cirq.OP_TREE:
    """Decomposes a two-qubit unitary matrix into `cirq_google.SYC` + single qubit rotations.

    The analytical decomposition first Synthesizes the given operation using `cirq.CZPowGate` +
    single qubit rotations and then decomposes each `cirq.CZPowGate` into `cirq_google.SYC` +
    single qubit rotations using `cirq_google.known_2q_op_to_sycamore_operations`.

    Note that the resulting decomposition may not be optimal, and users should first try to
    decompose a given operation using `cirq_google.known_2q_op_to_sycamore_operations`.

    Args:
        q0: The first qubit being operated on.
        q1: The other qubit being operated on.
        mat: Defines the operation to apply to the pair of qubits.
        atol: A limit on the amount of absolute error introduced by the
            construction.
        clean_operations: Merges runs of single qubit gates to a single `cirq.PhasedXZGate` in
            the resulting operations list.

    Returns:
        A `cirq.OP_TREE` that implements the given unitary operation using only `cirq_google.SYC` +
        single qubit rotations.
    """
    decomposed_ops: List[cirq.OP_TREE] = []
    for op in cirq.two_qubit_matrix_to_cz_operations(
            q0,
            q1,
            mat,
            allow_partial_czs=True,
            atol=atol,
            clean_operations=clean_operations):
        if cirq.num_qubits(op) == 2:
            decomposed_cphase = known_2q_op_to_sycamore_operations(op)
            assert decomposed_cphase is not None
            decomposed_ops.append(decomposed_cphase)
        else:
            decomposed_ops.append(op)
    return ([
        *cirq.merge_single_qubit_gates_to_phxz(
            cirq.Circuit(decomposed_ops)).all_operations()
    ] if clean_operations else decomposed_ops)
Beispiel #7
0
def _decompose_two_qubit(operation: cirq.Operation) -> cirq.OP_TREE:
    """Decomposes a two qubit unitary operation into ZPOW, XPOW, and CNOT."""
    mat = cirq.unitary(operation)
    q0, q1 = operation.qubits
    naive = cirq.two_qubit_matrix_to_cz_operations(q0,
                                                   q1,
                                                   mat,
                                                   allow_partial_czs=False)
    temp = cirq.map_operations_and_unroll(
        cirq.Circuit(naive),
        lambda op, _:
        [cirq.H(op.qubits[1]),
         cirq.CNOT(*op.qubits),
         cirq.H(op.qubits[1])] if type(op.gate) == cirq.CZPowGate else op,
    )
    temp = cirq.merge_single_qubit_gates_to_phased_x_and_z(temp)
    # A final pass breaks up PhasedXPow into Rz, Rx.
    yield cirq.map_operations_and_unroll(
        temp, lambda op, _: cirq.decompose_once(op)
        if type(op.gate) == cirq.PhasedXPowGate else op).all_operations()
Beispiel #8
0
 def _decompose_two_qubit_operation(self, op: cirq.Operation,
                                    _) -> cirq.OP_TREE:
     if not cirq.has_unitary(op):
         return NotImplemented
     mat = cirq.unitary(op)
     q0, q1 = op.qubits
     naive = cirq.two_qubit_matrix_to_cz_operations(q0,
                                                    q1,
                                                    mat,
                                                    allow_partial_czs=False)
     temp = cirq.map_operations_and_unroll(
         cirq.Circuit(naive),
         lambda op, _: [
             cirq.H(op.qubits[1]),
             cirq.CNOT(*op.qubits),
             cirq.H(op.qubits[1])
         ] if op.gate == cirq.CZ else op,
     )
     return cirq.merge_k_qubit_unitaries(
         temp,
         k=1,
         rewriter=lambda op: self._decompose_single_qubit_operation(
             op, -1)).all_operations()