Skip to content

Commit 39795e1

Browse files
authored
Move CircuitDag to contrib (#5481)
* Move CircuitDag to contrib - Moves CircuitDag to contrib. - cirq.CircuitDag is now deprecated and now must be changed to cirq.contrib.CircuitDag. - Also moves the related cirq.Unique class Note: the tests use a high number of cirq.Unique instances which are also moved, so unable to verify count of deprecation messages in many tests.
1 parent a823872 commit 39795e1

13 files changed

+634
-125
lines changed

cirq-core/cirq/circuits/circuit_dag.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import functools
1717
import networkx
1818

19-
from cirq import ops
19+
from cirq import _compat, ops
2020
from cirq.circuits import circuit
2121

2222
if TYPE_CHECKING:
@@ -25,6 +25,7 @@
2525
T = TypeVar('T')
2626

2727

28+
@_compat.deprecated_class(deadline='v0.16', fix='Use cirq contrib.Unique instead.')
2829
@functools.total_ordering
2930
class Unique(Generic[T]):
3031
"""A wrapper for a value that doesn't compare equal to other instances.
@@ -55,6 +56,7 @@ def _disjoint_qubits(op1: 'cirq.Operation', op2: 'cirq.Operation') -> bool:
5556
return not set(op1.qubits) & set(op2.qubits)
5657

5758

59+
@_compat.deprecated_class(deadline='v0.16', fix='Use cirq contrib.CircuitDag instead.')
5860
class CircuitDag(networkx.DiGraph):
5961
"""A representation of a Circuit as a directed acyclic graph.
6062

cirq-core/cirq/circuits/circuit_dag_test.py

+142-104
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,18 @@ class FakeDevice(cirq.Device):
2828
def test_wrapper_eq():
2929
q0, q1 = cirq.LineQubit.range(2)
3030
eq = cirq.testing.EqualsTester()
31-
eq.add_equality_group(cirq.CircuitDag.make_node(cirq.X(q0)))
32-
eq.add_equality_group(cirq.CircuitDag.make_node(cirq.X(q0)))
33-
eq.add_equality_group(cirq.CircuitDag.make_node(cirq.Y(q0)))
34-
eq.add_equality_group(cirq.CircuitDag.make_node(cirq.X(q1)))
31+
32+
with cirq.testing.assert_deprecated('Use cirq contrib.Unique', deadline='v0.16', count=4):
33+
eq.add_equality_group(cirq.CircuitDag.make_node(cirq.X(q0)))
34+
eq.add_equality_group(cirq.CircuitDag.make_node(cirq.X(q0)))
35+
eq.add_equality_group(cirq.CircuitDag.make_node(cirq.Y(q0)))
36+
eq.add_equality_group(cirq.CircuitDag.make_node(cirq.X(q1)))
3537

3638

3739
def test_wrapper_cmp():
38-
u0 = cirq.Unique(0)
39-
u1 = cirq.Unique(1)
40+
with cirq.testing.assert_deprecated('Use cirq contrib.Unique', deadline='v0.16', count=2):
41+
u0 = cirq.Unique(0)
42+
u1 = cirq.Unique(1)
4043
# The ordering of Unique instances is unpredictable
4144
u0, u1 = (u1, u0) if u1 < u0 else (u0, u1)
4245
assert u0 == u0
@@ -50,88 +53,107 @@ def test_wrapper_cmp():
5053

5154

5255
def test_wrapper_cmp_failure():
53-
with pytest.raises(TypeError):
54-
_ = object() < cirq.Unique(1)
55-
with pytest.raises(TypeError):
56-
_ = cirq.Unique(1) < object()
56+
with cirq.testing.assert_deprecated('Use cirq contrib.Unique', deadline='v0.16', count=2):
57+
with pytest.raises(TypeError):
58+
_ = object() < cirq.Unique(1)
59+
with pytest.raises(TypeError):
60+
_ = cirq.Unique(1) < object()
5761

5862

5963
def test_wrapper_repr():
6064
q0 = cirq.LineQubit(0)
6165

62-
node = cirq.CircuitDag.make_node(cirq.X(q0))
63-
assert repr(node) == 'cirq.Unique(' + str(id(node)) + ', cirq.X(cirq.LineQubit(0)))'
66+
with cirq.testing.assert_deprecated('Use cirq contrib.Unique', deadline='v0.16'):
67+
node = cirq.CircuitDag.make_node(cirq.X(q0))
68+
assert repr(node) == 'cirq.Unique(' + str(id(node)) + ', cirq.X(cirq.LineQubit(0)))'
6469

6570

6671
def test_init():
67-
dag = cirq.CircuitDag()
68-
assert networkx.dag.is_directed_acyclic_graph(dag)
69-
assert list(dag.nodes()) == []
70-
assert list(dag.edges()) == []
72+
with cirq.testing.assert_deprecated('Use cirq contrib.CircuitDag', deadline='v0.16', count=1):
73+
dag = cirq.CircuitDag()
74+
assert networkx.dag.is_directed_acyclic_graph(dag)
75+
assert list(dag.nodes()) == []
76+
assert list(dag.edges()) == []
7177

7278

7379
def test_append():
7480
q0 = cirq.LineQubit(0)
75-
dag = cirq.CircuitDag()
76-
dag.append(cirq.X(q0))
77-
dag.append(cirq.Y(q0))
78-
assert networkx.dag.is_directed_acyclic_graph(dag)
79-
assert len(dag.nodes()) == 2
80-
assert [(n1.val, n2.val) for n1, n2 in dag.edges()] == [(cirq.X(q0), cirq.Y(q0))]
81+
with cirq.testing.assert_deprecated(
82+
'Use cirq contrib.CircuitDag', deadline='v0.16', count=None
83+
):
84+
dag = cirq.CircuitDag()
85+
dag.append(cirq.X(q0))
86+
dag.append(cirq.Y(q0))
87+
assert networkx.dag.is_directed_acyclic_graph(dag)
88+
assert len(dag.nodes()) == 2
89+
assert [(n1.val, n2.val) for n1, n2 in dag.edges()] == [(cirq.X(q0), cirq.Y(q0))]
8190

8291

8392
def test_two_identical_ops():
8493
q0 = cirq.LineQubit(0)
85-
dag = cirq.CircuitDag()
86-
dag.append(cirq.X(q0))
87-
dag.append(cirq.Y(q0))
88-
dag.append(cirq.X(q0))
89-
assert networkx.dag.is_directed_acyclic_graph(dag)
90-
assert len(dag.nodes()) == 3
91-
assert set((n1.val, n2.val) for n1, n2 in dag.edges()) == {
92-
(cirq.X(q0), cirq.Y(q0)),
93-
(cirq.X(q0), cirq.X(q0)),
94-
(cirq.Y(q0), cirq.X(q0)),
95-
}
94+
with cirq.testing.assert_deprecated(
95+
'Use cirq contrib.CircuitDag', deadline='v0.16', count=None
96+
):
97+
dag = cirq.CircuitDag()
98+
dag.append(cirq.X(q0))
99+
dag.append(cirq.Y(q0))
100+
dag.append(cirq.X(q0))
101+
assert networkx.dag.is_directed_acyclic_graph(dag)
102+
assert len(dag.nodes()) == 3
103+
assert set((n1.val, n2.val) for n1, n2 in dag.edges()) == {
104+
(cirq.X(q0), cirq.Y(q0)),
105+
(cirq.X(q0), cirq.X(q0)),
106+
(cirq.Y(q0), cirq.X(q0)),
107+
}
96108

97109

98110
def test_from_ops():
99111
q0 = cirq.LineQubit(0)
100-
dag = cirq.CircuitDag.from_ops(cirq.X(q0), cirq.Y(q0))
101-
assert networkx.dag.is_directed_acyclic_graph(dag)
102-
assert len(dag.nodes()) == 2
103-
assert [(n1.val, n2.val) for n1, n2 in dag.edges()] == [(cirq.X(q0), cirq.Y(q0))]
112+
with cirq.testing.assert_deprecated(
113+
'Use cirq contrib.CircuitDag', deadline='v0.16', count=None
114+
):
115+
dag = cirq.CircuitDag.from_ops(cirq.X(q0), cirq.Y(q0))
116+
assert networkx.dag.is_directed_acyclic_graph(dag)
117+
assert len(dag.nodes()) == 2
118+
assert [(n1.val, n2.val) for n1, n2 in dag.edges()] == [(cirq.X(q0), cirq.Y(q0))]
104119

105120

106121
def test_from_circuit():
107122
q0 = cirq.LineQubit(0)
108123
circuit = cirq.Circuit(cirq.X(q0), cirq.Y(q0))
109-
dag = cirq.CircuitDag.from_circuit(circuit)
110-
assert networkx.dag.is_directed_acyclic_graph(dag)
111-
assert len(dag.nodes()) == 2
112-
assert [(n1.val, n2.val) for n1, n2 in dag.edges()] == [(cirq.X(q0), cirq.Y(q0))]
113-
assert sorted(circuit.all_qubits()) == sorted(dag.all_qubits())
124+
with cirq.testing.assert_deprecated(
125+
'Use cirq contrib.CircuitDag', deadline='v0.16', count=None
126+
):
127+
dag = cirq.CircuitDag.from_circuit(circuit)
128+
assert networkx.dag.is_directed_acyclic_graph(dag)
129+
assert len(dag.nodes()) == 2
130+
assert [(n1.val, n2.val) for n1, n2 in dag.edges()] == [(cirq.X(q0), cirq.Y(q0))]
131+
assert sorted(circuit.all_qubits()) == sorted(dag.all_qubits())
114132

115133

116134
def test_to_empty_circuit():
117135
circuit = cirq.Circuit()
118-
dag = cirq.CircuitDag.from_circuit(circuit)
119-
assert networkx.dag.is_directed_acyclic_graph(dag)
120-
assert circuit == dag.to_circuit()
136+
with cirq.testing.assert_deprecated('Use cirq contrib.CircuitDag', deadline='v0.16'):
137+
dag = cirq.CircuitDag.from_circuit(circuit)
138+
assert networkx.dag.is_directed_acyclic_graph(dag)
139+
assert circuit == dag.to_circuit()
121140

122141

123142
def test_to_circuit():
124143
q0 = cirq.LineQubit(0)
125144
circuit = cirq.Circuit(cirq.X(q0), cirq.Y(q0))
126-
dag = cirq.CircuitDag.from_circuit(circuit)
145+
with cirq.testing.assert_deprecated(
146+
'Use cirq contrib.CircuitDag', deadline='v0.16', count=None
147+
):
148+
dag = cirq.CircuitDag.from_circuit(circuit)
127149

128-
assert networkx.dag.is_directed_acyclic_graph(dag)
129-
# Only one possible output circuit for this simple case
130-
assert circuit == dag.to_circuit()
150+
assert networkx.dag.is_directed_acyclic_graph(dag)
151+
# Only one possible output circuit for this simple case
152+
assert circuit == dag.to_circuit()
131153

132-
cirq.testing.assert_allclose_up_to_global_phase(
133-
circuit.unitary(), dag.to_circuit().unitary(), atol=1e-7
134-
)
154+
cirq.testing.assert_allclose_up_to_global_phase(
155+
circuit.unitary(), dag.to_circuit().unitary(), atol=1e-7
156+
)
135157

136158

137159
def test_equality():
@@ -156,43 +178,49 @@ def test_equality():
156178
)
157179

158180
eq = cirq.testing.EqualsTester()
159-
eq.make_equality_group(
160-
lambda: cirq.CircuitDag.from_circuit(circuit1),
161-
lambda: cirq.CircuitDag.from_circuit(circuit2),
162-
)
163-
eq.add_equality_group(cirq.CircuitDag.from_circuit(circuit3))
164-
eq.add_equality_group(cirq.CircuitDag.from_circuit(circuit4))
181+
with cirq.testing.assert_deprecated(
182+
'Use cirq contrib.CircuitDag', deadline='v0.16', count=None
183+
):
184+
eq.make_equality_group(
185+
lambda: cirq.CircuitDag.from_circuit(circuit1),
186+
lambda: cirq.CircuitDag.from_circuit(circuit2),
187+
)
188+
eq.add_equality_group(cirq.CircuitDag.from_circuit(circuit3))
189+
eq.add_equality_group(cirq.CircuitDag.from_circuit(circuit4))
165190

166191

167192
def test_larger_circuit():
168-
q0, q1, q2, q3 = [
169-
cirq.GridQubit(0, 5),
170-
cirq.GridQubit(1, 5),
171-
cirq.GridQubit(2, 5),
172-
cirq.GridQubit(3, 5),
173-
]
174-
# This circuit does not have CZ gates on adjacent qubits because the order
175-
# dag.to_circuit() would append them is non-deterministic.
176-
circuit = cirq.Circuit(
177-
cirq.X(q0),
178-
cirq.CZ(q1, q2),
179-
cirq.CZ(q0, q1),
180-
cirq.Y(q0),
181-
cirq.Z(q0),
182-
cirq.CZ(q1, q2),
183-
cirq.X(q0),
184-
cirq.Y(q0),
185-
cirq.CZ(q0, q1),
186-
cirq.T(q3),
187-
strategy=cirq.InsertStrategy.EARLIEST,
188-
)
189-
190-
dag = cirq.CircuitDag.from_circuit(circuit)
191-
192-
assert networkx.dag.is_directed_acyclic_graph(dag)
193-
# Operation order within a moment is non-deterministic
194-
# but text diagrams still look the same.
195-
desired = """
193+
with cirq.testing.assert_deprecated(
194+
'Use cirq contrib.CircuitDag', deadline='v0.16', count=None
195+
):
196+
q0, q1, q2, q3 = [
197+
cirq.GridQubit(0, 5),
198+
cirq.GridQubit(1, 5),
199+
cirq.GridQubit(2, 5),
200+
cirq.GridQubit(3, 5),
201+
]
202+
# This circuit does not have CZ gates on adjacent qubits because the order
203+
# dag.to_circuit() would append them is non-deterministic.
204+
circuit = cirq.Circuit(
205+
cirq.X(q0),
206+
cirq.CZ(q1, q2),
207+
cirq.CZ(q0, q1),
208+
cirq.Y(q0),
209+
cirq.Z(q0),
210+
cirq.CZ(q1, q2),
211+
cirq.X(q0),
212+
cirq.Y(q0),
213+
cirq.CZ(q0, q1),
214+
cirq.T(q3),
215+
strategy=cirq.InsertStrategy.EARLIEST,
216+
)
217+
218+
dag = cirq.CircuitDag.from_circuit(circuit)
219+
220+
assert networkx.dag.is_directed_acyclic_graph(dag)
221+
# Operation order within a moment is non-deterministic
222+
# but text diagrams still look the same.
223+
desired = """
196224
(0, 5): ───X───@───Y───Z───X───Y───@───
197225
│ │
198226
(1, 5): ───@───@───@───────────────@───
@@ -201,20 +229,26 @@ def test_larger_circuit():
201229
202230
(3, 5): ───T───────────────────────────
203231
"""
204-
cirq.testing.assert_has_diagram(circuit, desired)
205-
cirq.testing.assert_has_diagram(dag.to_circuit(), desired)
232+
cirq.testing.assert_has_diagram(circuit, desired)
233+
cirq.testing.assert_has_diagram(dag.to_circuit(), desired)
206234

207-
cirq.testing.assert_allclose_up_to_global_phase(
208-
circuit.unitary(), dag.to_circuit().unitary(), atol=1e-7
209-
)
235+
cirq.testing.assert_allclose_up_to_global_phase(
236+
circuit.unitary(), dag.to_circuit().unitary(), atol=1e-7
237+
)
210238

211239

212240
@pytest.mark.parametrize('circuit', [cirq.testing.random_circuit(10, 10, 0.5) for _ in range(3)])
213241
def test_is_maximalist(circuit):
214-
dag = cirq.CircuitDag.from_circuit(circuit)
215-
transitive_closure = networkx.dag.transitive_closure(dag)
216-
assert cirq.CircuitDag(incoming_graph_data=transitive_closure) == dag
217-
assert not any(dag.has_edge(b, a) for a, b in itertools.combinations(dag.ordered_nodes(), 2))
242+
# This creates a number of Unique classes so the count is not consistent.
243+
with cirq.testing.assert_deprecated(
244+
'Use cirq contrib.CircuitDag', deadline='v0.16', count=None
245+
):
246+
dag = cirq.CircuitDag.from_circuit(circuit)
247+
transitive_closure = networkx.dag.transitive_closure(dag)
248+
assert cirq.CircuitDag(incoming_graph_data=transitive_closure) == dag
249+
assert not any(
250+
dag.has_edge(b, a) for a, b in itertools.combinations(dag.ordered_nodes(), 2)
251+
)
218252

219253

220254
def _get_circuits_and_is_blockers():
@@ -230,12 +264,16 @@ def _get_circuits_and_is_blockers():
230264

231265
@pytest.mark.parametrize('circuit, is_blocker', _get_circuits_and_is_blockers())
232266
def test_findall_nodes_until_blocked(circuit, is_blocker):
233-
dag = cirq.CircuitDag.from_circuit(circuit)
234-
all_nodes = list(dag.ordered_nodes())
235-
found_nodes = list(dag.findall_nodes_until_blocked(is_blocker))
236-
assert not any(dag.has_edge(b, a) for a, b in itertools.combinations(found_nodes, 2))
237-
238-
blocking_nodes = set(node for node in all_nodes if is_blocker(node.val))
239-
blocked_nodes = blocking_nodes.union(*(dag.succ[node] for node in blocking_nodes))
240-
expected_nodes = set(all_nodes) - blocked_nodes
241-
assert sorted(found_nodes) == sorted(expected_nodes)
267+
# This creates a number of Unique classes so the count is not consistent.
268+
with cirq.testing.assert_deprecated(
269+
'Use cirq contrib.CircuitDag', deadline='v0.16', count=None
270+
):
271+
dag = cirq.CircuitDag.from_circuit(circuit)
272+
all_nodes = list(dag.ordered_nodes())
273+
found_nodes = list(dag.findall_nodes_until_blocked(is_blocker))
274+
assert not any(dag.has_edge(b, a) for a, b in itertools.combinations(found_nodes, 2))
275+
276+
blocking_nodes = set(node for node in all_nodes if is_blocker(node.val))
277+
blocked_nodes = blocking_nodes.union(*(dag.succ[node] for node in blocking_nodes))
278+
expected_nodes = set(all_nodes) - blocked_nodes
279+
assert sorted(found_nodes) == sorted(expected_nodes)

cirq-core/cirq/contrib/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@
2323
from cirq.contrib import quirk
2424
from cirq.contrib.qcircuit import circuit_to_latex_using_qcircuit
2525
from cirq.contrib import json
26+
from cirq.contrib.circuitdag import CircuitDag, Unique

cirq-core/cirq/contrib/acquaintance/inspection_utils.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414

1515
from typing import FrozenSet, Sequence, Set, TYPE_CHECKING
1616

17-
from cirq import circuits, devices
17+
from cirq import devices
1818

1919
from cirq.contrib.acquaintance.executor import AcquaintanceOperation, ExecutionStrategy
2020
from cirq.contrib.acquaintance.mutation_utils import expose_acquaintance_gates
2121
from cirq.contrib.acquaintance.permutation import LogicalIndex, LogicalMapping
22+
from cirq.contrib import circuitdag
2223

2324
if TYPE_CHECKING:
2425
import cirq
@@ -59,7 +60,7 @@ def get_acquaintance_dag(strategy: 'cirq.Circuit', initial_mapping: LogicalMappi
5960
for op in moment.operations
6061
if isinstance(op, AcquaintanceOperation)
6162
)
62-
return circuits.CircuitDag.from_ops(acquaintance_ops)
63+
return circuitdag.CircuitDag.from_ops(acquaintance_ops)
6364

6465

6566
def get_logical_acquaintance_opportunities(

cirq-core/cirq/contrib/acquaintance/topological_sort_test.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
[
2424
(dag, tuple(cca.random_topological_sort(dag)))
2525
for dag in [
26-
cirq.CircuitDag.from_circuit(cirq.testing.random_circuit(10, 10, 0.5)) for _ in range(5)
26+
cirq.contrib.CircuitDag.from_circuit(cirq.testing.random_circuit(10, 10, 0.5))
27+
for _ in range(5)
2728
]
2829
for _ in range(5)
2930
],

0 commit comments

Comments
 (0)