Ejemplo n.º 1
0
def test_ccz():
    before = cirq.Circuit(
        cirq.CCZ(cirq.GridQubit(5, 5), cirq.GridQubit(5, 6),
                 cirq.GridQubit(5, 7)))

    after = cg.optimized_for_xmon(before)

    assert len(after) <= 22
    assert_circuits_with_terminal_measurements_are_equivalent(before,
                                                              after,
                                                              atol=1e-4)
Ejemplo n.º 2
0
def test_remap_qubits():
    before = cirq.Circuit(
        [cirq.Moment([cirq.CZ(cirq.LineQubit(0), cirq.LineQubit(1))])])

    after = cg.optimized_for_xmon(before,
                                  new_device=cg.Foxtail,
                                  qubit_map=lambda q: cirq.GridQubit(q.x, 0))

    assert after == cirq.Circuit(
        [cirq.Moment([cirq.CZ(cirq.GridQubit(0, 0), cirq.GridQubit(1, 0))])],
        device=cg.Foxtail)
Ejemplo n.º 3
0
def test_ccz():
    before = cirq.Circuit.from_ops(
        cirq.CCZ(cirq.GridQubit(5, 5),
                 cirq.GridQubit(5, 6),
                 cirq.GridQubit(5, 7)))

    after = cg.optimized_for_xmon(before)

    assert len(after) <= 22
    assert_circuits_with_terminal_measurements_are_equivalent(
        before, after, atol=1e-4)
Ejemplo n.º 4
0
def test_swap_field(n: int, d: int):
    before = cirq.Circuit(
        cirq.ISWAP(cirq.LineQubit(j), cirq.LineQubit(j + 1)) for i in range(d)
        for j in range(i % 2, n - 1, 2))
    before.append(cirq.measure(*before.all_qubits()))

    after = cg.optimized_for_xmon(before)
    assert len(after) == d * 4 + 2
    if n <= 5:
        assert_circuits_with_terminal_measurements_are_equivalent(before,
                                                                  after,
                                                                  atol=1e-4)
Ejemplo n.º 5
0
def test_remap_qubits():
    before = cirq.Circuit([cirq.Moment([
        cirq.CZ(cirq.LineQubit(0), cirq.LineQubit(1))])])

    after = cg.optimized_for_xmon(before,
                                  new_device=cg.Foxtail,
                                  qubit_map=lambda q: cirq.GridQubit(q.x, 0))

    assert after == cirq.Circuit([
        cirq.Moment([
            cg.Exp11Gate().on(cirq.GridQubit(0, 0), cirq.GridQubit(1, 0))])],
        device=cg.Foxtail)
Ejemplo n.º 6
0
def test_dont_allow_partial_czs():
    before = cirq.Circuit([cirq.Moment([
        cirq.CZ(cirq.GridQubit(5, 5), cirq.GridQubit(5, 6)) ** 0.5])])

    after = cg.optimized_for_xmon(before, allow_partial_czs=False)

    cz_gates = [op.gate for op in after.all_operations()
                if isinstance(op, cirq.GateOperation) and
                isinstance(op.gate, cirq.Rot11Gate)]
    num_full_cz = sum(1 for cz in cz_gates if cz.half_turns == 1)
    num_part_cz = sum(1 for cz in cz_gates if cz.half_turns != 1)
    assert num_full_cz == 2
    assert num_part_cz == 0
Ejemplo n.º 7
0
def test_dont_allow_partial_czs():
    before = cirq.Circuit([cirq.Moment([
        cirq.CZ(cirq.GridQubit(5, 5), cirq.GridQubit(5, 6)) ** 0.5])])

    after = cg.optimized_for_xmon(before, allow_partial_czs=False)

    cz_gates = [op.gate for op in after.all_operations()
                        if cg.XmonGate.is_xmon_op(op) and
                           isinstance(op.gate, cg.Exp11Gate)]
    num_full_cz = sum(1 for cz in cz_gates if cz.half_turns == 1)
    num_part_cz = sum(1 for cz in cz_gates if cz.half_turns != 1)
    assert num_full_cz == 2
    assert num_part_cz == 0
Ejemplo n.º 8
0
def test_adjacent_cz_get_split_apart():
    before = cirq.Circuit([cirq.Moment([
        cirq.CZ(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)),
        cirq.CZ(cirq.GridQubit(1, 0), cirq.GridQubit(1, 1))])])

    after = cg.optimized_for_xmon(before,
                                  new_device=cg.Foxtail)

    assert after == cirq.Circuit([
        cirq.Moment([
            cirq.CZ(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1))]),
        cirq.Moment([
            cirq.CZ(cirq.GridQubit(1, 0), cirq.GridQubit(1, 1))])],
        device=cg.Foxtail)
Ejemplo n.º 9
0
def test_adjacent_cz_get_split_apart():
    before = cirq.Circuit([cirq.Moment([
        cirq.CZ(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)),
        cirq.CZ(cirq.GridQubit(1, 0), cirq.GridQubit(1, 1))])])

    after = cg.optimized_for_xmon(before,
                                  new_device=cg.Foxtail)

    assert after == cirq.Circuit([
        cirq.Moment([
            cg.Exp11Gate().on(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1))]),
        cirq.Moment([
            cg.Exp11Gate().on(cirq.GridQubit(1, 0), cirq.GridQubit(1, 1))])],
        device=cg.Foxtail)
Ejemplo n.º 10
0
def test_swap_field(n: int, d: int):
    before = cirq.Circuit.from_ops(
        cirq.ISWAP(cirq.LineQubit(j), cirq.LineQubit(j + 1))
        for i in range(d)
        for j in range(i % 2, n - 1, 2)
    )
    before.append(cirq.measure(*before.all_qubits()))

    after = cg.optimized_for_xmon(before)

    assert len(after) == d*4 + 2
    if n <= 5:
        assert_circuits_with_terminal_measurements_are_equivalent(
            before, after, atol=1e-4)
Ejemplo n.º 11
0
def test_allow_partial_czs():
    before = cirq.Circuit([
        cirq.Moment([cirq.CZ(cirq.GridQubit(5, 5), cirq.GridQubit(5, 6))**0.5])
    ])

    after = cg.optimized_for_xmon(before, allow_partial_czs=True)

    cz_gates = [
        op.gate for op in after.all_operations()
        if isinstance(op, cirq.GateOperation)
        and isinstance(op.gate, cirq.CZPowGate)
    ]
    num_full_cz = sum(1 for cz in cz_gates if cz.exponent % 2 == 1)
    num_part_cz = sum(1 for cz in cz_gates if cz.exponent % 2 != 1)
    assert num_full_cz == 0
    assert num_part_cz == 1
Ejemplo n.º 12
0
def converted_gate_set(circuit: circuits.Circuit, atol: float = 1e-7
                       ) -> circuits.Circuit:
    """Returns a new, equivalent circuit using the gate set {CliffordGate,
    PauliInteractionGate, PauliStringPhasor}.

    The circuit structure may differ because it is optimized during conversion.
    """
    xmon_circuit = google.optimized_for_xmon(circuit, allow_partial_czs=False)

    qubits = circuit.all_qubits()
    tol = linalg.Tolerance(atol=atol)

    def is_clifford_rotation(half_turns):
        return tol.all_near_zero_mod(half_turns, 0.5)

    def to_quarter_turns(half_turns):
        return round(2 * half_turns) % 4

    def is_quarter_turn(half_turns):
        return (is_clifford_rotation(half_turns) and
                to_quarter_turns(half_turns) % 2 == 1)

    def is_half_turn(half_turns):
        return (is_clifford_rotation(half_turns) and
                to_quarter_turns(half_turns) == 2)

    def is_no_turn(half_turns):
        return (is_clifford_rotation(half_turns) and
                to_quarter_turns(half_turns) == 0)

    def rotation_to_clifford_op(pauli, qubit, half_turns):
        quarter_turns = to_quarter_turns(half_turns)
        if quarter_turns == 0:
            return ops.CliffordGate.I(qubit)
        elif quarter_turns == 2:
            return ops.CliffordGate.from_pauli(pauli)(qubit)
        else:
            gate = ops.CliffordGate.from_pauli(pauli, True)(qubit)
            if quarter_turns == 3:
                gate = gate.inverse()
            return gate

    def rotation_to_non_clifford_op(pauli, qubit, half_turns):
        return PauliStringPhasor(ops.PauliString.from_single(qubit, pauli),
                                 half_turns=half_turns)

    def single_qubit_matrix_to_ops(mat, qubit):
        # Decompose matrix
        z_rad_before, y_rad, z_rad_after = (
            linalg.deconstruct_single_qubit_matrix_into_angles(mat))
        z_ht_before = z_rad_before / np.pi - 0.5
        m_ht = y_rad / np.pi
        m_pauli = ops.Pauli.X
        z_ht_after = z_rad_after / np.pi + 0.5

        # Clean up angles
        if is_clifford_rotation(z_ht_before):
            if is_quarter_turn(z_ht_before) or is_quarter_turn(z_ht_after):
                z_ht_before += 0.5
                z_ht_after -= 0.5
                m_pauli = ops.Pauli.Y
            if is_half_turn(z_ht_before) or is_half_turn(z_ht_after):
                z_ht_before -= 1
                z_ht_after += 1
                m_ht = -m_ht
        if is_no_turn(m_ht):
            z_ht_before += z_ht_after
            z_ht_after = 0
        elif is_half_turn(m_ht):
            z_ht_after -= z_ht_before
            z_ht_before = 0

        # Generate operations
        rotation_list = [
            (ops.Pauli.Z, z_ht_before),
            (m_pauli, m_ht),
            (ops.Pauli.Z, z_ht_after)]
        is_clifford_list = [is_clifford_rotation(ht)
                            for pauli, ht in rotation_list]
        op_list = [rotation_to_clifford_op(pauli, qubit, ht) if is_clifford
                   else rotation_to_non_clifford_op(pauli, qubit, ht)
                   for is_clifford, (pauli, ht) in
                        zip(is_clifford_list, rotation_list)]

        # Merge adjacent Clifford gates
        for i in reversed(range(len(op_list) - 1)):
            if is_clifford_list[i] and is_clifford_list[i+1]:
                op_list[i] = op_list[i].gate.merged_with(op_list[i+1].gate
                                                         )(qubit)
                is_clifford_list.pop(i+1)
                op_list.pop(i+1)

        # Yield non-identity ops
        for is_clifford, op in zip(is_clifford_list, op_list):
            if is_clifford and op.gate == ops.CliffordGate.I:
                continue
            yield op

    def generate_ops():
        conv_cz = ops.PauliInteractionGate(ops.Pauli.Z, False,
                                           ops.Pauli.Z, False)
        matrices = {qubit: np.eye(2) for qubit in qubits}

        def clear_matrices(qubits):
            for qubit in qubits:
                yield single_qubit_matrix_to_ops(matrices[qubit], qubit)
                matrices[qubit] = np.eye(2)

        for op in xmon_circuit.all_operations():
            # Assumes all Xmon operations are GateOperation
            gate = op.gate
            if isinstance(gate, google.XmonMeasurementGate):
                yield clear_matrices(op.qubits)
                yield ops.MeasurementGate(gate.key, gate.invert_mask
                                          )(*op.qubits)
            elif len(op.qubits) == 1:
                # Collect all one qubit rotations
                # Assumes all Xmon gates implement KnownMatrix
                qubit, = op.qubits
                matrices[qubit] = op.matrix().dot(matrices[qubit])
            elif isinstance(gate, google.Exp11Gate):
                yield clear_matrices(op.qubits)
                if gate.half_turns != 1:
                    # coverage: ignore
                    raise ValueError('Unexpected partial CZ: {}'.format(op))
                yield conv_cz(*op.qubits)
            else:
                # coverage: ignore
                raise TypeError('Unknown Xmon operation: {}'.format(op))

        yield clear_matrices(qubits)

    return circuits.Circuit.from_ops(
                generate_ops(),
                strategy=circuits.InsertStrategy.EARLIEST)
Ejemplo n.º 13
0
def converted_gate_set(circuit: circuits.Circuit,
                       atol: float = 1e-7) -> circuits.Circuit:
    """Returns a new, equivalent circuit using the gate set {CliffordGate,
    PauliInteractionGate, PauliStringPhasor}.

    The circuit structure may differ because it is optimized during conversion.
    """
    xmon_circuit = google.optimized_for_xmon(circuit, allow_partial_czs=False)

    qubits = circuit.all_qubits()
    tol = linalg.Tolerance(atol=atol)

    def is_clifford_rotation(half_turns):
        return tol.all_near_zero_mod(half_turns, 0.5)

    def to_quarter_turns(half_turns):
        return round(2 * half_turns) % 4

    def is_quarter_turn(half_turns):
        return (is_clifford_rotation(half_turns)
                and to_quarter_turns(half_turns) % 2 == 1)

    def is_half_turn(half_turns):
        return (is_clifford_rotation(half_turns)
                and to_quarter_turns(half_turns) == 2)

    def is_no_turn(half_turns):
        return (is_clifford_rotation(half_turns)
                and to_quarter_turns(half_turns) == 0)

    def rotation_to_clifford_op(pauli, qubit, half_turns):
        quarter_turns = to_quarter_turns(half_turns)
        if quarter_turns == 0:
            return ops.CliffordGate.I(qubit)
        elif quarter_turns == 2:
            return ops.CliffordGate.from_pauli(pauli)(qubit)
        else:
            gate = ops.CliffordGate.from_pauli(pauli, True)(qubit)
            if quarter_turns == 3:
                gate = gate.inverse()
            return gate

    def rotation_to_non_clifford_op(pauli, qubit, half_turns):
        return PauliStringPhasor(ops.PauliString.from_single(qubit, pauli),
                                 half_turns=half_turns)

    def single_qubit_matrix_to_ops(mat, qubit):
        # Decompose matrix
        z_rad_before, y_rad, z_rad_after = (
            linalg.deconstruct_single_qubit_matrix_into_angles(mat))
        z_ht_before = z_rad_before / np.pi - 0.5
        m_ht = y_rad / np.pi
        m_pauli = ops.Pauli.X
        z_ht_after = z_rad_after / np.pi + 0.5

        # Clean up angles
        if is_clifford_rotation(z_ht_before):
            if is_quarter_turn(z_ht_before) or is_quarter_turn(z_ht_after):
                z_ht_before += 0.5
                z_ht_after -= 0.5
                m_pauli = ops.Pauli.Y
            if is_half_turn(z_ht_before) or is_half_turn(z_ht_after):
                z_ht_before -= 1
                z_ht_after += 1
                m_ht = -m_ht
        if is_no_turn(m_ht):
            z_ht_before += z_ht_after
            z_ht_after = 0
        elif is_half_turn(m_ht):
            z_ht_after -= z_ht_before
            z_ht_before = 0

        # Generate operations
        rotation_list = [(ops.Pauli.Z, z_ht_before), (m_pauli, m_ht),
                         (ops.Pauli.Z, z_ht_after)]
        is_clifford_list = [
            is_clifford_rotation(ht) for pauli, ht in rotation_list
        ]
        op_list = [
            rotation_to_clifford_op(pauli, qubit, ht)
            if is_clifford else rotation_to_non_clifford_op(pauli, qubit, ht)
            for is_clifford, (pauli,
                              ht) in zip(is_clifford_list, rotation_list)
        ]

        # Merge adjacent Clifford gates
        for i in reversed(range(len(op_list) - 1)):
            if is_clifford_list[i] and is_clifford_list[i + 1]:
                op_list[i] = op_list[i].gate.merged_with(
                    op_list[i + 1].gate)(qubit)
                is_clifford_list.pop(i + 1)
                op_list.pop(i + 1)

        # Yield non-identity ops
        for is_clifford, op in zip(is_clifford_list, op_list):
            if is_clifford and op.gate == ops.CliffordGate.I:
                continue
            yield op

    def generate_ops():
        conv_cz = ops.PauliInteractionGate(ops.Pauli.Z, False, ops.Pauli.Z,
                                           False)
        matrices = {qubit: np.eye(2) for qubit in qubits}

        def clear_matrices(qubits):
            for qubit in qubits:
                yield single_qubit_matrix_to_ops(matrices[qubit], qubit)
                matrices[qubit] = np.eye(2)

        for op in xmon_circuit.all_operations():
            # Assumes all Xmon operations are GateOperation
            gate = op.gate
            if isinstance(gate, google.XmonMeasurementGate):
                yield clear_matrices(op.qubits)
                yield ops.MeasurementGate(gate.key,
                                          gate.invert_mask)(*op.qubits)
            elif len(op.qubits) == 1:
                # Collect all one qubit rotations
                # Assumes all Xmon gates implement KnownMatrix
                qubit, = op.qubits
                matrices[qubit] = op.matrix().dot(matrices[qubit])
            elif isinstance(gate, google.Exp11Gate):
                yield clear_matrices(op.qubits)
                if gate.half_turns != 1:
                    # coverage: ignore
                    raise ValueError('Unexpected partial CZ: {}'.format(op))
                yield conv_cz(*op.qubits)
            else:
                # coverage: ignore
                raise TypeError('Unknown Xmon operation: {}'.format(op))

        yield clear_matrices(qubits)

    return circuits.Circuit.from_ops(generate_ops(),
                                     strategy=circuits.InsertStrategy.EARLIEST)