Skip to content

Commit d67300a

Browse files
Merge branch 'master' into deprecate_device_decompose
2 parents 645ac19 + 86c873b commit d67300a

37 files changed

+725
-119
lines changed

cirq-core/cirq/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@
358358
decompose_multi_controlled_x,
359359
decompose_multi_controlled_rotation,
360360
decompose_two_qubit_interaction_into_four_fsim_gates,
361+
drop_empty_moments,
362+
drop_negligible_operations,
361363
is_negligible_turn,
362364
map_moments,
363365
map_operations,
@@ -371,6 +373,7 @@
371373
single_qubit_matrix_to_phased_x_z,
372374
single_qubit_matrix_to_phxz,
373375
single_qubit_op_to_framed_phase_form,
376+
synchronize_terminal_measurements,
374377
TRANSFORMER,
375378
TransformerContext,
376379
TransformerLogger,

cirq-core/cirq/circuits/circuit.py

+26-13
Original file line numberDiff line numberDiff line change
@@ -2016,6 +2016,10 @@ def _pick_or_create_inserted_op_moment_index(
20162016
def _can_add_op_at(self, moment_index: int, operation: 'cirq.Operation') -> bool:
20172017
if not 0 <= moment_index < len(self._moments):
20182018
return True
2019+
2020+
if self._device == cirq.UNCONSTRAINED_DEVICE:
2021+
return not self._moments[moment_index].operates_on(operation.qubits)
2022+
20192023
return self._device.can_add_operation_into_moment(operation, self._moments[moment_index])
20202024

20212025
def insert(
@@ -2120,19 +2124,28 @@ def insert_into_range(self, operations: 'cirq.OP_TREE', start: int, end: int) ->
21202124

21212125
i = start
21222126
op_index = 0
2123-
while op_index < len(flat_ops):
2124-
op = flat_ops[op_index]
2125-
while i < end and not self._device.can_add_operation_into_moment(op, self._moments[i]):
2126-
i += 1
2127-
if i >= end:
2128-
break
2129-
self._moments[i] = self._moments[i].with_operation(op)
2130-
op_index += 1
2131-
2132-
if op_index >= len(flat_ops):
2133-
return end
2134-
2135-
return self.insert(end, flat_ops[op_index:])
2127+
cannot_add_lambda = lambda a, b: b.operates_on(a.qubits)
2128+
if self._device != cirq.UNCONSTRAINED_DEVICE:
2129+
_compat._warn_or_error(
2130+
"In Cirq v0.15 device specific validation in "
2131+
"insert_into_range will no longer enforced."
2132+
)
2133+
cannot_add_lambda = lambda a, b: not self._device.can_add_operation_into_moment(a, b)
2134+
2135+
with _compat.block_overlapping_deprecation('can_add_operation_into_moment'):
2136+
while op_index < len(flat_ops):
2137+
op = flat_ops[op_index]
2138+
while i < end and cannot_add_lambda(op, self._moments[i]):
2139+
i += 1
2140+
if i >= end:
2141+
break
2142+
self._moments[i] = self._moments[i].with_operation(op)
2143+
op_index += 1
2144+
2145+
if op_index >= len(flat_ops):
2146+
return end
2147+
2148+
return self.insert(end, flat_ops[op_index:])
21362149

21372150
def _push_frontier(
21382151
self,

cirq-core/cirq/circuits/circuit_test.py

+8
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,14 @@ def optimization_at(
11781178
)
11791179

11801180

1181+
def test_insert_into_range_deprecated():
1182+
with cirq.testing.assert_deprecated('insert_into_range', deadline='v0.15'):
1183+
x, y = cirq.GridQubit.rect(1, 2)
1184+
c = cirq.Circuit([cirq.Moment([cirq.X(x)])] * 4)
1185+
c._device = FOXY
1186+
c.insert_into_range([cirq.Z(x), cirq.CZ(x, y)], 2, 2)
1187+
1188+
11811189
def test_insert_into_range():
11821190
x = cirq.NamedQubit('x')
11831191
y = cirq.NamedQubit('y')

cirq-core/cirq/contrib/paulistring/convert_gate_set.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from cirq import circuits, optimizers
15+
from cirq import circuits, optimizers, transformers
1616

1717
from cirq.contrib.paulistring.convert_to_pauli_string_phasors import ConvertToPauliStringPhasors
1818

@@ -34,5 +34,4 @@ def converted_gate_set(
3434
keep_clifford=not no_clifford_gates,
3535
atol=atol,
3636
).optimize_circuit(conv_circuit)
37-
optimizers.DropEmptyMoments().optimize_circuit(conv_circuit)
38-
return conv_circuit
37+
return transformers.drop_empty_moments(conv_circuit)

cirq-core/cirq/contrib/quimb/Cirq-to-Tensor-Networks.ipynb

+6-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
" import cirq\n",
1313
"except ImportError:\n",
1414
" print(\"installing cirq...\")\n",
15-
" !pip install --quiet cirq\n",
15+
" !pip install --quiet cirq --pre\n",
1616
" print(\"installed cirq.\")\n",
1717
"\n",
1818
"try:\n",
@@ -78,7 +78,7 @@
7878
"source": [
7979
"qubits = cirq.LineQubit.range(3)\n",
8080
"circuit = cirq.testing.random_circuit(qubits, n_moments=10, op_density=0.8, random_state=52)\n",
81-
"cirq.DropEmptyMoments().optimize_circuit(circuit)\n",
81+
"circuit = cirq.drop_empty_moments(circuit)\n",
8282
"SVGCircuit(circuit)"
8383
]
8484
},
@@ -87,7 +87,9 @@
8787
"metadata": {},
8888
"source": [
8989
"### Circuit to Tensors\n",
90-
"The circuit defines a tensor network representation. By default, the initial state is the `|0...0>` state (represented by the \"zero qubit\" operations labeled \"Q0\" in the legend. \"Q1\" are single qubit operations and \"Q2\" are two qubit operations. The open legs are the indices into the state vector and are of the form \"i{m}_q{n}\" where `m` is the time index (given by the returned `qubit_frontier` dictionary) and \"n\" is the qubit string."
90+
"The circuit defines a tensor network representation. By default, the initial state is the `|0...0>` state (represented by the \"zero qubit\" operations labeled \"Q0\" in the legend. \"Q1\" are single qubit operations and \"Q2\" are two qubit operations. The open legs are the indices into the state vector and are of the form \"i{m}_q{n}\" where `m` is the time index (given by the returned `qubit_frontier` dictionary) and \"n\" is the qubit string.\n",
91+
"\n",
92+
"Note: this notebook relies on unreleased Cirq features. If you want to try these features, make sure you install cirq via `pip install cirq --pre`."
9193
]
9294
},
9395
{
@@ -285,7 +287,7 @@
285287
" circuit = cirq.testing.random_circuit(qubits, n_moments=n_moments, op_density=0.8)\n",
286288
" noise_model = cirq.ConstantQubitNoiseModel(cirq.DepolarizingChannel(p=1e-3))\n",
287289
" circuit = cirq.Circuit(noise_model.noisy_moments(circuit.moments, qubits))\n",
288-
" cirq.DropEmptyMoments().optimize_circuit(circuit)\n",
290+
" circuit = cirq.drop_empty_moments(circuit)\n",
289291
" n_moments = len(circuit)\n",
290292
" variables = {'circuit': circuit, 'qubits': qubits}\n",
291293
"\n",

cirq-core/cirq/contrib/quimb/Contract-a-Grid-Circuit.ipynb

+6-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
" import cirq\n",
1313
"except ImportError:\n",
1414
" print(\"installing cirq...\")\n",
15-
" !pip install --quiet cirq\n",
15+
" !pip install --quiet cirq --pre\n",
1616
" print(\"installed cirq.\")\n",
1717
"\n",
1818
"try:\n",
@@ -28,7 +28,9 @@
2828
"metadata": {},
2929
"source": [
3030
"# Contract a Grid Circuit\n",
31-
"Shallow circuits on a planar grid with low-weight observables permit easy contraction."
31+
"Shallow circuits on a planar grid with low-weight observables permit easy contraction.\n",
32+
"\n",
33+
"Note: this notebook relies on unreleased Cirq features. If you want to try these features, make sure you install cirq via `pip install cirq --pre`."
3234
]
3335
},
3436
{
@@ -207,8 +209,8 @@
207209
"ccq.MergeNQubitGates(n_qubits=2).optimize_circuit(compressed_c)\n",
208210
"ccq.MergeNQubitGates(n_qubits=1).optimize_circuit(compressed_c)\n",
209211
"\n",
210-
"cirq.DropNegligible(tolerance=1e-6).optimize_circuit(compressed_c)\n",
211-
"cirq.DropEmptyMoments().optimize_circuit(compressed_c)\n",
212+
"compressed_c = cirq.drop_negligible_operations(compressed_c, atol=1e-6)\n",
213+
"compressed_c = cirq.drop_empty_moments(compressed_c)\n",
212214
"print(len(list(compressed_c.all_operations())), len(compressed_c.all_qubits()))\n",
213215
"SVGCircuit(compressed_c)"
214216
]

cirq-core/cirq/contrib/quimb/density_matrix_test.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def test_tensor_density_matrix_3():
5858
def test_tensor_density_matrix_4():
5959
qubits = cirq.LineQubit.range(4)
6060
circuit = cirq.testing.random_circuit(qubits=qubits, n_moments=100, op_density=0.8)
61-
cirq.DropEmptyMoments().optimize_circuit(circuit)
61+
circuit = cirq.drop_empty_moments(circuit)
6262
noise_model = cirq.ConstantQubitNoiseModel(cirq.DepolarizingChannel(p=1e-3))
6363
circuit = cirq.Circuit(noise_model.noisy_moments(circuit.moments, qubits))
6464
rho1 = cirq.final_density_matrix(circuit, dtype=np.complex128)
@@ -69,7 +69,7 @@ def test_tensor_density_matrix_4():
6969
def test_tensor_density_matrix_gridqubit():
7070
qubits = cirq.GridQubit.rect(2, 2)
7171
circuit = cirq.testing.random_circuit(qubits=qubits, n_moments=10, op_density=0.8)
72-
cirq.DropEmptyMoments().optimize_circuit(circuit)
72+
circuit = cirq.drop_empty_moments(circuit)
7373
noise_model = cirq.ConstantQubitNoiseModel(cirq.DepolarizingChannel(p=1e-3))
7474
circuit = cirq.Circuit(noise_model.noisy_moments(circuit.moments, qubits))
7575
rho1 = cirq.final_density_matrix(circuit, dtype=np.complex128)

cirq-core/cirq/contrib/quimb/grid_circuits.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,9 @@ def simplify_expectation_value_circuit(circuit_sand: cirq.Circuit):
137137
n_op = sum(1 for _ in circuit_sand.all_operations())
138138
while True:
139139
MergeNQubitGates(n_qubits=1).optimize_circuit(circuit_sand)
140-
cirq.DropNegligible(tolerance=1e-6).optimize_circuit(circuit_sand)
140+
circuit_sand = cirq.drop_negligible_operations(circuit_sand, atol=1e-6)
141141
MergeNQubitGates(n_qubits=2).optimize_circuit(circuit_sand)
142-
cirq.DropNegligible(tolerance=1e-6)
143-
cirq.DropEmptyMoments().optimize_circuit(circuit_sand)
142+
circuit_sand = cirq.drop_empty_moments(circuit_sand)
144143
new_n_op = sum(1 for _ in circuit_sand.all_operations())
145144

146145
if new_n_op < n_op:

cirq-core/cirq/devices/device.py

+5
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ def validate_moment(self, moment: 'cirq.Moment') -> None:
158158
for operation in moment.operations:
159159
self.validate_operation(operation)
160160

161+
@_compat.deprecated(
162+
deadline='v0.15',
163+
fix='can_add_operation_into_moment will be removed in the future.'
164+
' Consider using device.validate_circuit instead.',
165+
)
161166
def can_add_operation_into_moment(
162167
self, operation: 'cirq.Operation', moment: 'cirq.Moment'
163168
) -> bool:

cirq-core/cirq/ion/ion_device_test.py

+16-15
Original file line numberDiff line numberDiff line change
@@ -156,21 +156,22 @@ def num_qubits(self):
156156
d.validate_operation(NotImplementedOperation())
157157

158158

159-
def test_can_add_operation_into_moment():
160-
d = ion_device(3)
161-
q0 = cirq.LineQubit(0)
162-
q1 = cirq.LineQubit(1)
163-
q2 = cirq.LineQubit(2)
164-
q3 = cirq.LineQubit(3)
165-
circuit = cirq.Circuit()
166-
circuit.append(cirq.XX(q0, q1))
167-
for moment in circuit:
168-
assert not d.can_add_operation_into_moment(cirq.XX(q2, q0), moment)
169-
assert not d.can_add_operation_into_moment(cirq.XX(q1, q2), moment)
170-
assert d.can_add_operation_into_moment(cirq.XX(q2, q3), moment)
171-
assert d.can_add_operation_into_moment(cirq.Z(q3), moment)
172-
circuit = cirq.Circuit([cirq.X(q0)])
173-
assert d.can_add_operation_into_moment(cirq.XX(q1, q2), circuit[0])
159+
def test_can_add_operation_into_moment_device_deprecated():
160+
with cirq.testing.assert_deprecated('can_add_operation_into_moment', deadline='v0.15', count=5):
161+
d = ion_device(3)
162+
q0 = cirq.LineQubit(0)
163+
q1 = cirq.LineQubit(1)
164+
q2 = cirq.LineQubit(2)
165+
q3 = cirq.LineQubit(3)
166+
circuit = cirq.Circuit()
167+
circuit.append(cirq.XX(q0, q1))
168+
for moment in circuit:
169+
assert not d.can_add_operation_into_moment(cirq.XX(q2, q0), moment)
170+
assert not d.can_add_operation_into_moment(cirq.XX(q1, q2), moment)
171+
assert d.can_add_operation_into_moment(cirq.XX(q2, q3), moment)
172+
assert d.can_add_operation_into_moment(cirq.Z(q3), moment)
173+
circuit = cirq.Circuit([cirq.X(q0)])
174+
assert d.can_add_operation_into_moment(cirq.XX(q1, q2), circuit[0])
174175

175176

176177
def test_ion_device_eq():

cirq-core/cirq/neutral_atoms/neutral_atom_devices_test.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,16 @@ def test_validate_moment_errors():
220220
d2.validate_moment(m)
221221

222222

223-
def test_can_add_operation_into_moment_coverage():
224-
d = square_device(2, 2)
225-
q00 = cirq.GridQubit(0, 0)
226-
q01 = cirq.GridQubit(0, 1)
227-
q10 = cirq.GridQubit(1, 0)
228-
m = cirq.Moment([cirq.X.on(q00)])
229-
assert not d.can_add_operation_into_moment(cirq.X.on(q00), m)
230-
assert not d.can_add_operation_into_moment(cirq.CZ.on(q01, q10), m)
231-
assert d.can_add_operation_into_moment(cirq.Z.on(q01), m)
223+
def test_can_add_operation_into_moment_coverage_deprecated():
224+
with cirq.testing.assert_deprecated('can_add_operation_into_moment', deadline='v0.15', count=3):
225+
d = square_device(2, 2)
226+
q00 = cirq.GridQubit(0, 0)
227+
q01 = cirq.GridQubit(0, 1)
228+
q10 = cirq.GridQubit(1, 0)
229+
m = cirq.Moment([cirq.X.on(q00)])
230+
assert not d.can_add_operation_into_moment(cirq.X.on(q00), m)
231+
assert not d.can_add_operation_into_moment(cirq.CZ.on(q01, q10), m)
232+
assert d.can_add_operation_into_moment(cirq.Z.on(q01), m)
232233

233234

234235
def test_validate_circuit_errors():

cirq-core/cirq/ops/pauli_string_phasor_test.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,8 @@ def test_drop_negligible():
250250
cirq.PauliStringPhasor(cirq.PauliString({q0: cirq.Z})) ** 0.25,
251251
cirq.PauliStringPhasor(cirq.PauliString({q0: cirq.Z})) ** sym,
252252
)
253-
cirq.DropNegligible().optimize_circuit(circuit)
254-
cirq.DropEmptyMoments().optimize_circuit(circuit)
253+
circuit = cirq.drop_negligible_operations(circuit)
254+
circuit = cirq.drop_empty_moments(circuit)
255255
assert circuit == expected
256256

257257

cirq-core/cirq/optimizers/drop_empty_moments.py

+2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616

1717
from cirq.circuits.circuit import Circuit
1818
from cirq.circuits import circuit as _circuit
19+
from cirq._compat import deprecated_class
1920

2021

22+
@deprecated_class(deadline='v1.0', fix='Use cirq.drop_empty_moments instead.')
2123
class DropEmptyMoments:
2224
"""Removes empty moments from a circuit."""
2325

cirq-core/cirq/optimizers/drop_empty_moments_test.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616

1717

1818
def assert_optimizes(before, after):
19-
opt = cirq.DropEmptyMoments()
20-
opt.optimize_circuit(before)
21-
assert before == after
19+
with cirq.testing.assert_deprecated("Use cirq.drop_empty_moments", deadline='v1.0'):
20+
opt = cirq.DropEmptyMoments()
21+
opt.optimize_circuit(before)
22+
assert before == after
2223

2324

2425
def test_drop():

cirq-core/cirq/optimizers/drop_negligible.py

+2
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818

1919
from cirq import protocols
2020
from cirq.circuits import circuit as _circuit
21+
from cirq._compat import deprecated_class
2122

2223
if TYPE_CHECKING:
2324
from cirq import ops
2425

2526

27+
@deprecated_class(deadline='v1.0', fix='Use cirq.drop_negligible_operations instead.')
2628
class DropNegligible:
2729
"""An optimization pass that removes operations with tiny effects."""
2830

cirq-core/cirq/optimizers/drop_negligible_test.py

+10-12
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,26 @@
1515
import cirq
1616

1717

18-
def assert_optimizes(optimizer, initial_circuit: cirq.Circuit, expected_circuit: cirq.Circuit):
19-
circuit = cirq.Circuit(initial_circuit)
20-
optimizer.optimize_circuit(circuit)
21-
assert circuit == expected_circuit
18+
def assert_optimizes(atol: float, initial_circuit: cirq.Circuit, expected_circuit: cirq.Circuit):
19+
with cirq.testing.assert_deprecated("Use cirq.drop_negligible_operations", deadline='v1.0'):
20+
optimizer = cirq.DropNegligible(atol)
21+
circuit = cirq.Circuit(initial_circuit)
22+
optimizer.optimize_circuit(circuit)
23+
assert circuit == expected_circuit
2224

2325

2426
def test_leaves_big():
25-
drop = cirq.DropNegligible(0.001)
2627
a = cirq.NamedQubit('a')
2728
circuit = cirq.Circuit([cirq.Moment([cirq.Z(a) ** 0.1])])
2829

29-
assert_optimizes(optimizer=drop, initial_circuit=circuit, expected_circuit=circuit)
30+
assert_optimizes(0.001, initial_circuit=circuit, expected_circuit=circuit)
3031

3132

3233
def test_clears_small():
33-
drop = cirq.DropNegligible(0.001)
3434
a = cirq.NamedQubit('a')
3535
circuit = cirq.Circuit([cirq.Moment([cirq.Z(a) ** 0.000001])])
3636

37-
assert_optimizes(
38-
optimizer=drop, initial_circuit=circuit, expected_circuit=cirq.Circuit([cirq.Moment()])
39-
)
37+
assert_optimizes(0.001, initial_circuit=circuit, expected_circuit=cirq.Circuit([cirq.Moment()]))
4038

4139

4240
def test_clears_known_empties_even_at_zero_tolerance():
@@ -45,12 +43,12 @@ def test_clears_known_empties_even_at_zero_tolerance():
4543
cirq.Z(a) ** 0, cirq.Y(a) ** 0.0000001, cirq.X(a) ** -0.0000001, cirq.CZ(a, b) ** 0
4644
)
4745
assert_optimizes(
48-
optimizer=cirq.DropNegligible(tolerance=0.001),
46+
0.001,
4947
initial_circuit=circuit,
5048
expected_circuit=cirq.Circuit([cirq.Moment()] * 4),
5149
)
5250
assert_optimizes(
53-
optimizer=cirq.DropNegligible(tolerance=0),
51+
0,
5452
initial_circuit=circuit,
5553
expected_circuit=cirq.Circuit(
5654
[

0 commit comments

Comments
 (0)