Skip to content

Commit

Permalink
Deprecate Cirq-FT module in favour of Qualtran (#6362)
Browse files Browse the repository at this point in the history
* Deprecate Cirq-FT module in favour of Qualtran

* Fix failing tests, lint and add coverage ignores

* Address comments
  • Loading branch information
tanujkhattar authored Nov 28, 2023
1 parent cf973a5 commit 3c6a305
Show file tree
Hide file tree
Showing 31 changed files with 233 additions and 47 deletions.
12 changes: 10 additions & 2 deletions cirq-ft/cirq_ft/algos/and_gate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import itertools
import random
import sys
from typing import List, Tuple

import cirq
Expand All @@ -23,11 +22,13 @@
import pytest
from cirq_ft import infra
from cirq_ft.infra.jupyter_tools import execute_notebook
from cirq_ft.deprecation import allow_deprecated_cirq_ft_use_in_tests

random.seed(12345)


@pytest.mark.parametrize("cv", [(0, 0), (0, 1), (1, 0), (1, 1)])
@allow_deprecated_cirq_ft_use_in_tests
def test_and_gate(cv: Tuple[int, int]):
c1, c2, t = cirq.LineQubit.range(3)
input_states = [(0, 0, 0), (0, 1, 0), (1, 0, 0), (1, 1, 0)]
Expand All @@ -44,6 +45,7 @@ def random_cv(n: int) -> List[int]:


@pytest.mark.parametrize("cv", [[1] * 3, random_cv(5), random_cv(6), random_cv(7)])
@allow_deprecated_cirq_ft_use_in_tests
def test_multi_controlled_and_gate(cv: List[int]):
gate = cirq_ft.And(cv)
r = gate.signature
Expand Down Expand Up @@ -77,6 +79,7 @@ def test_multi_controlled_and_gate(cv: List[int]):
)


@allow_deprecated_cirq_ft_use_in_tests
def test_and_gate_diagram():
gate = cirq_ft.And((1, 0, 1, 0, 1, 0))
qubit_regs = infra.get_named_qubits(gate.signature)
Expand Down Expand Up @@ -186,13 +189,15 @@ def test_and_gate_diagram():
((1, 0, 1), True, "And†(1, 0, 1)"),
],
)
@allow_deprecated_cirq_ft_use_in_tests
def test_and_gate_str_and_repr(cv, adjoint, str_output):
gate = cirq_ft.And(cv, adjoint=adjoint)
assert str(gate) == str_output
cirq.testing.assert_equivalent_repr(gate, setup_code="import cirq_ft\n")


@pytest.mark.parametrize("cv", [(0, 0), (0, 1), (1, 0), (1, 1)])
@allow_deprecated_cirq_ft_use_in_tests
def test_and_gate_adjoint(cv: Tuple[int, int]):
c1, c2, t = cirq.LineQubit.range(3)
all_cvs = [(0, 0), (0, 1), (1, 0), (1, 1)]
Expand All @@ -204,7 +209,7 @@ def test_and_gate_adjoint(cv: Tuple[int, int]):
cirq_ft.testing.assert_circuit_inp_out_cirqsim(circuit, [c1, c2, t], inp, out)


@pytest.mark.skipif(sys.platform != "linux", reason="Linux-only test")
@pytest.mark.skip(reason="Cirq-FT is deprecated, use Qualtran instead.")
def test_notebook():
execute_notebook('and_gate')

Expand All @@ -213,16 +218,19 @@ def test_notebook():
"cv", [*itertools.chain(*[itertools.product(range(2), repeat=n) for n in range(2, 7 + 1)])]
)
@pytest.mark.parametrize("adjoint", [*range(2)])
@allow_deprecated_cirq_ft_use_in_tests
def test_t_complexity(cv, adjoint):
gate = cirq_ft.And(cv=cv, adjoint=adjoint)
cirq_ft.testing.assert_decompose_is_consistent_with_t_complexity(gate)


@allow_deprecated_cirq_ft_use_in_tests
def test_and_gate_raises():
with pytest.raises(ValueError, match="at-least 2 control values"):
_ = cirq_ft.And(cv=(1,))


@allow_deprecated_cirq_ft_use_in_tests
def test_and_gate_power():
cv = (1, 0)
and_gate = cirq_ft.And(cv)
Expand Down
7 changes: 5 additions & 2 deletions cirq-ft/cirq_ft/algos/apply_gate_to_lth_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,13 @@ class ApplyGateToLthQubit(unary_iteration_gate.UnaryIterationGate):
)
nth_gate: Callable[..., cirq.Gate]
control_regs: Tuple[infra.Register, ...] = attr.field(
converter=lambda v: (v,) if isinstance(v, infra.Register) else tuple(v),
default=(infra.Register('control', 1),),
converter=lambda v: (v,) if isinstance(v, infra.Register) else tuple(v)
)

@control_regs.default
def control_regs_default(self):
return (infra.Register('control', 1),)

@classmethod
def make_on(
cls, *, nth_gate: Callable[..., cirq.Gate], **quregs: Sequence[cirq.Qid]
Expand Down
8 changes: 5 additions & 3 deletions cirq-ft/cirq_ft/algos/apply_gate_to_lth_target_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import sys

import cirq
import cirq_ft
import pytest
from cirq_ft import infra
from cirq_ft.infra.bit_tools import iter_bits
from cirq_ft.infra.jupyter_tools import execute_notebook
from cirq_ft.deprecation import allow_deprecated_cirq_ft_use_in_tests


@pytest.mark.parametrize("selection_bitsize,target_bitsize", [[3, 5], [3, 7], [4, 5]])
@allow_deprecated_cirq_ft_use_in_tests
def test_apply_gate_to_lth_qubit(selection_bitsize, target_bitsize):
greedy_mm = cirq.GreedyQubitManager(prefix="_a", maximize_reuse=True)
gate = cirq_ft.ApplyGateToLthQubit(
Expand Down Expand Up @@ -51,6 +51,7 @@ def test_apply_gate_to_lth_qubit(selection_bitsize, target_bitsize):
)


@allow_deprecated_cirq_ft_use_in_tests
def test_apply_gate_to_lth_qubit_diagram():
# Apply Z gate to all odd targets and Identity to even targets.
gate = cirq_ft.ApplyGateToLthQubit(
Expand Down Expand Up @@ -87,6 +88,7 @@ def test_apply_gate_to_lth_qubit_diagram():
)


@allow_deprecated_cirq_ft_use_in_tests
def test_apply_gate_to_lth_qubit_make_on():
gate = cirq_ft.ApplyGateToLthQubit(
cirq_ft.SelectionRegister('selection', 3, 5),
Expand All @@ -103,6 +105,6 @@ def test_apply_gate_to_lth_qubit_make_on():
assert op.gate.control_regs == op2.gate.control_regs


@pytest.mark.skipif(sys.platform != "linux", reason="Linux-only test")
@pytest.mark.skip(reason="Cirq-FT is deprecated, use Qualtran instead.")
def test_notebook():
execute_notebook('apply_gate_to_lth_target')
6 changes: 6 additions & 0 deletions cirq-ft/cirq_ft/algos/arithmetic_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@

from cirq_ft import infra
from cirq_ft.algos import and_gate
from cirq_ft.deprecation import deprecated_cirq_ft_class


@deprecated_cirq_ft_class()
@attr.frozen
class LessThanGate(cirq.ArithmeticGate):
"""Applies U_a|x>|z> = |x> |z ^ (x < a)>"""
Expand Down Expand Up @@ -297,6 +299,7 @@ def _equality_with_zero(
yield and_gate.And(cv=[0] * len(qubits)).on(*qubits, *ancilla, z)


@deprecated_cirq_ft_class()
@attr.frozen
class LessThanEqualGate(cirq.ArithmeticGate):
"""Applies U|x>|y>|z> = |x>|y> |z ^ (x <= y)>"""
Expand Down Expand Up @@ -454,6 +457,7 @@ def _has_unitary_(self):
return True


@deprecated_cirq_ft_class()
@attr.frozen
class ContiguousRegisterGate(cirq.ArithmeticGate):
"""Applies U|x>|y>|0> -> |x>|y>|x(x-1)/2 + y>
Expand Down Expand Up @@ -530,6 +534,7 @@ def __pow__(self, power: int):
return NotImplemented # pragma: no cover


@deprecated_cirq_ft_class()
@attr.frozen
class AdditionGate(cirq.ArithmeticGate):
"""Applies U|p>|q> -> |p>|p+q>.
Expand Down Expand Up @@ -613,6 +618,7 @@ def __repr__(self) -> str:
return f'cirq_ft.AdditionGate({self.bitsize})'


@deprecated_cirq_ft_class()
@attr.frozen(auto_attribs=True)
class AddMod(cirq.ArithmeticGate):
"""Applies U_{M}_{add}|x> = |(x + add) % M> if x < M else |x>.
Expand Down
20 changes: 20 additions & 0 deletions cirq-ft/cirq_ft/algos/arithmetic_gates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
import numpy as np
import pytest
from cirq_ft.infra import bit_tools
from cirq_ft.deprecation import allow_deprecated_cirq_ft_use_in_tests


def identity_map(n: int):
"""Returns a dict of size `2**n` mapping each integer in range [0, 2**n) to itself."""
return {i: i for i in range(2**n)}


@allow_deprecated_cirq_ft_use_in_tests
def test_less_than_gate():
qubits = cirq.LineQubit.range(4)
gate = cirq_ft.LessThanGate(3, 5)
Expand Down Expand Up @@ -61,6 +63,7 @@ def test_less_than_gate():

@pytest.mark.parametrize("bits", [*range(8)])
@pytest.mark.parametrize("val", [3, 5, 7, 8, 9])
@allow_deprecated_cirq_ft_use_in_tests
def test_decompose_less_than_gate(bits: int, val: int):
qubit_states = list(bit_tools.iter_bits(bits, 3))
circuit = cirq.Circuit(
Expand All @@ -81,6 +84,7 @@ def test_decompose_less_than_gate(bits: int, val: int):

@pytest.mark.parametrize("n", [*range(2, 5)])
@pytest.mark.parametrize("val", [3, 4, 5, 7, 8, 9])
@allow_deprecated_cirq_ft_use_in_tests
def test_less_than_consistent_protocols(n: int, val: int):
g = cirq_ft.LessThanGate(n, val)
cirq_ft.testing.assert_decompose_is_consistent_with_t_complexity(g)
Expand All @@ -90,6 +94,7 @@ def test_less_than_consistent_protocols(n: int, val: int):
np.testing.assert_allclose(u @ u, np.eye(2 ** (n + 1)))


@allow_deprecated_cirq_ft_use_in_tests
def test_multi_in_less_equal_than_gate():
qubits = cirq.LineQubit.range(7)
op = cirq_ft.LessThanEqualGate(3, 3).on(*qubits)
Expand All @@ -114,6 +119,7 @@ def test_multi_in_less_equal_than_gate():

@pytest.mark.parametrize("x_bitsize", [*range(1, 5)])
@pytest.mark.parametrize("y_bitsize", [*range(1, 5)])
@allow_deprecated_cirq_ft_use_in_tests
def test_less_than_equal_consistent_protocols(x_bitsize: int, y_bitsize: int):
g = cirq_ft.LessThanEqualGate(x_bitsize, y_bitsize)
cirq_ft.testing.assert_decompose_is_consistent_with_t_complexity(g)
Expand All @@ -138,6 +144,7 @@ def test_less_than_equal_consistent_protocols(x_bitsize: int, y_bitsize: int):
assert g.with_registers([2] * 4, [2] * 5, [2]) == cirq_ft.LessThanEqualGate(4, 5)


@allow_deprecated_cirq_ft_use_in_tests
def test_contiguous_register_gate():
gate = cirq_ft.ContiguousRegisterGate(3, 6)
circuit = cirq.Circuit(gate.on(*cirq.LineQubit.range(12)))
Expand All @@ -163,13 +170,15 @@ def test_contiguous_register_gate():


@pytest.mark.parametrize('n', [*range(1, 10)])
@allow_deprecated_cirq_ft_use_in_tests
def test_contiguous_register_gate_t_complexity(n):
gate = cirq_ft.ContiguousRegisterGate(n, 2 * n)
toffoli_complexity = cirq_ft.t_complexity(cirq.CCNOT)
assert cirq_ft.t_complexity(gate) == (n**2 + n - 1) * toffoli_complexity


@pytest.mark.parametrize('a,b,num_bits', itertools.product(range(4), range(4), range(3, 5)))
@allow_deprecated_cirq_ft_use_in_tests
def test_add(a: int, b: int, num_bits: int):
num_anc = num_bits - 1
gate = cirq_ft.AdditionGate(num_bits)
Expand Down Expand Up @@ -199,6 +208,7 @@ def test_add(a: int, b: int, num_bits: int):
@pytest.mark.parametrize('mod', [5, 8])
@pytest.mark.parametrize('add_val', [1, 2])
@pytest.mark.parametrize('cv', [[], [0, 1], [1, 0], [1, 1]])
@allow_deprecated_cirq_ft_use_in_tests
def test_add_mod_n(bitsize, mod, add_val, cv):
gate = cirq_ft.AddMod(bitsize, mod, add_val=add_val, cv=cv)
basis_map = {}
Expand All @@ -225,6 +235,7 @@ def test_add_mod_n(bitsize, mod, add_val, cv):
cirq.testing.assert_equivalent_repr(gate, setup_code='import cirq_ft')


@allow_deprecated_cirq_ft_use_in_tests
def test_add_mod_n_protocols():
with pytest.raises(ValueError, match="must be between"):
_ = cirq_ft.AddMod(3, 10)
Expand All @@ -238,6 +249,7 @@ def test_add_mod_n_protocols():
assert cirq.circuit_diagram_info(add_two).wire_symbols == ('@', '@(0)') + ('Add_2_Mod_5',) * 3


@allow_deprecated_cirq_ft_use_in_tests
def test_add_truncated():
num_bits = 3
num_anc = num_bits - 1
Expand Down Expand Up @@ -286,6 +298,7 @@ def test_add_truncated():


@pytest.mark.parametrize('a,b,num_bits', itertools.product(range(4), range(4), range(3, 5)))
@allow_deprecated_cirq_ft_use_in_tests
def test_subtract(a, b, num_bits):
num_anc = num_bits - 1
gate = cirq_ft.AdditionGate(num_bits)
Expand All @@ -309,13 +322,15 @@ def test_subtract(a, b, num_bits):


@pytest.mark.parametrize("n", [*range(3, 10)])
@allow_deprecated_cirq_ft_use_in_tests
def test_addition_gate_t_complexity(n: int):
g = cirq_ft.AdditionGate(n)
cirq_ft.testing.assert_decompose_is_consistent_with_t_complexity(g)
cirq.testing.assert_equivalent_repr(g, setup_code='import cirq_ft')


@pytest.mark.parametrize('a,b', itertools.product(range(2**3), repeat=2))
@allow_deprecated_cirq_ft_use_in_tests
def test_add_no_decompose(a, b):
num_bits = 5
qubits = cirq.LineQubit.range(2 * num_bits)
Expand All @@ -335,6 +350,7 @@ def test_add_no_decompose(a, b):

@pytest.mark.parametrize("P,n", [(v, n) for n in range(1, 4) for v in range(1 << n)])
@pytest.mark.parametrize("Q,m", [(v, n) for n in range(1, 4) for v in range(1 << n)])
@allow_deprecated_cirq_ft_use_in_tests
def test_decompose_less_than_equal_gate(P: int, n: int, Q: int, m: int):
qubit_states = list(bit_tools.iter_bits(P, n)) + list(bit_tools.iter_bits(Q, m))
circuit = cirq.Circuit(
Expand All @@ -353,6 +369,7 @@ def test_decompose_less_than_equal_gate(P: int, n: int, Q: int, m: int):


@pytest.mark.parametrize("adjoint", [False, True])
@allow_deprecated_cirq_ft_use_in_tests
def test_single_qubit_compare_protocols(adjoint: bool):
g = cirq_ft.algos.SingleQubitCompare(adjoint=adjoint)
cirq_ft.testing.assert_decompose_is_consistent_with_t_complexity(g)
Expand All @@ -370,6 +387,7 @@ def test_single_qubit_compare_protocols(adjoint: bool):


@pytest.mark.parametrize("v1,v2", [(v1, v2) for v1 in range(2) for v2 in range(2)])
@allow_deprecated_cirq_ft_use_in_tests
def test_single_qubit_compare(v1: int, v2: int):
g = cirq_ft.algos.SingleQubitCompare()
qubits = cirq.LineQid.range(4, dimension=2)
Expand All @@ -388,6 +406,7 @@ def test_single_qubit_compare(v1: int, v2: int):


@pytest.mark.parametrize("adjoint", [False, True])
@allow_deprecated_cirq_ft_use_in_tests
def test_bi_qubits_mixer_protocols(adjoint: bool):
g = cirq_ft.algos.BiQubitsMixer(adjoint=adjoint)
cirq_ft.testing.assert_decompose_is_consistent_with_t_complexity(g)
Expand All @@ -399,6 +418,7 @@ def test_bi_qubits_mixer_protocols(adjoint: bool):

@pytest.mark.parametrize("x", [*range(4)])
@pytest.mark.parametrize("y", [*range(4)])
@allow_deprecated_cirq_ft_use_in_tests
def test_bi_qubits_mixer(x: int, y: int):
g = cirq_ft.algos.BiQubitsMixer()
qubits = cirq.LineQid.range(7, dimension=2)
Expand Down
Loading

0 comments on commit 3c6a305

Please sign in to comment.