@@ -57,6 +57,22 @@ def _small_sample_qubit_pauli_maps():
5757 yield {qubits [0 ]: cirq .Z , qubits [1 ]: cirq .X , qubits [2 ]: cirq .Y }
5858
5959
60+ def assert_conjugation (
61+ input_ps : cirq .PauliString , ops : cirq .OP_TREE , expected : cirq .PauliString | None
62+ ):
63+ conjugation = input_ps .conjugated_by (ops )
64+ if expected is not None :
65+ assert conjugation == expected
66+ else : # Compares the unitary of the conjugation result and the expected unitary.
67+ op_list = list (cirq .flatten_to_ops (ops ))
68+ qubits_of_clifford = [q for op in op_list for q in op .qubits ]
69+ clifford = cirq .CliffordGate .from_op_list (op_list , qubits_of_clifford )
70+ actual_unitary = cirq .unitary (conjugation .dense (qubits_of_clifford ))
71+ c = cirq .unitary (clifford )
72+ expected_unitary = np .conj (c .T ) @ cirq .unitary (input_ps .dense (qubits_of_clifford )) @ c
73+ assert np .allclose (actual_unitary , expected_unitary , atol = 1e-8 )
74+
75+
6076def test_eq_ne_hash ():
6177 q0 , q1 , q2 = _make_qubits (3 )
6278 eq = cirq .testing .EqualsTester ()
@@ -1381,13 +1397,24 @@ def test_pauli_string_expectation_from_state_vector_mixed_state_linearity():
13811397def test_conjugated_by_normal_gates ():
13821398 a = cirq .LineQubit (0 )
13831399
1384- assert cirq .X (a ).conjugated_by (cirq .H (a )) == cirq .Z (a )
1385- assert cirq .Y (a ).conjugated_by (cirq .H (a )) == - cirq .Y (a )
1386- assert cirq .Z (a ).conjugated_by (cirq .H (a )) == cirq .X (a )
1400+ assert_conjugation (cirq .X (a ), cirq .H (a ), cirq .Z (a ))
1401+ assert_conjugation (cirq .Y (a ), cirq .H (a ), - cirq .Y (a ))
1402+ assert_conjugation (cirq .Z (a ), cirq .H (a ), cirq .X (a ))
1403+
1404+ assert_conjugation (cirq .X (a ), cirq .S (a ), - cirq .Y (a ))
1405+ assert_conjugation (cirq .Y (a ), cirq .S (a ), cirq .X (a ))
1406+ assert_conjugation (cirq .Z (a ), cirq .S (a ), cirq .Z (a ))
1407+
1408+ clifford_op = cirq .PhasedXZGate (axis_phase_exponent = 0.25 , x_exponent = - 1 , z_exponent = 0 ).on (a )
1409+ assert_conjugation (cirq .X (a ), clifford_op , cirq .Y (a ))
1410+ assert_conjugation (cirq .Y (a ), clifford_op , cirq .X (a ))
1411+ assert_conjugation (cirq .Z (a ), clifford_op , - cirq .Z (a ))
1412+
1413+
1414+ def test_conjugated_by_op_gate_of_clifford_gate_type ():
1415+ a = cirq .LineQubit (0 )
13871416
1388- assert cirq .X (a ).conjugated_by (cirq .S (a )) == - cirq .Y (a )
1389- assert cirq .Y (a ).conjugated_by (cirq .S (a )) == cirq .X (a )
1390- assert cirq .Z (a ).conjugated_by (cirq .S (a )) == cirq .Z (a )
1417+ assert_conjugation (cirq .X (a ), cirq .CliffordGate .from_op_list ([cirq .H (a )], [a ]).on (a ), cirq .Z (a ))
13911418
13921419
13931420def test_dense ():
@@ -1430,16 +1457,25 @@ def test_conjugated_by_incorrectly_powered_cliffords():
14301457 cirq .ZZ (a , b ),
14311458 ]
14321459 for c in cliffords :
1433- with pytest .raises (TypeError , match = 'not a known Clifford' ):
1460+ with pytest .raises (
1461+ ValueError ,
1462+ match = 'Clifford Gate can only be constructed from the operations'
1463+ ' that has stabilizer effect.' ,
1464+ ):
14341465 _ = p .conjugated_by (c ** 0.1 )
1435- with pytest .raises (TypeError , match = 'not a known Clifford' ):
1466+ with pytest .raises (
1467+ ValueError ,
1468+ match = 'Clifford Gate can only be constructed from the operations'
1469+ ' that has stabilizer effect.' ,
1470+ ):
14361471 _ = p .conjugated_by (c ** sympy .Symbol ('t' ))
14371472
14381473
14391474def test_conjugated_by_global_phase ():
1475+ """Global phase gate preserves PauliString."""
14401476 a = cirq .LineQubit (0 )
1441- assert cirq .X (a ). conjugated_by ( cirq .global_phase_operation (1j )) == cirq .X (a )
1442- assert cirq .Z (a ). conjugated_by ( cirq .global_phase_operation (np .exp (1.1j ))) == cirq .Z ( a )
1477+ assert_conjugation ( cirq .X (a ), cirq .global_phase_operation (1j ), cirq .X (a ) )
1478+ assert_conjugation ( cirq .X (a ), cirq .global_phase_operation (np .exp (1.1j )), cirq .X ( a ) )
14431479
14441480 class DecomposeGlobal (cirq .Gate ):
14451481 def num_qubits (self ):
@@ -1448,7 +1484,7 @@ def num_qubits(self):
14481484 def _decompose_ (self , qubits ):
14491485 yield cirq .global_phase_operation (1j )
14501486
1451- assert cirq .X (a ). conjugated_by ( DecomposeGlobal ().on (a )) == cirq .X (a )
1487+ assert_conjugation ( cirq .X (a ), DecomposeGlobal ().on (a ), cirq .X (a ) )
14521488
14531489
14541490def test_conjugated_by_composite_with_disjoint_sub_gates ():
@@ -1461,8 +1497,10 @@ def num_qubits(self):
14611497 def _decompose_ (self , qubits ):
14621498 yield cirq .H (qubits [1 ])
14631499
1464- assert cirq .X (a ).conjugated_by (DecomposeDisjoint ().on (a , b )) == cirq .X (a )
1465- assert cirq .X (a ).pass_operations_over ([DecomposeDisjoint ().on (a , b )]) == cirq .X (a )
1500+ for g1 in [cirq .X , cirq .Y ]:
1501+ for g2 in [cirq .X , cirq .Y ]:
1502+ ps = g1 (a ) * g2 (b )
1503+ assert ps .conjugated_by (DecomposeDisjoint ().on (a , b )) == ps .conjugated_by (cirq .H (b ))
14661504
14671505
14681506def test_conjugated_by_clifford_composite ():
@@ -1477,16 +1515,16 @@ def _decompose_(self, qubits):
14771515 yield cirq .SWAP (qubits [2 ], qubits [3 ])
14781516
14791517 a , b , c , d = cirq .LineQubit .range (4 )
1480- p = cirq .X (a ) * cirq .Z (b )
1518+ ps = cirq .X (a ) * cirq .Z (b )
14811519 u = UnknownGate ()
1482- assert p . conjugated_by ( u (a , b , c , d )) == cirq .Z (a ) * cirq .X (b )
1520+ assert_conjugation ( ps , u (a , b , c , d ), cirq .Z (a ) * cirq .X (b ) )
14831521
14841522
14851523def test_conjugated_by_move_into_uninvolved ():
14861524 a , b , c , d = cirq .LineQubit .range (4 )
1487- p = cirq .X (a ) * cirq .Z (b )
1488- assert p . conjugated_by ( [cirq .SWAP (c , d ), cirq .SWAP (b , c )]) == cirq .X (a ) * cirq .Z (d )
1489- assert p . conjugated_by ( [cirq .SWAP (b , c ), cirq .SWAP (c , d )]) == cirq .X (a ) * cirq .Z (c )
1525+ ps = cirq .X (a ) * cirq .Z (b )
1526+ assert_conjugation ( ps , [cirq .SWAP (c , d ), cirq .SWAP (b , c )], cirq .X (a ) * cirq .Z (d ) )
1527+ assert_conjugation ( ps , [cirq .SWAP (b , c ), cirq .SWAP (c , d )], cirq .X (a ) * cirq .Z (c ) )
14901528
14911529
14921530def test_conjugated_by_common_single_qubit_gates ():
@@ -1508,21 +1546,13 @@ def test_conjugated_by_common_single_qubit_gates():
15081546 single_qubit_gates = [g ** i for i in range (4 ) for g in base_single_qubit_gates ]
15091547 for p in [cirq .X , cirq .Y , cirq .Z ]:
15101548 for g in single_qubit_gates :
1511- assert p .on (a ).conjugated_by (g .on (b )) == p .on (a )
1512-
1513- actual = cirq .unitary (p .on (a ).conjugated_by (g .on (a )))
1514- u = cirq .unitary (g )
1515- expected = np .conj (u .T ) @ cirq .unitary (p ) @ u
1516- assert cirq .allclose_up_to_global_phase (actual , expected , atol = 1e-8 )
1549+ # pauli gate on a, clifford on b: pauli gate preserves.
1550+ assert_conjugation (p (a ), g (b ), p (a ))
1551+ # pauli gate on a, clifford on a: check conjugation in matrices.
1552+ assert_conjugation (p (a ), g (a ), None )
15171553
15181554
15191555def test_conjugated_by_common_two_qubit_gates ():
1520- class OrderSensitiveGate (cirq .Gate ):
1521- def num_qubits (self ):
1522- return 2
1523-
1524- def _decompose_ (self , qubits ):
1525- return [cirq .Y (qubits [0 ]) ** - 0.5 , cirq .CNOT (* qubits )]
15261556
15271557 a , b , c , d = cirq .LineQubit .range (4 )
15281558 two_qubit_gates = [
@@ -1541,34 +1571,25 @@ def _decompose_(self, qubits):
15411571 cirq .YY ** - 0.5 ,
15421572 cirq .ZZ ** - 0.5 ,
15431573 ]
1544- two_qubit_gates .extend ([OrderSensitiveGate ()])
15451574 for p1 in [cirq .I , cirq .X , cirq .Y , cirq .Z ]:
15461575 for p2 in [cirq .I , cirq .X , cirq .Y , cirq .Z ]:
15471576 pd = cirq .DensePauliString ([p1 , p2 ])
1548- p = pd .sparse ()
1577+ p = pd .sparse ([ a , b ] )
15491578 for g in two_qubit_gates :
1550- assert p .conjugated_by (g .on (c , d )) == p
1551-
1552- actual = cirq .unitary (p .conjugated_by (g .on (a , b )).dense ([a , b ]))
1553- u = cirq .unitary (g )
1554- expected = np .conj (u .T ) @ cirq .unitary (pd ) @ u
1555- np .testing .assert_allclose (actual , expected , atol = 1e-8 )
1579+ # pauli_string on (a,b), clifford on (c,d): pauli_string preserves.
1580+ assert_conjugation (p , g (c , d ), p )
1581+ # pauli_string on (a,b), clifford on (a,b): compare unitaries of
1582+ # the conjugated_by and actual matrix conjugation.
1583+ assert_conjugation (p , g .on (a , b ), None )
15561584
15571585
15581586def test_conjugated_by_ordering ():
1559- class OrderSensitiveGate (cirq .Gate ):
1560- def num_qubits (self ):
1561- return 2
1562-
1563- def _decompose_ (self , qubits ):
1564- return [cirq .Y (qubits [0 ]) ** - 0.5 , cirq .CNOT (* qubits )]
1565-
1587+ """Tests .conjugated_by([op1, op2]) == .conjugated_by(op2).conjugated_by(op1)"""
15661588 a , b = cirq .LineQubit .range (2 )
15671589 inp = cirq .Z (b )
1568- out1 = inp .conjugated_by (OrderSensitiveGate ().on (a , b ))
1569- out2 = inp .conjugated_by ([cirq .H (a ), cirq .CNOT (a , b )])
1570- out3 = inp .conjugated_by (cirq .CNOT (a , b )).conjugated_by (cirq .H (a ))
1571- assert out1 == out2 == out3 == cirq .X (a ) * cirq .Z (b )
1590+ out1 = inp .conjugated_by ([cirq .H (a ), cirq .CNOT (a , b )])
1591+ out2 = inp .conjugated_by (cirq .CNOT (a , b )).conjugated_by (cirq .H (a ))
1592+ assert out1 == out2 == cirq .X (a ) * cirq .Z (b )
15721593
15731594
15741595def test_pass_operations_over_ordering ():
0 commit comments