@@ -58,19 +58,53 @@ def _small_sample_qubit_pauli_maps():
58
58
59
59
60
60
def assert_conjugation (
61
- input_ps : cirq .PauliString , ops : cirq .OP_TREE , expected : cirq .PauliString | None
61
+ input_ps : cirq .PauliString ,
62
+ op : cirq .Operation ,
63
+ expected : cirq .PauliString | None = None ,
64
+ force_checking_unitary = True ,
65
+ ):
66
+ """Verifies that conjugating `input_ps` by `op` results in `expected`.
67
+
68
+ Also ensures that the unitary representation of the Pauli string is
69
+ preserved under the conjugation.
70
+ """
71
+
72
+ def _ps_on_qubits (ps : cirq .PauliString , qubits : tuple [cirq .Qid , ...]):
73
+ """Extracts a sub-PauliString from a given PauliString, restricted to
74
+ a specified subset of qubits.
75
+ """
76
+ pauli_map = {}
77
+ for q , pauli in ps .items ():
78
+ if q in qubits :
79
+ pauli_map [q ] = pauli
80
+ return cirq .PauliString (qubit_pauli_map = pauli_map , coefficient = ps .coefficient )
81
+
82
+ conjugation = input_ps .conjugated_by (op )
83
+ if expected is None or force_checking_unitary :
84
+ # Compares the unitary of the conjugation result and the expected unitary.
85
+ clifford = cirq .CliffordGate .from_op_list ([op ], op .qubits )
86
+ actual_unitary = cirq .unitary (_ps_on_qubits (conjugation , op .qubits ).dense (op .qubits ))
87
+ c = cirq .unitary (clifford )
88
+ expected_unitary = (
89
+ np .conj (c .T ) @ cirq .unitary (_ps_on_qubits (input_ps , op .qubits ).dense (op .qubits )) @ c
90
+ )
91
+ assert np .allclose (actual_unitary , expected_unitary , atol = 1e-8 )
92
+ if expected is not None :
93
+ assert conjugation == expected
94
+
95
+
96
+ def assert_conjugation_multi_ops (
97
+ input_ps : cirq .PauliString , ops : list [cirq .Operation ], expected : cirq .PauliString | None = None
62
98
):
63
99
conjugation = input_ps .conjugated_by (ops )
64
100
if expected is not None :
65
101
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 )
102
+ # conj_by(op_{n-1}).conj_by(op_{n-1}).....conj_by(op_0)
103
+ conj_in_order = input_ps
104
+ for op in ops [::- 1 ]:
105
+ assert_conjugation (conj_in_order , op )
106
+ conj_in_order = conj_in_order .conjugated_by (op )
107
+ assert conjugation == conj_in_order
74
108
75
109
76
110
def test_eq_ne_hash ():
@@ -741,26 +775,31 @@ def test_pass_operations_over_double(shift: int, t_or_f1: bool, t_or_f2: bool, n
741
775
op0 = cirq .PauliInteractionGate (Z , t_or_f1 , X , t_or_f2 )(q0 , q1 )
742
776
ps_before = cirq .PauliString (qubit_pauli_map = {q0 : Z , q2 : Y }, coefficient = sign )
743
777
ps_after = cirq .PauliString (qubit_pauli_map = {q0 : Z , q2 : Y }, coefficient = sign )
778
+ assert_conjugation (ps_before , op0 , ps_after , True )
744
779
_assert_pass_over ([op0 ], ps_before , ps_after )
745
780
746
781
op0 = cirq .PauliInteractionGate (Y , t_or_f1 , X , t_or_f2 )(q0 , q1 )
747
782
ps_before = cirq .PauliString ({q0 : Z , q2 : Y }, sign )
748
- ps_after = cirq .PauliString ({q0 : Z , q2 : Y , q1 : X }, sign )
783
+ ps_after = cirq .PauliString ({q0 : Z , q2 : Y , q1 : X }, - sign if t_or_f2 else sign )
784
+ assert_conjugation (ps_before , op0 , ps_after , True )
749
785
_assert_pass_over ([op0 ], ps_before , ps_after )
750
786
751
787
op0 = cirq .PauliInteractionGate (Z , t_or_f1 , X , t_or_f2 )(q0 , q1 )
752
788
ps_before = cirq .PauliString ({q0 : Z , q1 : Y }, sign )
753
- ps_after = cirq .PauliString ({q1 : Y }, sign )
789
+ ps_after = cirq .PauliString ({q1 : Y }, - sign if t_or_f1 else sign )
790
+ assert_conjugation (ps_before , op0 , ps_after , True )
754
791
_assert_pass_over ([op0 ], ps_before , ps_after )
755
792
756
793
op0 = cirq .PauliInteractionGate (Y , t_or_f1 , X , t_or_f2 )(q0 , q1 )
757
794
ps_before = cirq .PauliString ({q0 : Z , q1 : Y }, sign )
758
795
ps_after = cirq .PauliString ({q0 : X , q1 : Z }, - 1 if neg ^ t_or_f1 ^ t_or_f2 else + 1 )
796
+ assert_conjugation (ps_before , op0 , ps_after , True )
759
797
_assert_pass_over ([op0 ], ps_before , ps_after )
760
798
761
799
op0 = cirq .PauliInteractionGate (X , t_or_f1 , X , t_or_f2 )(q0 , q1 )
762
800
ps_before = cirq .PauliString ({q0 : Z , q1 : Y }, sign )
763
801
ps_after = cirq .PauliString ({q0 : Y , q1 : Z }, + 1 if neg ^ t_or_f1 ^ t_or_f2 else - 1 )
802
+ assert_conjugation (ps_before , op0 , ps_after , True )
764
803
_assert_pass_over ([op0 ], ps_before , ps_after )
765
804
766
805
@@ -774,7 +813,12 @@ def test_pass_operations_over_cz():
774
813
775
814
def test_pass_operations_over_no_common_qubits ():
776
815
class ExampleGate (cirq .testing .SingleQubitGate ):
777
- pass
816
+
817
+ def num_qubits (self ):
818
+ return 1
819
+
820
+ def _decompose_ (self , qubits ):
821
+ return cirq .X (qubits [0 ])
778
822
779
823
q0 , q1 = _make_qubits (2 )
780
824
op0 = ExampleGate ()(q1 )
@@ -786,7 +830,11 @@ class ExampleGate(cirq.testing.SingleQubitGate):
786
830
def test_pass_unsupported_operations_over ():
787
831
(q0 ,) = _make_qubits (1 )
788
832
pauli_string = cirq .PauliString ({q0 : cirq .X })
789
- with pytest .raises (TypeError , match = 'not a known Clifford' ):
833
+ with pytest .raises (
834
+ ValueError ,
835
+ match = 'Clifford Gate can only be constructed from the operations'
836
+ ' that has stabilizer effect.' ,
837
+ ):
790
838
pauli_string .pass_operations_over ([cirq .T (q0 )])
791
839
792
840
@@ -1523,8 +1571,8 @@ def _decompose_(self, qubits):
1523
1571
def test_conjugated_by_move_into_uninvolved ():
1524
1572
a , b , c , d = cirq .LineQubit .range (4 )
1525
1573
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 ))
1574
+ assert_conjugation_multi_ops (ps , [cirq .SWAP (c , d ), cirq .SWAP (b , c )], cirq .X (a ) * cirq .Z (d ))
1575
+ assert_conjugation_multi_ops (ps , [cirq .SWAP (b , c ), cirq .SWAP (c , d )], cirq .X (a ) * cirq .Z (c ))
1528
1576
1529
1577
1530
1578
def test_conjugated_by_common_single_qubit_gates ():
@@ -1549,7 +1597,7 @@ def test_conjugated_by_common_single_qubit_gates():
1549
1597
# pauli gate on a, clifford on b: pauli gate preserves.
1550
1598
assert_conjugation (p (a ), g (b ), p (a ))
1551
1599
# pauli gate on a, clifford on a: check conjugation in matrices.
1552
- assert_conjugation (p (a ), g (a ), None )
1600
+ assert_conjugation (p (a ), g (a ))
1553
1601
1554
1602
1555
1603
def test_conjugated_by_common_two_qubit_gates ():
@@ -1580,7 +1628,7 @@ def test_conjugated_by_common_two_qubit_gates():
1580
1628
assert_conjugation (p , g (c , d ), p )
1581
1629
# pauli_string on (a,b), clifford on (a,b): compare unitaries of
1582
1630
# the conjugated_by and actual matrix conjugation.
1583
- assert_conjugation (p , g .on (a , b ), None )
1631
+ assert_conjugation (p , g .on (a , b ))
1584
1632
1585
1633
1586
1634
def test_conjugated_by_ordering ():
0 commit comments