예제 #1
0
def assert_optimizes(
    before: cirq.Circuit,
    expected: cirq.Circuit,
    eject_parameterized: bool = False,
    *,
    with_context: bool = False,
):
    if cirq.has_unitary(before):
        cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
            before, expected, atol=1e-8)
    context = cirq.TransformerContext(
        tags_to_ignore=("nocompile", )) if with_context else None
    circuit = cirq.eject_z(before,
                           eject_parameterized=eject_parameterized,
                           context=context)
    expected = cirq.eject_z(expected,
                            eject_parameterized=eject_parameterized,
                            context=context)
    cirq.testing.assert_same_circuits(circuit, expected)

    # And it should be idempotent.
    circuit = cirq.eject_z(before,
                           eject_parameterized=eject_parameterized,
                           context=context)
    cirq.testing.assert_same_circuits(circuit, expected)
예제 #2
0
def test_eject_phased_xz():
    a = cirq.NamedQubit('a')
    b = cirq.NamedQubit('b')
    c = cirq.Circuit(
        cirq.PhasedXZGate(x_exponent=1, z_exponent=0.5, axis_phase_exponent=0.5).on(a),
        cirq.CZ(a, b) ** 0.25,
    )
    c_expected = cirq.Circuit(
        cirq.CZ(a, b) ** -0.25, cirq.PhasedXPowGate(phase_exponent=0.75).on(a), cirq.T(b)
    )
    cirq.testing.assert_same_circuits(
        cirq.eject_z(cirq.eject_phased_paulis(cirq.eject_z(c))), c_expected
    )
    cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(c, c_expected, 1e-8)
예제 #3
0
def optimized_for_sycamore(
    circuit: cirq.Circuit,
    *,
    qubit_map: Callable[[cirq.Qid], cirq.GridQubit] = lambda e: cast(cirq.GridQubit, e),
    optimizer_type: str = 'sqrt_iswap',
    tolerance: float = 1e-5,
    tabulation_resolution: Optional[float] = None,
) -> cirq.Circuit:
    """Optimizes a circuit for Google devices.

    Uses a set of optimizers that will compile to the proper gateset for the
    device (xmon, sqrt_iswap, or sycamore gates) and then use optimizers to
    compress the gate depth down as much as is easily algorithmically possible
    by merging rotations, ejecting Z gates, etc.

    Args:
        circuit: The circuit to optimize.
        qubit_map: Transforms the qubits (e.g. so that they are GridQubits).
        optimizer_type: A string defining the optimizations to apply.
            Possible values are  'xmon', 'xmon_partial_cz', 'sqrt_iswap',
            'sycamore'
        tolerance: The tolerance passed to the various circuit optimization
            passes.
        tabulation_resolution: If provided, compute a gateset tabulation
            with the specified resolution and use it to approximately
            compile arbitrary two-qubit gates for which an analytic compilation
            is not known.
    Returns:
        The optimized circuit.

    Raises:
        ValueError: If the `optimizer_type` is not a supported type.
    """
    copy = circuit.copy()
    if optimizer_type not in _TARGET_GATESETS:
        raise ValueError(
            f'{optimizer_type} is not an allowed type.  Allowed '
            f'types are: {_TARGET_GATESETS.keys()}'
        )

    tabulation: Optional[cirq.TwoQubitGateTabulation] = None
    if tabulation_resolution is not None:
        tabulation = _gate_product_tabulation_cached(optimizer_type, tabulation_resolution)

    if optimizer_type in _TARGET_GATESETS:
        copy = cirq.optimize_for_target_gateset(
            circuit,
            gateset=_TARGET_GATESETS[optimizer_type](tolerance, tabulation),
            context=cirq.TransformerContext(deep=True),
        )
    copy = cirq.merge_single_qubit_gates_to_phxz(copy, atol=tolerance)
    copy = cirq.eject_phased_paulis(copy, atol=tolerance)
    copy = cirq.eject_z(copy, atol=tolerance)
    copy = cirq.drop_negligible_operations(copy, atol=tolerance)

    ret = cirq.Circuit(
        (op.transform_qubits(qubit_map) for op in copy.all_operations()),
        strategy=cirq.InsertStrategy.EARLIEST,
    )
    return ret
예제 #4
0
def simplify_circuit(
    circuit: cirq.Circuit,
    *,
    max_iterations: int = 20,
    drop_final_rz: bool = False,
) -> cirq.Circuit:
    """Simplifies and optimizes the given circuit.

    Currently it

    * merges any neighboring gates belonging to the same one-parameter family
    * merges all one-qubit rotations into phased X rotations followed by Z rotations
    * pushes the Z rotations towards the end of the circuit as far as possible
    * drops any empty Moments

    This sequence of optimization passes is repeated until the circuit hits a fixed point,
    or ``max_iterations`` is exceeded.

    Finally, it removes Z rotations that are immediately followed by a Z-basis measurement.

    Args:
        circuit: circuit to simplify
        max_iterations: maximum number of simplification rounds
        drop_final_rz: iff True, drop z rotations that have no successor operations

    Returns:
        simplified circuit
    """
    c = circuit.copy()

    # the optimizers cause the immediate decomposition of any gates they insert into the Circuit
    for _ in range(max_iterations):
        # It seems that Cirq optimizers have no way of communicating
        # if they actually made any changes to the Circuit.
        # See https://github.com/quantumlib/Cirq/issues/3761

        before = c.copy()

        # all mergeable 2-qubit gates are merged
        MergeOneParameterGroupGates().optimize_circuit(c)
        c = cirq.merge_single_qubit_gates_to_phased_x_and_z(c)
        # all z rotations are pushed past the first two-qubit gate following them
        c = cirq.eject_z(c, eject_parameterized=True)
        c = cirq.drop_empty_moments(c)

        if c == before:
            # the optimization hit a fixed point
            break

    DropRZBeforeMeasurement(drop_final=drop_final_rz).optimize_circuit(c)
    c = cirq.drop_empty_moments(c)

    return c
예제 #5
0
def test_swap_iswap(exponent):
    a, b = cirq.LineQubit.range(2)
    original = cirq.Circuit([cirq.rz(0.123).on(a), cirq.ISWAP(a, b)**exponent])
    optimized = original.copy()

    optimized = cirq.eject_z(optimized)
    optimized = cirq.drop_empty_moments(optimized)

    assert optimized[0].operations == (cirq.ISWAP(a, b)**exponent, )
    # Note: EjectZ drops `global_phase` from Rz turning it into a Z
    assert optimized[1].operations == (cirq.Z(b)**(0.123 / np.pi), )
    cirq.testing.assert_allclose_up_to_global_phase(cirq.unitary(original),
                                                    cirq.unitary(optimized),
                                                    atol=1e-8)
예제 #6
0
    def test_eject_z(self, family, ex, qubits):
        """Commuting z rotations towards the end of the circuit."""

        q0, q1 = qubits[:2]

        c = cirq.Circuit()
        c.append([
            cirq.ZPowGate(exponent=0.3)(q0),
            cirq.ZPowGate(exponent=0.8)(q1),
            family(exponent=ex)(q0, q1),
            cirq.MeasurementGate(1, key='q0')(q0),
            cirq.MeasurementGate(1, key='q1')(q1),
        ])

        c = cirq.eject_z(c)
        c = cirq.drop_empty_moments(c)

        # the ZPowGates have been commuted and canceled
        assert len(c) == 2
예제 #7
0
def assert_removes_all_z_gates(circuit: cirq.Circuit,
                               eject_parameterized: bool = True):
    optimized = cirq.eject_z(circuit, eject_parameterized=eject_parameterized)
    for op in optimized.all_operations():
        # assert _try_get_known_z_half_turns(op, eject_parameterized) is None
        if isinstance(op.gate, cirq.PhasedXZGate) and (
                eject_parameterized
                or not cirq.is_parameterized(op.gate.z_exponent)):
            assert op.gate.z_exponent == 0

    if cirq.is_parameterized(circuit):
        for a in (0, 0.1, 0.5, 1.0, -1.0, 3.0):
            (cirq.testing.
             assert_circuits_with_terminal_measurements_are_equivalent(
                 cirq.resolve_parameters(circuit, {'a': a}),
                 cirq.resolve_parameters(optimized, {'a': a}),
                 atol=1e-8,
             ))
    else:
        cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
            circuit, optimized, atol=1e-8)
예제 #8
0
def assert_optimizes(
    before: cirq.Circuit,
    expected: cirq.Circuit,
    eject_parameterized: bool = False,
    *,
    with_context: bool = False,
):
    if cirq.has_unitary(before):
        cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
            before, expected, atol=1e-8)
    context = cirq.TransformerContext(
        tags_to_ignore=("nocompile", )) if with_context else None
    circuit = cirq.eject_z(before,
                           eject_parameterized=eject_parameterized,
                           context=context)
    expected = cirq.eject_z(expected,
                            eject_parameterized=eject_parameterized,
                            context=context)
    cirq.testing.assert_same_circuits(circuit, expected)

    # And it should be idempotent.
    circuit = cirq.eject_z(before,
                           eject_parameterized=eject_parameterized,
                           context=context)
    cirq.testing.assert_same_circuits(circuit, expected)

    # Nested sub-circuits should also get optimized.
    q = before.all_qubits()
    c_nested = cirq.Circuit(
        [(cirq.Z**0.5).on_each(*q), (cirq.Y**0.25).on_each(*q)],
        cirq.Moment(
            cirq.CircuitOperation(
                before.freeze()).repeat(2).with_tags("ignore")),
        [(cirq.Z**0.5).on_each(*q), (cirq.Y**0.25).on_each(*q)],
        cirq.Moment(
            cirq.CircuitOperation(
                before.freeze()).repeat(3).with_tags("preserve_tag")),
    )
    c_expected = cirq.Circuit(
        cirq.PhasedXPowGate(phase_exponent=0, exponent=0.25).on_each(*q),
        (cirq.Z**0.5).on_each(*q),
        cirq.Moment(
            cirq.CircuitOperation(
                before.freeze()).repeat(2).with_tags("ignore")),
        cirq.PhasedXPowGate(phase_exponent=0, exponent=0.25).on_each(*q),
        (cirq.Z**0.5).on_each(*q),
        cirq.Moment(
            cirq.CircuitOperation(
                expected.freeze()).repeat(3).with_tags("preserve_tag")),
    )
    if context is None:
        context = cirq.TransformerContext(tags_to_ignore=("ignore", ),
                                          deep=True)
    else:
        context = dataclasses.replace(context,
                                      tags_to_ignore=context.tags_to_ignore +
                                      ("ignore", ),
                                      deep=True)
    c_nested = cirq.eject_z(c_nested,
                            context=context,
                            eject_parameterized=eject_parameterized)
    cirq.testing.assert_same_circuits(c_nested, c_expected)
    c_nested = cirq.eject_z(c_nested,
                            context=context,
                            eject_parameterized=eject_parameterized)
    cirq.testing.assert_same_circuits(c_nested, c_expected)