1# Copyright 2018 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
15import pytest
16
17import cirq
18import cirq.testing
19
20
21def test_validation():
22    a = cirq.NamedQubit('a')
23    b = cirq.NamedQubit('b')
24    c = cirq.NamedQubit('c')
25    d = cirq.NamedQubit('d')
26
27    _ = cirq.Moment([])
28    _ = cirq.Moment([cirq.X(a)])
29    _ = cirq.Moment([cirq.CZ(a, b)])
30    _ = cirq.Moment([cirq.CZ(b, d)])
31    _ = cirq.Moment([cirq.CZ(a, b), cirq.CZ(c, d)])
32    _ = cirq.Moment([cirq.CZ(a, c), cirq.CZ(b, d)])
33    _ = cirq.Moment([cirq.CZ(a, c), cirq.X(b)])
34
35    with pytest.raises(ValueError):
36        _ = cirq.Moment([cirq.X(a), cirq.X(a)])
37    with pytest.raises(ValueError):
38        _ = cirq.Moment([cirq.CZ(a, c), cirq.X(c)])
39    with pytest.raises(ValueError):
40        _ = cirq.Moment([cirq.CZ(a, c), cirq.CZ(c, d)])
41
42
43def test_equality():
44    a = cirq.NamedQubit('a')
45    b = cirq.NamedQubit('b')
46    c = cirq.NamedQubit('c')
47    d = cirq.NamedQubit('d')
48
49    eq = cirq.testing.EqualsTester()
50
51    # Default is empty. Iterables get frozen into tuples.
52    eq.add_equality_group(cirq.Moment(), cirq.Moment([]), cirq.Moment(()))
53    eq.add_equality_group(cirq.Moment([cirq.X(d)]), cirq.Moment((cirq.X(d),)))
54
55    # Equality depends on gate and qubits.
56    eq.add_equality_group(cirq.Moment([cirq.X(a)]))
57    eq.add_equality_group(cirq.Moment([cirq.X(b)]))
58    eq.add_equality_group(cirq.Moment([cirq.Y(a)]))
59
60    # Equality doesn't depend on order.
61    eq.add_equality_group(cirq.Moment([cirq.X(a), cirq.X(b)]), cirq.Moment([cirq.X(a), cirq.X(b)]))
62
63    # Two qubit gates.
64    eq.make_equality_group(lambda: cirq.Moment([cirq.CZ(c, d)]))
65    eq.make_equality_group(lambda: cirq.Moment([cirq.CZ(a, c)]))
66    eq.make_equality_group(lambda: cirq.Moment([cirq.CZ(a, b), cirq.CZ(c, d)]))
67    eq.make_equality_group(lambda: cirq.Moment([cirq.CZ(a, c), cirq.CZ(b, d)]))
68
69
70def test_approx_eq():
71    a = cirq.NamedQubit('a')
72    b = cirq.NamedQubit('b')
73
74    assert not cirq.approx_eq(cirq.Moment([cirq.X(a)]), cirq.X(a))
75
76    # Default is empty. Iterables get frozen into tuples.
77    assert cirq.approx_eq(cirq.Moment(), cirq.Moment([]))
78    assert cirq.approx_eq(cirq.Moment([]), cirq.Moment(()))
79
80    assert cirq.approx_eq(cirq.Moment([cirq.X(a)]), cirq.Moment([cirq.X(a)]))
81    assert not cirq.approx_eq(cirq.Moment([cirq.X(a)]), cirq.Moment([cirq.X(b)]))
82
83    assert cirq.approx_eq(
84        cirq.Moment([cirq.XPowGate(exponent=0)(a)]), cirq.Moment([cirq.XPowGate(exponent=1e-9)(a)])
85    )
86    assert not cirq.approx_eq(
87        cirq.Moment([cirq.XPowGate(exponent=0)(a)]), cirq.Moment([cirq.XPowGate(exponent=1e-7)(a)])
88    )
89    assert cirq.approx_eq(
90        cirq.Moment([cirq.XPowGate(exponent=0)(a)]),
91        cirq.Moment([cirq.XPowGate(exponent=1e-7)(a)]),
92        atol=1e-6,
93    )
94
95
96def test_operates_on_single_qubit():
97    a = cirq.NamedQubit('a')
98    b = cirq.NamedQubit('b')
99    c = cirq.NamedQubit('c')
100
101    # Empty case.
102    assert not cirq.Moment().operates_on_single_qubit(a)
103    assert not cirq.Moment().operates_on_single_qubit(b)
104
105    # One-qubit operation case.
106    assert cirq.Moment([cirq.X(a)]).operates_on_single_qubit(a)
107    assert not cirq.Moment([cirq.X(a)]).operates_on_single_qubit(b)
108
109    # Two-qubit operation case.
110    assert cirq.Moment([cirq.CZ(a, b)]).operates_on_single_qubit(a)
111    assert cirq.Moment([cirq.CZ(a, b)]).operates_on_single_qubit(b)
112    assert not cirq.Moment([cirq.CZ(a, b)]).operates_on_single_qubit(c)
113
114    # Multiple operations case.
115    assert cirq.Moment([cirq.X(a), cirq.X(b)]).operates_on_single_qubit(a)
116    assert cirq.Moment([cirq.X(a), cirq.X(b)]).operates_on_single_qubit(b)
117    assert not cirq.Moment([cirq.X(a), cirq.X(b)]).operates_on_single_qubit(c)
118
119
120def test_operates_on():
121    a = cirq.NamedQubit('a')
122    b = cirq.NamedQubit('b')
123    c = cirq.NamedQubit('c')
124
125    # Empty case.
126    assert not cirq.Moment().operates_on([])
127    assert not cirq.Moment().operates_on([a])
128    assert not cirq.Moment().operates_on([b])
129    assert not cirq.Moment().operates_on([a, b])
130
131    # One-qubit operation case.
132    assert not cirq.Moment([cirq.X(a)]).operates_on([])
133    assert cirq.Moment([cirq.X(a)]).operates_on([a])
134    assert not cirq.Moment([cirq.X(a)]).operates_on([b])
135    assert cirq.Moment([cirq.X(a)]).operates_on([a, b])
136
137    # Two-qubit operation case.
138    assert not cirq.Moment([cirq.CZ(a, b)]).operates_on([])
139    assert cirq.Moment([cirq.CZ(a, b)]).operates_on([a])
140    assert cirq.Moment([cirq.CZ(a, b)]).operates_on([b])
141    assert cirq.Moment([cirq.CZ(a, b)]).operates_on([a, b])
142    assert not cirq.Moment([cirq.CZ(a, b)]).operates_on([c])
143    assert cirq.Moment([cirq.CZ(a, b)]).operates_on([a, c])
144    assert cirq.Moment([cirq.CZ(a, b)]).operates_on([a, b, c])
145
146    # Multiple operations case.
147    assert not cirq.Moment([cirq.X(a), cirq.X(b)]).operates_on([])
148    assert cirq.Moment([cirq.X(a), cirq.X(b)]).operates_on([a])
149    assert cirq.Moment([cirq.X(a), cirq.X(b)]).operates_on([b])
150    assert cirq.Moment([cirq.X(a), cirq.X(b)]).operates_on([a, b])
151    assert not cirq.Moment([cirq.X(a), cirq.X(b)]).operates_on([c])
152    assert cirq.Moment([cirq.X(a), cirq.X(b)]).operates_on([a, c])
153    assert cirq.Moment([cirq.X(a), cirq.X(b)]).operates_on([a, b, c])
154
155
156def test_operation_at():
157    a = cirq.NamedQubit('a')
158    b = cirq.NamedQubit('b')
159    c = cirq.NamedQubit('c')
160
161    # No operation on that qubit
162    assert cirq.Moment().operation_at(a) is None
163
164    # One Operation on the quibt
165    assert cirq.Moment([cirq.X(a)]).operation_at(a) == cirq.X(a)
166
167    # Multiple Operations on the qubits
168    assert cirq.Moment([cirq.CZ(a, b), cirq.X(c)]).operation_at(a) == cirq.CZ(a, b)
169
170
171def test_with_operation():
172    a = cirq.NamedQubit('a')
173    b = cirq.NamedQubit('b')
174
175    assert cirq.Moment().with_operation(cirq.X(a)) == cirq.Moment([cirq.X(a)])
176
177    assert cirq.Moment([cirq.X(a)]).with_operation(cirq.X(b)) == cirq.Moment([cirq.X(a), cirq.X(b)])
178
179    # One-qubit operation case.
180    with pytest.raises(ValueError):
181        _ = cirq.Moment([cirq.X(a)]).with_operation(cirq.X(a))
182
183    # Two-qubit operation case.
184    with pytest.raises(ValueError):
185        _ = cirq.Moment([cirq.CZ(a, b)]).with_operation(cirq.X(a))
186    with pytest.raises(ValueError):
187        _ = cirq.Moment([cirq.CZ(a, b)]).with_operation(cirq.X(b))
188
189    # Multiple operations case.
190    with pytest.raises(ValueError):
191        _ = cirq.Moment([cirq.X(a), cirq.X(b)]).with_operation(cirq.X(a))
192    with pytest.raises(ValueError):
193        _ = cirq.Moment([cirq.X(a), cirq.X(b)]).with_operation(cirq.X(b))
194
195
196def test_with_operations():
197    a = cirq.NamedQubit('a')
198    b = cirq.NamedQubit('b')
199    c = cirq.NamedQubit('c')
200
201    assert cirq.Moment().with_operations(cirq.X(a)) == cirq.Moment([cirq.X(a)])
202    assert cirq.Moment().with_operations(cirq.X(a), cirq.X(b)) == cirq.Moment(
203        [cirq.X(a), cirq.X(b)]
204    )
205
206    assert cirq.Moment([cirq.X(a)]).with_operations(cirq.X(b)) == cirq.Moment(
207        [cirq.X(a), cirq.X(b)]
208    )
209    assert cirq.Moment([cirq.X(a)]).with_operations(cirq.X(b), cirq.X(c)) == cirq.Moment(
210        [cirq.X(a), cirq.X(b), cirq.X(c)]
211    )
212
213    # One-qubit operation case.
214    with pytest.raises(ValueError):
215        _ = cirq.Moment([cirq.X(a)]).with_operations(cirq.X(a))
216
217    # Two-qubit operation case.
218    with pytest.raises(ValueError):
219        _ = cirq.Moment([cirq.CZ(a, b)]).with_operations(cirq.X(a))
220    with pytest.raises(ValueError):
221        _ = cirq.Moment([cirq.CZ(a, b)]).with_operations(cirq.X(b))
222
223    # Multiple operations case.
224    with pytest.raises(ValueError):
225        _ = cirq.Moment([cirq.X(a), cirq.X(b)]).with_operations(cirq.X(a))
226    with pytest.raises(ValueError):
227        _ = cirq.Moment([cirq.X(a), cirq.X(b)]).with_operations(cirq.X(b))
228
229
230def test_without_operations_touching():
231    a = cirq.NamedQubit('a')
232    b = cirq.NamedQubit('b')
233    c = cirq.NamedQubit('c')
234
235    # Empty case.
236    assert cirq.Moment().without_operations_touching([]) == cirq.Moment()
237    assert cirq.Moment().without_operations_touching([a]) == cirq.Moment()
238    assert cirq.Moment().without_operations_touching([a, b]) == cirq.Moment()
239
240    # One-qubit operation case.
241    assert cirq.Moment([cirq.X(a)]).without_operations_touching([]) == cirq.Moment([cirq.X(a)])
242    assert cirq.Moment([cirq.X(a)]).without_operations_touching([a]) == cirq.Moment()
243    assert cirq.Moment([cirq.X(a)]).without_operations_touching([b]) == cirq.Moment([cirq.X(a)])
244
245    # Two-qubit operation case.
246    assert cirq.Moment([cirq.CZ(a, b)]).without_operations_touching([]) == cirq.Moment(
247        [cirq.CZ(a, b)]
248    )
249    assert cirq.Moment([cirq.CZ(a, b)]).without_operations_touching([a]) == cirq.Moment()
250    assert cirq.Moment([cirq.CZ(a, b)]).without_operations_touching([b]) == cirq.Moment()
251    assert cirq.Moment([cirq.CZ(a, b)]).without_operations_touching([c]) == cirq.Moment(
252        [cirq.CZ(a, b)]
253    )
254
255    # Multiple operation case.
256    assert cirq.Moment([cirq.CZ(a, b), cirq.X(c)]).without_operations_touching([]) == cirq.Moment(
257        [cirq.CZ(a, b), cirq.X(c)]
258    )
259    assert cirq.Moment([cirq.CZ(a, b), cirq.X(c)]).without_operations_touching([a]) == cirq.Moment(
260        [cirq.X(c)]
261    )
262    assert cirq.Moment([cirq.CZ(a, b), cirq.X(c)]).without_operations_touching([b]) == cirq.Moment(
263        [cirq.X(c)]
264    )
265    assert cirq.Moment([cirq.CZ(a, b), cirq.X(c)]).without_operations_touching([c]) == cirq.Moment(
266        [cirq.CZ(a, b)]
267    )
268    assert cirq.Moment([cirq.CZ(a, b), cirq.X(c)]).without_operations_touching(
269        [a, b]
270    ) == cirq.Moment([cirq.X(c)])
271    assert (
272        cirq.Moment([cirq.CZ(a, b), cirq.X(c)]).without_operations_touching([a, c]) == cirq.Moment()
273    )
274
275
276def test_with_measurement_keys():
277    a, b = cirq.LineQubit.range(2)
278    m = cirq.Moment(cirq.measure(a, key='m1'), cirq.measure(b, key='m2'))
279
280    new_moment = cirq.with_measurement_key_mapping(
281        m,
282        {
283            'm1': 'p1',
284            'm2': 'p2',
285            'x': 'z',
286        },
287    )
288
289    assert new_moment.operations[0] == cirq.measure(a, key='p1')
290    assert new_moment.operations[1] == cirq.measure(b, key='p2')
291
292
293def test_with_key_path():
294    a, b = cirq.LineQubit.range(2)
295    m = cirq.Moment(cirq.measure(a, key='m1'), cirq.measure(b, key='m2'))
296
297    new_moment = cirq.with_key_path(m, ('a', 'b'))
298
299    assert new_moment.operations[0] == cirq.measure(
300        a, key=cirq.MeasurementKey.parse_serialized('a:b:m1')
301    )
302    assert new_moment.operations[1] == cirq.measure(
303        b, key=cirq.MeasurementKey.parse_serialized('a:b:m2')
304    )
305
306
307def test_copy():
308    a = cirq.NamedQubit('a')
309    b = cirq.NamedQubit('b')
310    original = cirq.Moment([cirq.CZ(a, b)])
311    copy = original.__copy__()
312    assert original == copy
313    assert id(original) != id(copy)
314
315
316def test_qubits():
317    a = cirq.NamedQubit('a')
318    b = cirq.NamedQubit('b')
319
320    assert cirq.Moment([cirq.X(a), cirq.X(b)]).qubits == {a, b}
321    assert cirq.Moment([cirq.X(a)]).qubits == {a}
322    assert cirq.Moment([cirq.CZ(a, b)]).qubits == {a, b}
323
324
325def test_container_methods():
326    a = cirq.NamedQubit('a')
327    b = cirq.NamedQubit('b')
328    m = cirq.Moment([cirq.H(a), cirq.H(b)])
329    assert list(m) == list(m.operations)
330    # __iter__
331    assert list(iter(m)) == list(m.operations)
332    # __contains__ for free.
333    assert cirq.H(b) in m
334
335    assert len(m) == 2
336
337
338def test_decompose():
339    a = cirq.NamedQubit('a')
340    b = cirq.NamedQubit('b')
341    m = cirq.Moment(cirq.X(a), cirq.X(b))
342    assert list(cirq.decompose(m)) == list(m.operations)
343
344
345def test_measurement_keys():
346    a = cirq.NamedQubit('a')
347    b = cirq.NamedQubit('b')
348    m = cirq.Moment(cirq.X(a), cirq.X(b))
349    assert cirq.measurement_key_names(m) == set()
350    assert not cirq.is_measurement(m)
351
352    m2 = cirq.Moment(cirq.measure(a, b, key='foo'))
353    assert cirq.measurement_key_objs(m2) == {cirq.MeasurementKey('foo')}
354    assert cirq.measurement_key_names(m2) == {'foo'}
355    assert cirq.is_measurement(m2)
356
357
358def test_bool():
359    assert not cirq.Moment()
360    a = cirq.NamedQubit('a')
361    assert cirq.Moment([cirq.X(a)])
362
363
364def test_repr():
365    a = cirq.NamedQubit('a')
366    b = cirq.NamedQubit('b')
367
368    cirq.testing.assert_equivalent_repr(cirq.Moment())
369    cirq.testing.assert_equivalent_repr(cirq.Moment(cirq.CZ(a, b)))
370    cirq.testing.assert_equivalent_repr(cirq.Moment(cirq.X(a), cirq.Y(b)))
371
372
373def test_json_dict():
374    a = cirq.NamedQubit('a')
375    b = cirq.NamedQubit('b')
376    mom = cirq.Moment([cirq.CZ(a, b)])
377    assert mom._json_dict_() == {'cirq_type': 'Moment', 'operations': (cirq.CZ(a, b),)}
378
379
380def test_inverse():
381    a, b, c = cirq.LineQubit.range(3)
382    m = cirq.Moment([cirq.S(a), cirq.CNOT(b, c)])
383    assert m ** 1 is m
384    assert m ** -1 == cirq.Moment([cirq.S(a) ** -1, cirq.CNOT(b, c)])
385    assert m ** 0.5 == cirq.Moment([cirq.T(a), cirq.CNOT(b, c) ** 0.5])
386    assert cirq.inverse(m) == m ** -1
387    assert cirq.inverse(cirq.inverse(m)) == m
388    assert cirq.inverse(cirq.Moment([cirq.measure(a)]), default=None) is None
389
390
391def test_immutable_moment():
392    with pytest.raises(AttributeError):
393        q1, q2 = cirq.LineQubit.range(2)
394        circuit = cirq.Circuit(cirq.X(q1))
395        moment = circuit.moments[0]
396        moment.operations += (cirq.Y(q2),)
397
398
399def test_add():
400    a, b, c = cirq.LineQubit.range(3)
401    expected_circuit = cirq.Circuit([cirq.CNOT(a, b), cirq.X(a), cirq.Y(b)])
402
403    circuit1 = cirq.Circuit([cirq.CNOT(a, b), cirq.X(a)])
404    circuit1[1] += cirq.Y(b)
405    assert circuit1 == expected_circuit
406
407    circuit2 = cirq.Circuit(cirq.CNOT(a, b), cirq.Y(b))
408    circuit2[1] += cirq.X(a)
409    assert circuit2 == expected_circuit
410
411    m1 = cirq.Moment([cirq.X(a)])
412    m2 = cirq.Moment([cirq.CNOT(a, b)])
413    m3 = cirq.Moment([cirq.X(c)])
414    assert m1 + m3 == cirq.Moment([cirq.X(a), cirq.X(c)])
415    assert m2 + m3 == cirq.Moment([cirq.CNOT(a, b), cirq.X(c)])
416    with pytest.raises(ValueError, match='Overlap'):
417        _ = m1 + m2
418
419    assert m1 + [[[[cirq.Y(b)]]]] == cirq.Moment(cirq.X(a), cirq.Y(b))
420    assert m1 + [] == m1
421
422
423def test_sub():
424    a, b, c = cirq.LineQubit.range(3)
425    m = cirq.Moment(cirq.X(a), cirq.Y(b))
426    assert m - [] == m
427    assert m - cirq.X(a) == cirq.Moment(cirq.Y(b))
428    assert m - [[[[cirq.X(a)]], []]] == cirq.Moment(cirq.Y(b))
429    assert m - [cirq.X(a), cirq.Y(b)] == cirq.Moment()
430    assert m - [cirq.Y(b)] == cirq.Moment(cirq.X(a))
431
432    with pytest.raises(ValueError, match="missing operations"):
433        _ = m - cirq.X(b)
434    with pytest.raises(ValueError, match="missing operations"):
435        _ = m - [cirq.X(a), cirq.Z(c)]
436
437    # Preserves relative order.
438    m2 = cirq.Moment(cirq.X(a), cirq.Y(b), cirq.Z(c))
439    assert m2 - cirq.Y(b) == cirq.Moment(cirq.X(a), cirq.Z(c))
440
441
442def test_op_tree():
443    eq = cirq.testing.EqualsTester()
444    a, b = cirq.LineQubit.range(2)
445
446    eq.add_equality_group(
447        cirq.Moment(),
448        cirq.Moment([]),
449        cirq.Moment([[], [[[]]]]),
450    )
451
452    eq.add_equality_group(
453        cirq.Moment(cirq.X(a)),
454        cirq.Moment([cirq.X(a)]),
455        cirq.Moment({cirq.X(a)}),
456    )
457
458    eq.add_equality_group(
459        cirq.Moment(cirq.X(a), cirq.Y(b)),
460        cirq.Moment([cirq.X(a), cirq.Y(b)]),
461    )
462
463
464def test_indexes_by_qubit():
465    a, b, c = cirq.LineQubit.range(3)
466    moment = cirq.Moment([cirq.H(a), cirq.CNOT(b, c)])
467
468    assert moment[a] == cirq.H(a)
469    assert moment[b] == cirq.CNOT(b, c)
470    assert moment[c] == cirq.CNOT(b, c)
471
472
473def test_throws_when_indexed_by_unused_qubit():
474    a, b = cirq.LineQubit.range(2)
475    moment = cirq.Moment([cirq.H(a)])
476
477    with pytest.raises(KeyError, match="Moment doesn't act on given qubit"):
478        _ = moment[b]
479
480
481def test_indexes_by_list_of_qubits():
482    q = cirq.LineQubit.range(4)
483    moment = cirq.Moment([cirq.Z(q[0]), cirq.CNOT(q[1], q[2])])
484
485    assert moment[[q[0]]] == cirq.Moment([cirq.Z(q[0])])
486    assert moment[[q[1]]] == cirq.Moment([cirq.CNOT(q[1], q[2])])
487    assert moment[[q[2]]] == cirq.Moment([cirq.CNOT(q[1], q[2])])
488    assert moment[[q[3]]] == cirq.Moment([])
489    assert moment[q[0:2]] == moment
490    assert moment[q[1:3]] == cirq.Moment([cirq.CNOT(q[1], q[2])])
491    assert moment[q[2:4]] == cirq.Moment([cirq.CNOT(q[1], q[2])])
492    assert moment[[q[0], q[3]]] == cirq.Moment([cirq.Z(q[0])])
493    assert moment[q] == moment
494
495
496def test_moment_text_diagram():
497    a, b, c, d = cirq.GridQubit.rect(2, 2)
498    m = cirq.Moment(cirq.CZ(a, b), cirq.CNOT(c, d))
499    assert (
500        str(m).strip()
501        == """
502  ╷ 0 1
503╶─┼─────
5040 │ @─@
5055061 │ @─X
507508    """.strip()
509    )
510
511    m = cirq.Moment(cirq.CZ(a, b), cirq.CNOT(c, d))
512    cirq.testing.assert_has_diagram(
513        m,
514        """
515   ╷ None 0 1
516╶──┼──────────
517aa │
5185190  │      @─@
5205211  │      @─X
522523        """,
524        extra_qubits=[cirq.NamedQubit("aa")],
525    )
526
527    m = cirq.Moment(cirq.S(c), cirq.ISWAP(a, d))
528    cirq.testing.assert_has_diagram(
529        m,
530        """
531  ╷ 0     1
532╶─┼─────────────
5330 │ iSwap─┐
534  │       │
5351 │ S     iSwap
536537    """,
538    )
539
540    m = cirq.Moment(cirq.S(c) ** 0.1, cirq.ISWAP(a, d) ** 0.5)
541    cirq.testing.assert_has_diagram(
542        m,
543        """
544  ╷ 0         1
545╶─┼─────────────────
5460 │ iSwap^0.5─┐
547  │           │
5481 │ Z^0.05    iSwap
549550    """,
551    )
552
553    a, b, c = cirq.LineQubit.range(3)
554    m = cirq.Moment(cirq.X(a), cirq.SWAP(b, c))
555    cirq.testing.assert_has_diagram(
556        m,
557        """
558  ╷ a b c
559╶─┼───────
5600 │ X
5615621 │   ×─┐
563  │     │
5642 │     ×
565566    """,
567        xy_breakdown_func=lambda q: ('abc'[q.x], q.x),
568    )
569
570    class EmptyGate(cirq.Gate):
571        def _num_qubits_(self) -> int:
572            return 1
573
574        def __str__(self):
575            return 'Empty'
576
577    m = cirq.Moment(EmptyGate().on(a))
578    cirq.testing.assert_has_diagram(
579        m,
580        """
581  ╷ 0
582╶─┼───────
5830 │ Empty
584585    """,
586    )
587
588
589def test_commutes():
590    a = cirq.NamedQubit('a')
591    b = cirq.NamedQubit('b')
592    c = cirq.NamedQubit('c')
593    d = cirq.NamedQubit('d')
594
595    moment = cirq.Moment([cirq.X(a), cirq.Y(b), cirq.H(c)])
596
597    assert NotImplemented == cirq.commutes(moment, a, default=NotImplemented)
598
599    assert cirq.commutes(moment, cirq.X(a))
600    assert cirq.commutes(moment, cirq.Y(b))
601    assert cirq.commutes(moment, cirq.H(c))
602    assert cirq.commutes(moment, cirq.H(d))
603
604    # X and H do not commute
605    assert not cirq.commutes(moment, cirq.H(a))
606    assert not cirq.commutes(moment, cirq.H(b))
607    assert not cirq.commutes(moment, cirq.X(c))
608
609
610def test_transform_qubits():
611    a, b = cirq.LineQubit.range(2)
612    x, y = cirq.GridQubit.rect(2, 1, 10, 20)
613
614    original = cirq.Moment([cirq.X(a), cirq.Y(b)])
615    modified = cirq.Moment([cirq.X(x), cirq.Y(y)])
616
617    assert original.transform_qubits({a: x, b: y}) == modified
618    assert original.transform_qubits(lambda q: cirq.GridQubit(10 + q.x, 20)) == modified
619    with pytest.raises(TypeError, match='must be a function or dict'):
620        _ = original.transform_qubits('bad arg')
621