1
+ # Copyright 2021 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
1
15
from typing import Callable , List
2
16
17
+ import pytest
18
+
3
19
import cirq
4
20
5
21
6
22
def assert_optimizes (before : cirq .Circuit , expected : cirq .Circuit , ** kwargs ):
7
- actual = cirq .Circuit (before )
23
+ """Check that optimizing the circuit ``before`` produces the circuit ``expected``.
24
+
25
+ The optimized circuit is cleaned up with follow up optimizations to make the
26
+ comparison more robust to extra moments or extra gates nearly equal to
27
+ identity that don't matter.
28
+
29
+ Args:
30
+ before: The input circuit to optimize.
31
+ expected: The expected result of optimization to compare against.
32
+ kwargs: Any extra arguments to pass to the
33
+ ``MergeInteractionsToSqrtIswap`` constructor.
34
+ """
35
+ actual = before .copy ()
8
36
opt = cirq .MergeInteractionsToSqrtIswap (** kwargs )
9
37
opt .optimize_circuit (actual )
10
38
@@ -23,21 +51,21 @@ def assert_optimizes(before: cirq.Circuit, expected: cirq.Circuit, **kwargs):
23
51
assert actual == expected , f'ACTUAL { actual } : EXPECTED { expected } '
24
52
25
53
26
- def assert_optimization_not_broken (circuit : cirq .Circuit ):
54
+ def assert_optimization_not_broken (circuit : cirq .Circuit , ** kwargs ):
27
55
"""Check that the unitary matrix for the input circuit is the same (up to
28
56
global phase and rounding error) as the unitary matrix of the optimized
29
57
circuit."""
30
58
u_before = circuit .unitary ()
31
59
c_sqrt_iswap = circuit .copy ()
32
- cirq .MergeInteractionsToSqrtIswap ().optimize_circuit (c_sqrt_iswap )
33
- u_after = c_sqrt_iswap .unitary ()
60
+ cirq .MergeInteractionsToSqrtIswap (** kwargs ).optimize_circuit (c_sqrt_iswap )
61
+ u_after = c_sqrt_iswap .unitary (circuit . all_qubits () )
34
62
35
63
cirq .testing .assert_allclose_up_to_global_phase (u_before , u_after , atol = 2e-8 )
36
64
37
65
# Also test optimization with SQRT_ISWAP_INV
38
66
c_sqrt_iswap_inv = circuit .copy ()
39
67
cirq .MergeInteractionsToSqrtIswap (use_sqrt_iswap_inv = True ).optimize_circuit (c_sqrt_iswap_inv )
40
- u_after2 = c_sqrt_iswap_inv .unitary ()
68
+ u_after2 = c_sqrt_iswap_inv .unitary (circuit . all_qubits () )
41
69
42
70
cirq .testing .assert_allclose_up_to_global_phase (u_before , u_after2 , atol = 2e-8 )
43
71
@@ -106,6 +134,57 @@ def test_simplifies_sqrt_iswap_inv():
106
134
)
107
135
108
136
137
+ def test_works_with_tags ():
138
+ a , b = cirq .LineQubit .range (2 )
139
+ assert_optimizes (
140
+ before = cirq .Circuit (
141
+ [
142
+ cirq .Moment ([cirq .SQRT_ISWAP (a , b ).with_tags ('mytag1' )]),
143
+ cirq .Moment ([cirq .SQRT_ISWAP (a , b ).with_tags ('mytag2' )]),
144
+ cirq .Moment ([cirq .SQRT_ISWAP_INV (a , b ).with_tags ('mytag3' )]),
145
+ ]
146
+ ),
147
+ expected = cirq .Circuit (
148
+ [
149
+ cirq .Moment ([cirq .SQRT_ISWAP (a , b )]),
150
+ ]
151
+ ),
152
+ )
153
+
154
+
155
+ def test_no_touch_single_sqrt_iswap ():
156
+ a , b = cirq .LineQubit .range (2 )
157
+ assert_optimizes (
158
+ before = cirq .Circuit (
159
+ [
160
+ cirq .Moment ([cirq .SQRT_ISWAP (a , b ).with_tags ('mytag' )]),
161
+ ]
162
+ ),
163
+ expected = cirq .Circuit (
164
+ [
165
+ cirq .Moment ([cirq .SQRT_ISWAP (a , b ).with_tags ('mytag' )]),
166
+ ]
167
+ ),
168
+ )
169
+
170
+
171
+ def test_no_touch_single_sqrt_iswap_inv ():
172
+ a , b = cirq .LineQubit .range (2 )
173
+ assert_optimizes (
174
+ use_sqrt_iswap_inv = True ,
175
+ before = cirq .Circuit (
176
+ [
177
+ cirq .Moment ([cirq .SQRT_ISWAP_INV (a , b ).with_tags ('mytag' )]),
178
+ ]
179
+ ),
180
+ expected = cirq .Circuit (
181
+ [
182
+ cirq .Moment ([cirq .SQRT_ISWAP_INV (a , b ).with_tags ('mytag' )]),
183
+ ]
184
+ ),
185
+ )
186
+
187
+
109
188
def test_cnots_separated_by_single_gates_correct ():
110
189
a , b = cirq .LineQubit .range (2 )
111
190
assert_optimization_not_broken (
@@ -165,23 +244,73 @@ def test_optimizes_single_iswap():
165
244
166
245
def test_optimizes_single_inv_sqrt_iswap ():
167
246
a , b = cirq .LineQubit .range (2 )
168
- c = cirq .Circuit (cirq .SQRT_ISWAP (a , b ) ** - 1 )
247
+ c = cirq .Circuit (cirq .SQRT_ISWAP_INV (a , b ))
169
248
assert_optimization_not_broken (c )
170
249
cirq .MergeInteractionsToSqrtIswap ().optimize_circuit (c )
171
250
assert len ([1 for op in c .all_operations () if len (op .qubits ) == 2 ]) == 1
172
251
173
252
253
+ def test_init_raises ():
254
+ with pytest .raises (ValueError , match = 'must be 0, 1, 2, or 3' ):
255
+ cirq .MergeInteractionsToSqrtIswap (required_sqrt_iswap_count = 4 )
256
+
257
+
258
+ def test_optimizes_single_iswap_require0 ():
259
+ a , b = cirq .LineQubit .range (2 )
260
+ c = cirq .Circuit (cirq .CNOT (a , b ), cirq .CNOT (a , b )) # Minimum 0 sqrt-iSWAP
261
+ assert_optimization_not_broken (c , required_sqrt_iswap_count = 0 )
262
+ cirq .MergeInteractionsToSqrtIswap (required_sqrt_iswap_count = 0 ).optimize_circuit (c )
263
+ assert len ([1 for op in c .all_operations () if len (op .qubits ) == 2 ]) == 0
264
+
265
+
266
+ def test_optimizes_single_iswap_require0_raises ():
267
+ a , b = cirq .LineQubit .range (2 )
268
+ c = cirq .Circuit (cirq .CNOT (a , b )) # Minimum 2 sqrt-iSWAP
269
+ with pytest .raises (ValueError , match = 'cannot be decomposed into exactly 0 sqrt-iSWAP gates' ):
270
+ cirq .MergeInteractionsToSqrtIswap (required_sqrt_iswap_count = 0 ).optimize_circuit (c )
271
+
272
+
273
+ def test_optimizes_single_iswap_require1 ():
274
+ a , b = cirq .LineQubit .range (2 )
275
+ c = cirq .Circuit (cirq .SQRT_ISWAP_INV (a , b )) # Minimum 1 sqrt-iSWAP
276
+ assert_optimization_not_broken (c , required_sqrt_iswap_count = 1 )
277
+ cirq .MergeInteractionsToSqrtIswap (required_sqrt_iswap_count = 1 ).optimize_circuit (c )
278
+ assert len ([1 for op in c .all_operations () if len (op .qubits ) == 2 ]) == 1
279
+
280
+
281
+ def test_optimizes_single_iswap_require1_raises ():
282
+ a , b = cirq .LineQubit .range (2 )
283
+ c = cirq .Circuit (cirq .CNOT (a , b )) # Minimum 2 sqrt-iSWAP
284
+ with pytest .raises (ValueError , match = 'cannot be decomposed into exactly 1 sqrt-iSWAP gates' ):
285
+ cirq .MergeInteractionsToSqrtIswap (required_sqrt_iswap_count = 1 ).optimize_circuit (c )
286
+
287
+
288
+ def test_optimizes_single_iswap_require2 ():
289
+ a , b = cirq .LineQubit .range (2 )
290
+ c = cirq .Circuit (cirq .SQRT_ISWAP_INV (a , b )) # Minimum 1 sqrt-iSWAP but 2 possible
291
+ assert_optimization_not_broken (c , required_sqrt_iswap_count = 2 )
292
+ cirq .MergeInteractionsToSqrtIswap (required_sqrt_iswap_count = 2 ).optimize_circuit (c )
293
+ assert len ([1 for op in c .all_operations () if len (op .qubits ) == 2 ]) == 2
294
+
295
+
296
+ def test_optimizes_single_iswap_require2_raises ():
297
+ a , b = cirq .LineQubit .range (2 )
298
+ c = cirq .Circuit (cirq .SWAP (a , b )) # Minimum 3 sqrt-iSWAP
299
+ with pytest .raises (ValueError , match = 'cannot be decomposed into exactly 2 sqrt-iSWAP gates' ):
300
+ cirq .MergeInteractionsToSqrtIswap (required_sqrt_iswap_count = 2 ).optimize_circuit (c )
301
+
302
+
174
303
def test_optimizes_single_iswap_require3 ():
175
304
a , b = cirq .LineQubit .range (2 )
176
- c = cirq .Circuit (cirq .ISWAP (a , b ))
177
- assert_optimization_not_broken (c )
178
- cirq .MergeInteractionsToSqrtIswap (require_three_sqrt_iswap = True ).optimize_circuit (c )
305
+ c = cirq .Circuit (cirq .ISWAP (a , b )) # Minimum 2 sqrt-iSWAP but 3 possible
306
+ assert_optimization_not_broken (c , required_sqrt_iswap_count = 3 )
307
+ cirq .MergeInteractionsToSqrtIswap (required_sqrt_iswap_count = 3 ).optimize_circuit (c )
179
308
assert len ([1 for op in c .all_operations () if len (op .qubits ) == 2 ]) == 3
180
309
181
310
182
311
def test_optimizes_single_inv_sqrt_iswap_require3 ():
183
312
a , b = cirq .LineQubit .range (2 )
184
- c = cirq .Circuit (cirq .SQRT_ISWAP (a , b ) ** - 1 )
185
- assert_optimization_not_broken (c )
186
- cirq .MergeInteractionsToSqrtIswap (require_three_sqrt_iswap = True ).optimize_circuit (c )
313
+ c = cirq .Circuit (cirq .SQRT_ISWAP_INV (a , b ))
314
+ assert_optimization_not_broken (c , required_sqrt_iswap_count = 3 )
315
+ cirq .MergeInteractionsToSqrtIswap (required_sqrt_iswap_count = 3 ).optimize_circuit (c )
187
316
assert len ([1 for op in c .all_operations () if len (op .qubits ) == 2 ]) == 3
0 commit comments