예제 #1
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
def test_clears_known_empties_even_at_zero_tolerance():
    a, b = cirq.LineQubit.range(2)
    circuit = cirq.Circuit(
        cirq.Z(a)**0,
        cirq.Y(a)**0.0000001,
        cirq.X(a)**-0.0000001,
        cirq.CZ(a, b)**0)
    cirq.testing.assert_same_circuits(
        cirq.drop_negligible_operations(circuit, atol=0.001),
        cirq.Circuit([cirq.Moment()] * 4))
    cirq.testing.assert_same_circuits(
        cirq.drop_negligible_operations(circuit, atol=0),
        cirq.Circuit(
            cirq.Moment(),
            cirq.Moment(cirq.Y(a)**0.0000001),
            cirq.Moment(cirq.X(a)**-0.0000001),
            cirq.Moment(),
        ),
    )
def test_does_not_clear_small_no_compile():
    a = cirq.NamedQubit('a')
    circuit = cirq.Circuit(
        cirq.Moment((cirq.Z(a)**0.000001).with_tags(NO_COMPILE_TAG)))
    cirq.testing.assert_same_circuits(
        cirq.drop_negligible_operations(
            circuit,
            context=cirq.TransformerContext(tags_to_ignore=(NO_COMPILE_TAG, )),
            atol=0.001),
        circuit,
    )
def test_drop_negligible():
    (q0, ) = _make_qubits(1)
    sym = sympy.Symbol('a')
    circuit = cirq.Circuit(
        cirq.PauliStringPhasor(cirq.PauliString({q0: cirq.Z}))**0.25,
        cirq.PauliStringPhasor(cirq.PauliString({q0: cirq.Z}))**1e-10,
        cirq.PauliStringPhasor(cirq.PauliString({q0: cirq.Z}))**sym,
    )
    expected = cirq.Circuit(
        cirq.PauliStringPhasor(cirq.PauliString({q0: cirq.Z}))**0.25,
        cirq.PauliStringPhasor(cirq.PauliString({q0: cirq.Z}))**sym,
    )
    circuit = cirq.drop_negligible_operations(circuit)
    circuit = cirq.drop_empty_moments(circuit)
    assert circuit == expected
def test_recursively_runs_inside_circuit_ops_deep():
    a = cirq.NamedQubit('a')
    small_op = cirq.Z(a)**0.000001
    nested_circuit = cirq.FrozenCircuit(cirq.X(a), small_op,
                                        small_op.with_tags(NO_COMPILE_TAG),
                                        small_op, cirq.Y(a))
    nested_circuit_dropped = cirq.FrozenCircuit(
        cirq.Moment(cirq.X(a)),
        cirq.Moment(),
        cirq.Moment(small_op.with_tags(NO_COMPILE_TAG)),
        cirq.Moment(),
        cirq.Moment(cirq.Y(a)),
    )
    c_orig = cirq.Circuit(
        small_op,
        cirq.CircuitOperation(nested_circuit).repeat(6).with_tags(
            NO_COMPILE_TAG),
        small_op,
        cirq.CircuitOperation(nested_circuit).repeat(5).with_tags(
            "preserve_tag"),
        small_op,
    )
    c_expected = cirq.Circuit(
        cirq.Moment(),
        cirq.Moment(
            cirq.CircuitOperation(nested_circuit).repeat(6).with_tags(
                NO_COMPILE_TAG)),
        cirq.Moment(),
        cirq.Moment(
            cirq.CircuitOperation(nested_circuit_dropped).repeat(5).with_tags(
                "preserve_tag")),
        cirq.Moment(),
    )
    context = cirq.TransformerContext(tags_to_ignore=[NO_COMPILE_TAG],
                                      deep=True)
    cirq.testing.assert_same_circuits(
        cirq.drop_negligible_operations(c_orig, context=context, atol=0.001),
        c_expected)
예제 #6
0
def simplify_expectation_value_circuit(circuit_sand: cirq.Circuit):
    """For low weight operators on low-degree circuits, we can simplify
    the circuit representation of an expectation value.

    In particular, this should be used on `circuit_for_expectation_value`
    circuits. It will merge single- and two-qubit gates from the "forwards"
    and "backwards" parts of the circuit outside of the operator's lightcone.

    This might be too slow in practice and you can just use quimb to simplify
    things for you.
    """
    n_op = sum(1 for _ in circuit_sand.all_operations())
    while True:
        MergeNQubitGates(n_qubits=1).optimize_circuit(circuit_sand)
        circuit_sand = cirq.drop_negligible_operations(circuit_sand, atol=1e-6)
        MergeNQubitGates(n_qubits=2).optimize_circuit(circuit_sand)
        circuit_sand = cirq.drop_empty_moments(circuit_sand)
        new_n_op = sum(1 for _ in circuit_sand.all_operations())

        if new_n_op < n_op:
            n_op = new_n_op
        else:
            return
def test_clears_small():
    a = cirq.NamedQubit('a')
    circuit = cirq.Circuit(cirq.Moment(cirq.Z(a)**0.000001))
    cirq.testing.assert_same_circuits(
        cirq.drop_negligible_operations(circuit, atol=0.001),
        cirq.Circuit(cirq.Moment()))