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_operations(a, b, u, True)
    c = cirq.Circuit.from_ops(operations_with_full)
    # 3 CP, 3+1 PhasedX, 1 Z
    assert len(c) <= 8

    # Double-axis interaction.
    u = cirq.unitary(cirq.Circuit.from_ops(cirq.CNOT(a, b), cirq.CNOT(b, a)))
    operations_with_part = cirq.two_qubit_matrix_to_operations(a, b, u, True)
    c = cirq.Circuit.from_ops(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_operations(a, b, u, True)
    c = cirq.Circuit.from_ops(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_operations(a, b, u, True)
    c = cirq.Circuit.from_ops(operations_with_part)
    # 1 CP, 1+1 PhasedX, 1 Z
    assert len(c) <= 4
示例#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_operations(q0, q1, effect, True)
    operations_with_full = cirq.two_qubit_matrix_to_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)
示例#3
0
def decompose_arbitrary_into_syc_analytic(qubit_a: cirq.Qid, qubit_b: cirq.Qid,
                                          op: cirq.Operation) -> cirq.OP_TREE:
    """Synthesize an arbitrary 2 qubit operation to a sycamore operation using
    the given Tabulation.

     Args:
            qubit_a: first qubit of the operation
            qubit_b: second qubit of the operation
            op: operation to decompose
            tabulation: A tabulation for the Sycamore gate.
        Returns:
            New operations iterable object
    """
    new_ops = cirq.two_qubit_matrix_to_operations(qubit_a,
                                                  qubit_b,
                                                  op,
                                                  allow_partial_czs=True)
    for new_op in new_ops:
        num_qubits = len(new_op.qubits)
        if num_qubits == 1:
            (a, ) = new_op.qubits
            yield from _phased_x_z_ops(cirq.unitary(new_op), a)
        elif num_qubits == 2:
            a, b = op.qubits
            yield from cirq.flatten_to_ops(
                known_two_q_operations_to_sycamore_operations(a, b, new_op))
示例#4
0
def decompose_arbitrary_into_syc_analytic(qubit_a: cirq.Qid, qubit_b: cirq.Qid,
                                          op: cirq.Operation) -> cirq.OP_TREE:
    """Synthesize an arbitrary 2 qubit operation to a Sycamore operation using the given Tabulation.

    Args:
        qubit_a: First qubit of the operation.
        qubit_b: Second qubit of the operation.
        op: Operation to decompose.
        tabulation: A tabulation for the Sycamore gate.
    Yields:
        A `cirq.OP_TREE` which produces the given operation using Sycamores.
    """
    new_ops = cirq.two_qubit_matrix_to_operations(qubit_a,
                                                  qubit_b,
                                                  op,
                                                  allow_partial_czs=True)
    for new_op in new_ops:
        num_qubits = len(new_op.qubits)
        if num_qubits == 1:
            (a, ) = new_op.qubits
            yield from _phased_x_z_ops(cirq.unitary(new_op), a)
        elif num_qubits == 2:
            a, b = op.qubits
            yield from cirq.flatten_to_ops(
                known_two_q_operations_to_sycamore_operations(a, b, new_op))
示例#5
0
def test_two_to_ops_equivalent_and_bounded_for_known_and_random(
        max_partial_cz_depth,
        max_full_cz_depth,
        effect):
    q0 = cirq.QubitId()
    q1 = cirq.QubitId()

    operations_with_partial = cirq.two_qubit_matrix_to_operations(
        q0, q1, effect, True)
    operations_with_full = cirq.two_qubit_matrix_to_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 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_operations(a, b, u, False)
    c = cirq.Circuit.from_ops(operations_with_full)
    # 3 CZ, 3+1 PhasedX, 1 Z
    assert len(c) <= 8

    # Double-axis interaction.
    u = cirq.unitary(cirq.Circuit.from_ops(cirq.CNOT(a, b),
                                           cirq.CNOT(b, a)))
    operations_with_part = cirq.two_qubit_matrix_to_operations(a, b, u, False)
    c = cirq.Circuit.from_ops(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.from_ops(cirq.CNOT(a, b),
                                           cirq.CNOT(b, a)))
    operations_with_part = cirq.two_qubit_matrix_to_operations(a, b, u, False,
                                                               1e-8, False)
    c = cirq.Circuit.from_ops(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_operations(a, b, u, False)
    c = cirq.Circuit.from_ops(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_operations(a, b, u, False)
    c = cirq.Circuit.from_ops(operations_with_part)
    # 1 CZ, 1+1 PhasedX, 1 Z
    assert len(c) <= 4
示例#7
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_operations(op.qubits[0],
                                                       op.qubits[1],
                                                       mat,
                                                       allow_partial_czs=True,
                                                       clean_operations=False)

        return NotImplemented
示例#8
0
def matrix_to_sycamore_operations(
        target_qubits: List[cirq.GridQubit],
        matrix: np.ndarray) -> Tuple[cirq.OP_TREE, List[cirq.GridQubit]]:
    """A method to convert a unitary matrix to a list of Sycamore operations.

    This method will return a list of `cirq.Operation`s using the qubits and (optionally) ancilla
    qubits to implement the unitary matrix `matrix` on the target qubits `qubits`.
    The operations are also supported by `cirq.google.gate_sets.SYC_GATESET`.

    Args:
        target_qubits: list of qubits the returned operations will act on. The qubit order defined by the list
            is assumed to be used by the operations to implement `matrix`.
        matrix: a matrix that is guaranteed to be unitary and of size (2**len(qs), 2**len(qs)).
    Returns:
        A tuple of operations and ancilla qubits allocated.
            Operations: In case the matrix is supported, a list of operations `ops` is returned.
                `ops` acts on `qs` qubits and for which `cirq.unitary(ops)` is equal to `matrix` up
                 to certain tolerance. In case the matrix is not supported, it might return NotImplemented to
                 reduce the noise in the judge output.
            Ancilla qubits: In case ancilla qubits are allocated a list of ancilla qubits. Otherwise
                an empty list.
        .
    """
    num_qubit = len(target_qubits)
    ops = []
    if num_qubit == 1:
        ops = cirq.optimizers.single_qubit_matrix_to_gates(matrix)
        for i in range(len(ops)):
            ops[i] = ops[i].on(target_qubits[0])
    elif num_qubit == 2:
        if np.all(matrix == cirq.unitary(cirq.google.SYC)):
            ops = [cirq.google.SYC(target_qubits[0], target_qubits[1])]
        else:
            ops = cirq.two_qubit_matrix_to_operations(target_qubits[0],
                                                      target_qubits[1],
                                                      matrix,
                                                      allow_partial_czs=False)
    elif num_qubit == 3:
        if (matrix == np.diag([1, 1, 1, 1, 1, 1, 1, 1])).all():
            ops = []
        else:
            ops = cirq.three_qubit_matrix_to_operations(
                target_qubits[0], target_qubits[1], target_qubits[2], matrix)

    # print('target_qubit:', target_qubits)
    # print('matrix:', matrix, end='\n\n')
    # print('ops:')
    # for i in ops:
    #     print(i)
    return ops, []
示例#9
0
def generate_model_circuit(
        num_qubits: int,
        depth: int,
        *,
        random_state: Optional[np.random.RandomState] = None) -> cirq.Circuit:
    """Generates a model circuit with the given number of qubits and depth.

    The generated circuit consists of `depth` layers of random qubit
    permutations followed by random two-qubit gates that are sampled from the
    Haar measure on SU(4).

    Args:
        num_qubits: The number of qubits in the generated circuit.
        depth: The number of layers in the circuit.
        random_state: A way to seed the RandomState.

    Returns:
        The generated circuit.
    """
    # Setup the circuit and its qubits.
    qubits = cirq.LineQubit.range(num_qubits)
    circuit = cirq.Circuit()
    if random_state is None:
        random_state = np.random

    # For each layer.
    for _ in range(depth):
        # Generate uniformly random permutation Pj of [0...n-1]
        perm = random_state.permutation(num_qubits)

        # For each consecutive pair in Pj, generate Haar random SU(4)
        # Decompose each SU(4) into CNOT + SU(2) and add to Ci
        for k in range(0, num_qubits - 1, 2):
            permuted_indices = [int(perm[k]), int(perm[k + 1])]
            special_unitary = cirq.testing.random_special_unitary(
                4, random_state=random_state)

            # Convert the decomposed unitary to Cirq operations and add them to
            # the circuit.
            circuit.append(
                cirq.two_qubit_matrix_to_operations(
                    qubits[permuted_indices[0]],
                    qubits[permuted_indices[1]],
                    special_unitary,
                    allow_partial_czs=False))

    # Don't measure all of the qubits at the end of the circuit because we will
    # need to classically simulate it to compute its heavy set.
    return circuit
示例#10
0
def matrix_to_sycamore_operations(
        target_qubits: List[cirq.GridQubit],
        matrix: np.ndarray) -> Tuple[cirq.OP_TREE, List[cirq.GridQubit]]:
    """A method to convert a unitary matrix to a list of Sycamore operations.

    This method will return a list of `cirq.Operation`s using the qubits and (optionally) ancilla
    qubits to implement the unitary matrix `matrix` on the target qubits `qubits`.
    The operations are also supported by `cirq.google.gate_sets.SYC_GATESET`.

    Args:
        target_qubits: list of qubits the returned operations will act on. The qubit order defined by the list
            is assumed to be used by the operations to implement `matrix`.
        matrix: a matrix that is guaranteed to be unitary and of size (2**len(qs), 2**len(qs)).
    Returns:
        A tuple of operations and ancilla qubits allocated.
            Operations: In case the matrix is supported, a list of operations `ops` is returned.
                `ops` acts on `qs` qubits and for which `cirq.unitary(ops)` is equal to `matrix` up
                 to certain tolerance. In case the matrix is not supported, it might return NotImplemented to
                 reduce the noise in the judge output.
            Ancilla qubits: In case ancilla qubits are allocated a list of ancilla qubits. Otherwise
                an empty list.
        .
    """

    ops = NotImplemented

    if len(target_qubits) == 1:
        ops = cirq.single_qubit_matrix_to_gates(matrix)
        for i, x in enumerate(ops):
            ops[i] = cirq.GateOperation(x, [target_qubits[0]])

    elif len(target_qubits) == 2:
        ops = cirq.two_qubit_matrix_to_operations(target_qubits[0],
                                                  target_qubits[1],
                                                  matrix,
                                                  allow_partial_czs=False,
                                                  atol=1e-4)

    elif len(target_qubits) == 3:
        ops = cirq.three_qubit_matrix_to_operations(target_qubits[0],
                                                    target_qubits[1],
                                                    target_qubits[2],
                                                    matrix,
                                                    atol=1e-4)

    return ops, []
示例#11
0
def test_two_qubit_matrix_to_operations_deprecated():
    q0 = cirq.NamedQubit('q0')
    q1 = cirq.NamedQubit('q1')
    effect = np.array(
        [
            [0, 0, 0, 1],
            [0, 0, 1, 0],
            [0, 1, 0, 0],
            [1, 0, 0, 0j],
        ]
    )

    with cirq.testing.assert_deprecated('two_qubit_matrix_to_cz_operations', deadline='v0.15'):
        _ = cirq.two_qubit_matrix_to_operations(q0, q1, effect, True)
    with cirq.testing.assert_deprecated(
        'two_qubit_matrix_to_diagonal_and_cz_operations', deadline='v0.15'
    ):
        _ = cirq.two_qubit_matrix_to_diagonal_and_operations(q0, q1, effect, True)
示例#12
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_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()