Skip to content
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

Deprecate cirq_google.ConvertToSqrtIswapGates and cirq.MergeInteractionsToSqrtIswap #5040

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
4 changes: 4 additions & 0 deletions cirq-core/cirq/optimizers/merge_interactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
import cirq


@_compat.deprecated_class(
deadline='v1.0',
fix='Use cirq.optimize_for_target_gateset and cirq.CompilationTargetGateset instead.',
)
class MergeInteractionsAbc(circuits.PointOptimizer, metaclass=abc.ABCMeta):
"""Combines series of adjacent one- and two-qubit, non-parametrized gates
operating on a pair of qubits."""
Expand Down
32 changes: 24 additions & 8 deletions cirq-core/cirq/optimizers/merge_interactions_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@

def assert_optimizes(before: cirq.Circuit, expected: cirq.Circuit):
actual = cirq.Circuit(before)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
opt = cirq.MergeInteractions()
opt.optimize_circuit(actual)

Expand All @@ -46,7 +48,9 @@ def assert_optimization_not_broken(circuit):
global phase and rounding error) as the unitary matrix of the optimized
circuit."""
u_before = circuit.unitary()
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractions().optimize_circuit(circuit)
u_after = circuit.unitary()

Expand Down Expand Up @@ -161,7 +165,9 @@ def test_optimizes_single_iswap():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.ISWAP(a, b))
assert_optimization_not_broken(c)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractions().optimize_circuit(c)
assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 2

Expand All @@ -170,7 +176,9 @@ def test_optimizes_tagged_partial_cz():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit((cirq.CZ ** 0.5)(a, b).with_tags('mytag'))
assert_optimization_not_broken(c)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractions(allow_partial_czs=False).optimize_circuit(c)
assert (
len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 2
Expand All @@ -182,7 +190,9 @@ def test_not_decompose_czs():
cirq.CZPowGate(exponent=1, global_shift=-0.5).on(*cirq.LineQubit.range(2))
)
circ_orig = circuit.copy()
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractions(allow_partial_czs=False).optimize_circuit(circuit)
assert circ_orig == circuit

Expand All @@ -200,7 +210,9 @@ def test_not_decompose_czs():
),
)
def test_decompose_partial_czs(circuit):
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
optimizer = cirq.MergeInteractions(allow_partial_czs=False)
optimizer.optimize_circuit(circuit)

Expand All @@ -219,7 +231,9 @@ def test_not_decompose_partial_czs():
circuit = cirq.Circuit(
cirq.CZPowGate(exponent=0.1, global_shift=-0.5)(*cirq.LineQubit.range(2)),
)
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
optimizer = cirq.MergeInteractions(allow_partial_czs=True)
optimizer.optimize_circuit(circuit)

Expand Down Expand Up @@ -253,7 +267,9 @@ def clean_up(operations):
yield operations
yield Marker()(a, b)

with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
optimizer = cirq.MergeInteractions(allow_partial_czs=False, post_clean_up=clean_up)
optimizer.optimize_circuit(circuit)
circuit = cirq.drop_empty_moments(circuit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@

import numpy as np

from cirq import ops
from cirq import ops, _compat
from cirq.optimizers import merge_interactions
from cirq.transformers.analytical_decompositions import two_qubit_to_sqrt_iswap

if TYPE_CHECKING:
import cirq


@_compat.deprecated_class(
deadline='v1.0',
fix='Use cirq.optimize_for_target_gateset and cirq.SqrtIswapTargetGateset instead.',
)
class MergeInteractionsToSqrtIswap(merge_interactions.MergeInteractionsAbc):
"""Combines series of adjacent one- and two-qubit, non-parametrized gates
operating on a pair of qubits and replaces each series with the minimum
Expand Down
74 changes: 59 additions & 15 deletions cirq-core/cirq/optimizers/merge_interactions_to_sqrt_iswap_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ def assert_optimizes(before: cirq.Circuit, expected: cirq.Circuit, **kwargs):
``MergeInteractionsToSqrtIswap`` constructor.
"""
actual = before.copy()
opt = cirq.MergeInteractionsToSqrtIswap(**kwargs)
opt.optimize_circuit(actual)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
opt = cirq.MergeInteractionsToSqrtIswap(**kwargs)
opt.optimize_circuit(actual)

# Ignore differences that would be caught by follow-up optimizations.
followup_transformers: List[cirq.TRANSFORMER] = [
Expand All @@ -57,15 +60,23 @@ def assert_optimization_not_broken(circuit: cirq.Circuit, **kwargs):
circuit."""
u_before = circuit.unitary(sorted(circuit.all_qubits()))
c_sqrt_iswap = circuit.copy()
cirq.MergeInteractionsToSqrtIswap(**kwargs).optimize_circuit(c_sqrt_iswap)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(**kwargs).optimize_circuit(c_sqrt_iswap)
u_after = c_sqrt_iswap.unitary(sorted(circuit.all_qubits()))

# Not 1e-8 because of some unaccounted accumulated error in some of Cirq's linalg functions
cirq.testing.assert_allclose_up_to_global_phase(u_before, u_after, atol=1e-6)

# Also test optimization with SQRT_ISWAP_INV
c_sqrt_iswap_inv = circuit.copy()
cirq.MergeInteractionsToSqrtIswap(use_sqrt_iswap_inv=True).optimize_circuit(c_sqrt_iswap_inv)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(use_sqrt_iswap_inv=True).optimize_circuit(
c_sqrt_iswap_inv
)
u_after2 = c_sqrt_iswap_inv.unitary(sorted(circuit.all_qubits()))

cirq.testing.assert_allclose_up_to_global_phase(u_before, u_after2, atol=1e-6)
Expand Down Expand Up @@ -230,79 +241,112 @@ def test_optimizes_single_iswap():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.ISWAP(a, b))
assert_optimization_not_broken(c)
cirq.MergeInteractionsToSqrtIswap().optimize_circuit(c)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap().optimize_circuit(c)
assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 2


def test_optimizes_single_inv_sqrt_iswap():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.SQRT_ISWAP_INV(a, b))
assert_optimization_not_broken(c)
cirq.MergeInteractionsToSqrtIswap().optimize_circuit(c)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap().optimize_circuit(c)
assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 1


def test_init_raises():
with pytest.raises(ValueError, match='must be 0, 1, 2, or 3'):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=4)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=4)


def test_optimizes_single_iswap_require0():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.CNOT(a, b), cirq.CNOT(a, b)) # Minimum 0 sqrt-iSWAP
assert_optimization_not_broken(c, required_sqrt_iswap_count=0)
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=0).optimize_circuit(c)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=0).optimize_circuit(c)
assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 0


def test_optimizes_single_iswap_require0_raises():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.CNOT(a, b)) # Minimum 2 sqrt-iSWAP
with pytest.raises(ValueError, match='cannot be decomposed into exactly 0 sqrt-iSWAP gates'):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=0).optimize_circuit(c)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=0).optimize_circuit(c)


def test_optimizes_single_iswap_require1():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.SQRT_ISWAP_INV(a, b)) # Minimum 1 sqrt-iSWAP
assert_optimization_not_broken(c, required_sqrt_iswap_count=1)
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=1).optimize_circuit(c)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=1).optimize_circuit(c)
assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 1


def test_optimizes_single_iswap_require1_raises():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.CNOT(a, b)) # Minimum 2 sqrt-iSWAP
with pytest.raises(ValueError, match='cannot be decomposed into exactly 1 sqrt-iSWAP gates'):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=1).optimize_circuit(c)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=1).optimize_circuit(c)


def test_optimizes_single_iswap_require2():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.SQRT_ISWAP_INV(a, b)) # Minimum 1 sqrt-iSWAP but 2 possible
assert_optimization_not_broken(c, required_sqrt_iswap_count=2)
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=2).optimize_circuit(c)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=2).optimize_circuit(c)
assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 2


def test_optimizes_single_iswap_require2_raises():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.SWAP(a, b)) # Minimum 3 sqrt-iSWAP
with pytest.raises(ValueError, match='cannot be decomposed into exactly 2 sqrt-iSWAP gates'):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=2).optimize_circuit(c)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=2).optimize_circuit(c)


def test_optimizes_single_iswap_require3():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.ISWAP(a, b)) # Minimum 2 sqrt-iSWAP but 3 possible
assert_optimization_not_broken(c, required_sqrt_iswap_count=3)
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=3).optimize_circuit(c)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=3).optimize_circuit(c)
assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 3


def test_optimizes_single_inv_sqrt_iswap_require3():
a, b = cirq.LineQubit.range(2)
c = cirq.Circuit(cirq.SQRT_ISWAP_INV(a, b))
assert_optimization_not_broken(c, required_sqrt_iswap_count=3)
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=3).optimize_circuit(c)
with cirq.testing.assert_deprecated(
"Use cirq.optimize_for_target_gateset", deadline='v1.0', count=2
):
cirq.MergeInteractionsToSqrtIswap(required_sqrt_iswap_count=3).optimize_circuit(c)
assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 3
4 changes: 4 additions & 0 deletions cirq-google/cirq_google/optimizers/convert_to_sqrt_iswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ def _near_mod_2pi(e, t, atol=1e-8):
return _near_mod_n(e, t, 2 * np.pi, atol=atol)


@cirq._compat.deprecated_class(
deadline='v1.0',
fix='Use cirq.optimize_for_target_gateset and cirq.SqrtIswapTargetGateset instead.',
)
class ConvertToSqrtIswapGates(cirq.PointOptimizer):
"""Attempts to convert gates into ISWAP**-0.5 gates.
Expand Down
Loading