Skip to content

Commit

Permalink
Add cg.SycamoreTargetGateset and deprecate `cg.ConvertToSycamoreGat…
Browse files Browse the repository at this point in the history
…es` (#5054)

- Part of #5028
- Follows the new Transformer API #4483
- Supports no compile tags NoCompile Tag for optimizers #4253
  • Loading branch information
tanujkhattar authored Mar 14, 2022
1 parent c76bbc7 commit 889e5d2
Show file tree
Hide file tree
Showing 9 changed files with 580 additions and 30 deletions.
1 change: 1 addition & 0 deletions cirq-google/cirq_google/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
from cirq_google.transformers import (
known_2q_op_to_sycamore_operations,
two_qubit_matrix_to_sycamore_operations,
SycamoreTargetGateset,
)

from cirq_google.serialization import (
Expand Down
1 change: 1 addition & 0 deletions cirq-google/cirq_google/json_test_data/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
'WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION',
'XmonDevice',
'XMON',
'SycamoreTargetGateset',
],
should_not_be_serialized=[
'AnnealSequenceSearchStrategy',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
from cirq_google.transformers.analytical_decompositions import two_qubit_to_sycamore


@cirq._compat.deprecated_class(
deadline='v1.0',
fix='Use cirq.optimize_for_target_gateset and cirq_google.SycamoreTargetGateset instead.',
)
class ConvertToSycamoreGates(cirq.PointOptimizer):
"""Attempts to convert non-native gates into SycamoreGates.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ def test_convert_to_sycamore_gates_swap_zz():
)

compiled_circuit1 = circuit1.copy()
cgoc.ConvertToSycamoreGates()(compiled_circuit1)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
cgoc.ConvertToSycamoreGates()(compiled_circuit1)
compiled_circuit2 = circuit2.copy()
cgoc.ConvertToSycamoreGates()(compiled_circuit2)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
cgoc.ConvertToSycamoreGates()(compiled_circuit2)

cirq.testing.assert_same_circuits(compiled_circuit1, compiled_circuit2)
assert (
Expand All @@ -45,7 +47,8 @@ def test_convert_to_sycamore_gates_fsim():
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(cirq.FSimGate(theta=np.pi / 2, phi=np.pi / 6)(q0, q1))
compiled_circuit = circuit.copy()
cgoc.ConvertToSycamoreGates()(compiled_circuit)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
cgoc.ConvertToSycamoreGates()(compiled_circuit)

cirq.testing.assert_same_circuits(circuit, compiled_circuit)

Expand All @@ -56,7 +59,8 @@ def test_single_qubit_gate():
gate = cirq.MatrixGate(mat, qid_shape=(2,))
circuit = cirq.Circuit(gate(q))
converted_circuit = circuit.copy()
cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit)
ops = list(converted_circuit.all_operations())
assert len(ops) == 1
assert isinstance(ops[0].gate, cirq.PhasedXZGate)
Expand All @@ -70,7 +74,8 @@ def test_single_qubit_gate_phased_xz():
gate = cirq.PhasedXZGate(axis_phase_exponent=0.2, x_exponent=0.3, z_exponent=0.4)
circuit = cirq.Circuit(gate(q))
converted_circuit = circuit.copy()
cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit)
ops = list(converted_circuit.all_operations())
assert len(ops) == 1
assert ops[0].gate == gate
Expand All @@ -80,24 +85,28 @@ def test_circuit_operation_inspection():
q0, q1 = cirq.LineQubit.range(2)
gate = cirq.PhasedXZGate(axis_phase_exponent=0.2, x_exponent=0.3, z_exponent=0.4)
cop = cirq.CircuitOperation(cirq.FrozenCircuit(gate(q0)))
assert cgoc.ConvertToSycamoreGates()._is_native_sycamore_op(cop)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
assert cgoc.ConvertToSycamoreGates()._is_native_sycamore_op(cop)

cop2 = cirq.CircuitOperation(cirq.FrozenCircuit(cirq.SWAP(q0, q1)))
assert not cgoc.ConvertToSycamoreGates()._is_native_sycamore_op(cop2)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
assert not cgoc.ConvertToSycamoreGates()._is_native_sycamore_op(cop2)


def test_circuit_operation_conversion():
q0, q1 = cirq.LineQubit.range(2)
subcircuit = cirq.FrozenCircuit(cirq.X(q0), cirq.SWAP(q0, q1))
circuit = cirq.Circuit(cirq.CircuitOperation(subcircuit))
converted_circuit = circuit.copy()
cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit)
# 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.
reconverted_subcircuit = ops[0].circuit.unfreeze().copy()
cgoc.ConvertToSycamoreGates().optimize_circuit(reconverted_subcircuit)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
cgoc.ConvertToSycamoreGates().optimize_circuit(reconverted_subcircuit)
assert ops[0].circuit == reconverted_subcircuit
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
circuit, converted_circuit, atol=1e-8
Expand All @@ -111,7 +120,10 @@ class UnknownGate(cirq.testing.TwoQubitGate):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(UnknownGate()(q0, q1))
with pytest.raises(TypeError, match='gate with a known unitary'):
cgoc.ConvertToSycamoreGates().optimize_circuit(circuit)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0'
):
cgoc.ConvertToSycamoreGates().optimize_circuit(circuit)


def test_nested_unsupported_gate():
Expand All @@ -123,7 +135,10 @@ class UnknownGate(cirq.testing.TwoQubitGate):
subcircuit = cirq.FrozenCircuit(UnknownGate()(q0, q1))
circuit = cirq.Circuit(cirq.CircuitOperation(subcircuit))
with pytest.raises(TypeError, match='gate with a known unitary'):
cgoc.ConvertToSycamoreGates().optimize_circuit(circuit)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0'
):
cgoc.ConvertToSycamoreGates().optimize_circuit(circuit)


def test_unsupported_phased_iswap():
Expand All @@ -133,7 +148,8 @@ def test_unsupported_phased_iswap():
q1 = cirq.LineQubit(1)
circuit = cirq.Circuit(cirq.PhasedISwapPowGate(exponent=0.5, phase_exponent=0.33)(q0, q1))
converted_circuit = circuit.copy()
cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit)
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
circuit, converted_circuit, atol=1e-8
)
Expand All @@ -155,7 +171,8 @@ def with_qubits(self, *new_qubits):
q0 = cirq.LineQubit(0)
circuit = cirq.Circuit(UnknownOperation([q0]))
converted_circuit = circuit.copy()
cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit)
assert circuit == converted_circuit


Expand All @@ -168,7 +185,10 @@ class ThreeQubitGate(cirq.testing.ThreeQubitGate):
q2 = cirq.LineQubit(2)
circuit = cirq.Circuit(ThreeQubitGate()(q0, q1, q2))
with pytest.raises(TypeError):
cgoc.ConvertToSycamoreGates().optimize_circuit(circuit)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0'
):
cgoc.ConvertToSycamoreGates().optimize_circuit(circuit)


def random_single_qubit_unitary():
Expand Down Expand Up @@ -199,7 +219,10 @@ def test_zztheta_qaoa_like():
]
)
syc_circuit = cirq_circuit.copy()
cgoc.ConvertToSycamoreGates().optimize_circuit(syc_circuit)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0'
):
cgoc.ConvertToSycamoreGates().optimize_circuit(syc_circuit)

cirq.testing.assert_allclose_up_to_global_phase(
cirq.unitary(cirq_circuit), cirq.unitary(syc_circuit), atol=1e-7
Expand All @@ -214,7 +237,8 @@ def test_zztheta_zzpow_unsorted_qubits():
cirq.ZZPowGate(exponent=exponent, global_shift=-0.5).on(qubits[0], qubits[1]),
)
actual_circuit = expected_circuit.copy()
cgoc.ConvertToSycamoreGates().optimize_circuit(actual_circuit)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
cgoc.ConvertToSycamoreGates().optimize_circuit(actual_circuit)

cirq.testing.assert_allclose_up_to_global_phase(
cirq.unitary(expected_circuit), cirq.unitary(actual_circuit), atol=1e-7
Expand All @@ -231,15 +255,19 @@ def test_swap_zztheta():
)
expected_unitary = cirq.unitary(expected_circuit)
actual_circuit = expected_circuit.copy()
cgoc.ConvertToSycamoreGates().optimize_circuit(actual_circuit)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0'
):
cgoc.ConvertToSycamoreGates().optimize_circuit(actual_circuit)
actual_unitary = cirq.unitary(actual_circuit)
cirq.testing.assert_allclose_up_to_global_phase(actual_unitary, expected_unitary, atol=1e-7)


def test_known_two_q_operations_to_sycamore_operations_cnot():
a, b = cirq.LineQubit.range(2)
op = cirq.CNOT(a, b)
decomposed = cirq.Circuit(cgoc.ConvertToSycamoreGates().convert(op))
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
decomposed = cirq.Circuit(cgoc.ConvertToSycamoreGates().convert(op))

# Should be equivalent.
cirq.testing.assert_allclose_up_to_global_phase(
Expand Down Expand Up @@ -271,7 +299,8 @@ def test_known_two_q_operations_to_sycamore_operations_cnot():
def test_convert_to_sycamore_equivalent_unitaries(gate):
qubits = [cirq.NamedQubit('a'), cirq.NamedQubit('b')]
operation = gate.on(qubits[0], qubits[1])
converted = cgoc.ConvertToSycamoreGates().convert(operation)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
converted = cgoc.ConvertToSycamoreGates().convert(operation)
u1 = cirq.unitary(cirq.Circuit(converted))
u2 = cirq.unitary(operation)
cirq.testing.assert_allclose_up_to_global_phase(u1, u2, atol=1e-8)
Expand All @@ -284,7 +313,8 @@ def test_convert_to_sycamore_tabulation():
)
qubits = [cirq.NamedQubit('a'), cirq.NamedQubit('b')]
operation = cirq.MatrixGate(cirq.unitary(cirq.CX), qid_shape=(2, 2)).on(qubits[0], qubits[1])
converted = cgoc.ConvertToSycamoreGates(sycamore_tabulation).convert(operation)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
converted = cgoc.ConvertToSycamoreGates(sycamore_tabulation).convert(operation)
u1 = cirq.unitary(cirq.Circuit(converted))
u2 = cirq.unitary(operation)
overlap = abs(np.trace(u1.conj().T @ u2))
Expand All @@ -295,7 +325,10 @@ def test_sycamore_invalid_tabulation():
# An object other than a tabulation.
sycamore_tabulation = {}
with pytest.raises(ValueError):
cgoc.ConvertToSycamoreGates(sycamore_tabulation)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0'
):
cgoc.ConvertToSycamoreGates(sycamore_tabulation)


q = cirq.GridQubit.rect(1, 3)
Expand All @@ -315,4 +348,7 @@ def test_sycamore_invalid_tabulation():
)
def test_supported_operation(op, is_valid):
c = cirq.Circuit(op)
assert (cirq_google.ConvertToSycamoreGates().optimization_at(c, 0, op) is not None) == is_valid
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
assert (
cirq_google.ConvertToSycamoreGates().optimization_at(c, 0, op) is not None
) == is_valid
12 changes: 4 additions & 8 deletions cirq-google/cirq_google/optimizers/optimize_for_sycamore.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
from cirq_google import ops as cg_ops
from cirq_google.optimizers import (
convert_to_xmon_gates,
ConvertToSycamoreGates,
)
from cirq_google.transformers.target_gatesets import sycamore_gateset

if TYPE_CHECKING:
import cirq_google
Expand Down Expand Up @@ -51,20 +51,16 @@ def _get_xmon_optimizers_part_cz(
]


def _get_sycamore_optimizers(
tolerance: float, tabulation: Optional[cirq.TwoQubitGateTabulation]
) -> List[Callable[[cirq.Circuit], None]]:
return [ConvertToSycamoreGates(tabulation=tabulation).optimize_circuit]


_OPTIMIZER_TYPES = {
'xmon': _get_xmon_optimizers,
'xmon_partial_cz': _get_xmon_optimizers_part_cz,
'sycamore': _get_sycamore_optimizers,
}

_TARGET_GATESETS = {
'sqrt_iswap': lambda atol, _: cirq.SqrtIswapTargetGateset(atol=atol),
'sycamore': lambda atol, tabulation: sycamore_gateset.SycamoreTargetGateset(
atol=atol, tabulation=tabulation
),
'xmon': lambda atol, _: cirq.CZTargetGateset(atol=atol),
'xmon_partial_cz': lambda atol, _: cirq.CZTargetGateset(atol=atol, allow_partial_czs=True),
}
Expand Down
2 changes: 2 additions & 0 deletions cirq-google/cirq_google/transformers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@
known_2q_op_to_sycamore_operations,
two_qubit_matrix_to_sycamore_operations,
)

from cirq_google.transformers.target_gatesets import SycamoreTargetGateset
17 changes: 17 additions & 0 deletions cirq-google/cirq_google/transformers/target_gatesets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2022 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""`cirq.CompilationTargetGateset` implementations for cirq_google gatesets and devices."""

from cirq_google.transformers.target_gatesets.sycamore_gateset import SycamoreTargetGateset
Loading

0 comments on commit 889e5d2

Please sign in to comment.