Skip to content

Deprecate optimize_for_sycamore and optimize_for_xmon #5531

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions cirq-core/cirq/contrib/paulistring/recombine_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ def test_move_non_clifford_into_clifford():
_assert_no_multi_qubit_pauli_strings(c_recombined1)
_assert_no_multi_qubit_pauli_strings(c_recombined2)

baseline_len = len(cg.optimized_for_xmon(c_orig))
opt_len1 = len(cg.optimized_for_xmon(c_recombined1))
opt_len2 = len(cg.optimized_for_xmon(c_recombined2))
assert opt_len1 <= baseline_len
assert opt_len2 <= baseline_len
with cirq.testing.assert_deprecated(
'Use cirq.optimize_for_target_gateset', deadline='v0.16', count=None
):
baseline_len = len(cg.optimized_for_xmon(c_orig))
opt_len1 = len(cg.optimized_for_xmon(c_recombined1))
opt_len2 = len(cg.optimized_for_xmon(c_recombined2))
assert opt_len1 <= baseline_len
assert opt_len2 <= baseline_len
12 changes: 12 additions & 0 deletions cirq-google/cirq_google/optimizers/optimize_for_sycamore.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import numpy as np

import cirq
from cirq import _compat
from cirq_google import ops as cg_ops
from cirq_google.transformers.target_gatesets import sycamore_gateset

Expand Down Expand Up @@ -48,6 +49,17 @@ def _gate_product_tabulation_cached(
raise NotImplementedError(f"Two qubit gate tabulation not supported for {optimizer_type}")


@_compat.deprecated(
deadline='v0.16',
fix="""Use `cirq.optimize_for_target_gateset(circuit, gateset=<target_gateset>).`
If `optimizer_type` is 'sqrt_iswap', `gateset=cirq.SqrtIswapTargetGateset(atol=tolerance)`.
If `optimizer_type` is 'sycamore', `gateset=cirq_google.SycamoreTargetGateset(atol=tolerance),
optionally setting tabulation in the SycamoreTargetGateset constructor.
If `optimizer_type` is 'xmon', `gateset=cirq.CZTargetGateset(atol=tolerance).
If `optimizer_type` is 'xmon_partial_cz',
`gateset=cirq.CZTargetGateset(atol=tolerance, allow_partial_czs=True).
""",
)
def optimized_for_sycamore(
circuit: cirq.Circuit,
*,
Expand Down
158 changes: 93 additions & 65 deletions cirq-google/cirq_google/optimizers/optimize_for_sycamore_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@ def test_optimizer_output_gates_are_supported(optimizer_type, gateset):
circuit = cirq.Circuit(
cirq.CZ(q0, q1), cirq.X(q0) ** 0.2, cirq.Z(q1) ** 0.2, cirq.measure(q0, q1, key='m')
)
new_circuit = cg.optimized_for_sycamore(circuit, optimizer_type=optimizer_type)
for moment in new_circuit:
for op in moment:
assert gateset.is_supported_operation(op)

with cirq.testing.assert_deprecated(
'Use `cirq.optimize_for_target_gateset', deadline='v0.16', count=1
):
new_circuit = cg.optimized_for_sycamore(circuit, optimizer_type=optimizer_type)
for moment in new_circuit:
for op in moment:
assert gateset.is_supported_operation(op)


@pytest.mark.parametrize('optimizer_type, gateset', _OPTIMIZERS_AND_GATESETS)
Expand All @@ -53,19 +57,26 @@ def test_optimize_large_measurement_gates(optimizer_type, gateset):
[cirq.CZ(qubits[i], qubits[i + 1]) for i in range(1, len(qubits) - 1, 2)],
cirq.measure(*qubits, key='m'),
)
new_circuit = cg.optimized_for_sycamore(circuit, optimizer_type=optimizer_type)
for moment in new_circuit:
for op in moment:
assert gateset.is_supported_operation(op)

with cirq.testing.assert_deprecated(
'Use `cirq.optimize_for_target_gateset', deadline='v0.16', count=1
):
new_circuit = cg.optimized_for_sycamore(circuit, optimizer_type=optimizer_type)
for moment in new_circuit:
for op in moment:
assert gateset.is_supported_operation(op)


def test_invalid_input():
with pytest.raises(ValueError):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
cirq.CZ(q0, q1), cirq.X(q0) ** 0.2, cirq.Z(q1) ** 0.2, cirq.measure(q0, q1, key='m')
)
_ = cg.optimized_for_sycamore(circuit, optimizer_type='for_tis_100')
with cirq.testing.assert_deprecated(
'Use `cirq.optimize_for_target_gateset', deadline='v0.16', count=1
):
with pytest.raises(ValueError):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
cirq.CZ(q0, q1), cirq.X(q0) ** 0.2, cirq.Z(q1) ** 0.2, cirq.measure(q0, q1, key='m')
)
_ = cg.optimized_for_sycamore(circuit, optimizer_type='for_tis_100')


def test_tabulation():
Expand All @@ -74,53 +85,67 @@ def test_tabulation():
circuit = cirq.Circuit(cirq.MatrixGate(u).on(q0, q1))
np.testing.assert_allclose(u, cirq.unitary(circuit))

circuit2 = cg.optimized_for_sycamore(circuit, optimizer_type='sycamore')
cirq.testing.assert_allclose_up_to_global_phase(u, cirq.unitary(circuit2), atol=1e-5)
assert len(circuit2) == 13

# Note this is run on every commit, so it needs to be relatively quick.
# This requires us to use relatively loose tolerances
circuit3 = cg.optimized_for_sycamore(
circuit, optimizer_type='sycamore', tabulation_resolution=0.1
)
cirq.testing.assert_allclose_up_to_global_phase(u, cirq.unitary(circuit3), rtol=1e-1, atol=1e-1)
assert len(circuit3) == 7
with cirq.testing.assert_deprecated(
'Use `cirq.optimize_for_target_gateset', deadline='v0.16', count=2
):
circuit2 = cg.optimized_for_sycamore(circuit, optimizer_type='sycamore')
cirq.testing.assert_allclose_up_to_global_phase(u, cirq.unitary(circuit2), atol=1e-5)
assert len(circuit2) == 13
# Note this is run on every commit, so it needs to be relatively quick.
# This requires us to use relatively loose tolerances
circuit3 = cg.optimized_for_sycamore(
circuit, optimizer_type='sycamore', tabulation_resolution=0.1
)
cirq.testing.assert_allclose_up_to_global_phase(
u, cirq.unitary(circuit3), rtol=1e-1, atol=1e-1
)
assert len(circuit3) == 7


def test_no_tabulation():
circuit = cirq.Circuit(cirq.X(cirq.LineQubit(0)))
with pytest.raises(NotImplementedError):
cg.optimized_for_sycamore(circuit, optimizer_type='sqrt_iswap', tabulation_resolution=0.01)

with pytest.raises(NotImplementedError):
cg.optimized_for_sycamore(circuit, optimizer_type='xmon', tabulation_resolution=0.01)
with cirq.testing.assert_deprecated(
'Use `cirq.optimize_for_target_gateset', deadline='v0.16', count=3
):
with pytest.raises(NotImplementedError):
cg.optimized_for_sycamore(
circuit, optimizer_type='sqrt_iswap', tabulation_resolution=0.01
)

with pytest.raises(NotImplementedError):
cg.optimized_for_sycamore(
circuit, optimizer_type='xmon_partial_cz', tabulation_resolution=0.01
)
with pytest.raises(NotImplementedError):
cg.optimized_for_sycamore(circuit, optimizer_type='xmon', tabulation_resolution=0.01)

with pytest.raises(NotImplementedError):
cg.optimized_for_sycamore(
circuit, optimizer_type='xmon_partial_cz', tabulation_resolution=0.01
)


def test_one_q_matrix_gate():
u = cirq.testing.random_special_unitary(2)
q = cirq.LineQubit(0)
circuit0 = cirq.Circuit(cirq.MatrixGate(u).on(q))
assert len(circuit0) == 1
circuit_iswap = cg.optimized_for_sycamore(circuit0, optimizer_type='sqrt_iswap')
assert len(circuit_iswap) == 1
for moment in circuit_iswap:
for op in moment:
assert cg.SQRT_ISWAP_GATESET.is_supported_operation(op)
# single qubit gates shared between gatesets, so:
assert cg.SYC_GATESET.is_supported_operation(op)

circuit_syc = cg.optimized_for_sycamore(circuit0, optimizer_type='sycamore')
assert len(circuit_syc) == 1
for moment in circuit_iswap:
for op in moment:
assert cg.SYC_GATESET.is_supported_operation(op)
# single qubit gates shared between gatesets, so:
assert cg.SQRT_ISWAP_GATESET.is_supported_operation(op)

with cirq.testing.assert_deprecated(
'Use `cirq.optimize_for_target_gateset', deadline='v0.16', count=2
):
circuit_iswap = cg.optimized_for_sycamore(circuit0, optimizer_type='sqrt_iswap')
assert len(circuit_iswap) == 1
for moment in circuit_iswap:
for op in moment:
assert cg.SQRT_ISWAP_GATESET.is_supported_operation(op)
# single qubit gates shared between gatesets, so:
assert cg.SYC_GATESET.is_supported_operation(op)

circuit_syc = cg.optimized_for_sycamore(circuit0, optimizer_type='sycamore')
assert len(circuit_syc) == 1
for moment in circuit_iswap:
for op in moment:
assert cg.SYC_GATESET.is_supported_operation(op)
# single qubit gates shared between gatesets, so:
assert cg.SQRT_ISWAP_GATESET.is_supported_operation(op)


@pytest.mark.parametrize(
Expand All @@ -131,20 +156,23 @@ def test_circuit_operation_conversion(optimizer_type, two_qubit_gate_type):
q0, q1 = cirq.LineQubit.range(2)
subcircuit = cirq.FrozenCircuit(cirq.X(q0), cirq.SWAP(q0, q1))
circuit = cirq.Circuit(cirq.CircuitOperation(subcircuit))
converted_circuit = cg.optimized_for_sycamore(circuit, optimizer_type=optimizer_type)
# Verify that the CircuitOperation was preserved.
ops = list(converted_circuit.all_operations())
assert isinstance(ops[0], cirq.CircuitOperation)
# Verify that the contents of the CircuitOperation were optimized.
converted_subcircuit = cg.optimized_for_sycamore(
subcircuit.unfreeze(), optimizer_type=optimizer_type
)
assert len(
[*converted_subcircuit.findall_operations_with_gate_type(two_qubit_gate_type)]
) == len([*ops[0].circuit.findall_operations_with_gate_type(two_qubit_gate_type)])
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
ops[0].circuit, converted_subcircuit, atol=1e-6
)
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
circuit, converted_circuit, atol=1e-6
)
with cirq.testing.assert_deprecated(
'Use `cirq.optimize_for_target_gateset', deadline='v0.16', count=2
):
converted_circuit = cg.optimized_for_sycamore(circuit, optimizer_type=optimizer_type)
# Verify that the CircuitOperation was preserved.
ops = list(converted_circuit.all_operations())
assert isinstance(ops[0], cirq.CircuitOperation)
# Verify that the contents of the CircuitOperation were optimized.
converted_subcircuit = cg.optimized_for_sycamore(
subcircuit.unfreeze(), optimizer_type=optimizer_type
)
assert len(
[*converted_subcircuit.findall_operations_with_gate_type(two_qubit_gate_type)]
) == len([*ops[0].circuit.findall_operations_with_gate_type(two_qubit_gate_type)])
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
ops[0].circuit, converted_subcircuit, atol=1e-6
)
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
circuit, converted_circuit, atol=1e-6
)
6 changes: 6 additions & 0 deletions cirq-google/cirq_google/optimizers/optimize_for_xmon.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@
from typing import Callable, cast, TYPE_CHECKING

import cirq
from cirq import _compat
from cirq_google.optimizers import optimized_for_sycamore

if TYPE_CHECKING:
import cirq_google


@_compat.deprecated(
deadline='v0.16',
# pylint: disable=line-too-long
fix='Use cirq.optimize_for_target_gateset(circuit, gateset=cirq.CZTargetGateset(atol=tolerance, allow_partial_czs=allow_partial_czs)).',
)
def optimized_for_xmon(
circuit: cirq.Circuit,
qubit_map: Callable[[cirq.Qid], cirq.GridQubit] = lambda e: cast(cirq.GridQubit, e),
Expand Down
79 changes: 47 additions & 32 deletions cirq-google/cirq_google/optimizers/optimize_for_xmon_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,64 +28,79 @@ def test_swap_field(n: int, d: int):
)
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)
with cirq.testing.assert_deprecated(
'Use cirq.optimize_for_target_gateset', deadline='v0.16', count=2
):
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)


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)
with cirq.testing.assert_deprecated(
'Use cirq.optimize_for_target_gateset', deadline='v0.16', count=2
):
after = cg.optimized_for_xmon(before)

assert len(after) <= 22
assert_circuits_with_terminal_measurements_are_equivalent(before, after, atol=1e-4)
assert len(after) <= 22
assert_circuits_with_terminal_measurements_are_equivalent(before, after, atol=1e-4)


def test_remap_qubits():
before = cirq.Circuit([cirq.Moment([cirq.CZ(cirq.LineQubit(0), cirq.LineQubit(1))])])

after = cg.optimized_for_xmon(before, qubit_map=lambda q: cirq.GridQubit(q.x, 0))
with cirq.testing.assert_deprecated(
'Use cirq.optimize_for_target_gateset', deadline='v0.16', count=2
):
after = cg.optimized_for_xmon(before, 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))])]
)
assert after == cirq.Circuit(
[cirq.Moment([cirq.CZ(cirq.GridQubit(0, 0), cirq.GridQubit(1, 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)
with cirq.testing.assert_deprecated(
'Use cirq.optimize_for_target_gateset', deadline='v0.16', count=2
):
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.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 == 2
assert num_part_cz == 0
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 == 2
assert num_part_cz == 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
with cirq.testing.assert_deprecated(
'Use cirq.optimize_for_target_gateset', deadline='v0.16', count=2
):
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
6 changes: 5 additions & 1 deletion examples/advanced/quantum_volume_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import pytest

import cirq
from examples.advanced import quantum_volume


Expand All @@ -10,7 +11,10 @@ def test_main_loop():
# Keep test from taking a long time by lowering repetitions.
pytest.importorskip("cirq_google")
args = '--num_qubits 5 --depth 5 --num_circuits 1 --routes 3'.split()
quantum_volume.main(**quantum_volume.parse_arguments(args))
with cirq.testing.assert_deprecated(
'Use cirq.optimize_for_target_gateset', deadline='v0.16', count=None
):
quantum_volume.main(**quantum_volume.parse_arguments(args))


def test_parse_args():
Expand Down
Loading