@@ -58,19 +58,47 @@ 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
+ def _ps_on_qubits (ps : cirq .PauliString , qubits : list [cirq .Qid ]):
67
+ """Gets a sub PauliString from the given PauliString on a subset of qubits
68
+ on the original PauliString and preserves the coefficient.
69
+ """
70
+ pauli_map = {}
71
+ for q , pauli in ps .items ():
72
+ if q in qubits :
73
+ pauli_map [q ] = pauli
74
+ return cirq .PauliString (qubit_pauli_map = pauli_map , coefficient = ps .coefficient )
75
+
76
+ conjugation = input_ps .conjugated_by (op )
77
+ if expected is None or force_checking_unitary :
78
+ # Compares the unitary of the conjugation result and the expected unitary.
79
+ clifford = cirq .CliffordGate .from_op_list ([op ], op .qubits )
80
+ actual_unitary = cirq .unitary (_ps_on_qubits (conjugation , op .qubits ).dense (op .qubits ))
81
+ c = cirq .unitary (clifford )
82
+ expected_unitary = (
83
+ np .conj (c .T ) @ cirq .unitary (_ps_on_qubits (input_ps , op .qubits ).dense (op .qubits )) @ c
84
+ )
85
+ assert np .allclose (actual_unitary , expected_unitary , atol = 1e-8 )
86
+ if expected is not None :
87
+ assert conjugation == expected
88
+
89
+
90
+ def assert_conjugation_multi_ops (
91
+ input_ps : cirq .PauliString , ops : list [cirq .Operation ], expected : cirq .PauliString | None = None
62
92
):
63
93
conjugation = input_ps .conjugated_by (ops )
64
94
if expected is not None :
65
95
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 )
96
+ # conj_by(op_{n-1}).conj_by(op_{n-1}).....conj_by(op_0)
97
+ conj_in_order = input_ps
98
+ for op in ops [::- 1 ]:
99
+ assert_conjugation (conj_in_order , op )
100
+ conj_in_order = conj_in_order .conjugated_by (op )
101
+ assert conjugation == conj_in_order
74
102
75
103
76
104
def test_eq_ne_hash ():
@@ -741,26 +769,31 @@ def test_pass_operations_over_double(shift: int, t_or_f1: bool, t_or_f2: bool, n
741
769
op0 = cirq .PauliInteractionGate (Z , t_or_f1 , X , t_or_f2 )(q0 , q1 )
742
770
ps_before = cirq .PauliString (qubit_pauli_map = {q0 : Z , q2 : Y }, coefficient = sign )
743
771
ps_after = cirq .PauliString (qubit_pauli_map = {q0 : Z , q2 : Y }, coefficient = sign )
772
+ assert_conjugation (ps_before , op0 , ps_after , True )
744
773
_assert_pass_over ([op0 ], ps_before , ps_after )
745
774
746
775
op0 = cirq .PauliInteractionGate (Y , t_or_f1 , X , t_or_f2 )(q0 , q1 )
747
776
ps_before = cirq .PauliString ({q0 : Z , q2 : Y }, sign )
748
- ps_after = cirq .PauliString ({q0 : Z , q2 : Y , q1 : X }, sign )
777
+ ps_after = cirq .PauliString ({q0 : Z , q2 : Y , q1 : X }, - sign if t_or_f2 else sign )
778
+ assert_conjugation (ps_before , op0 , ps_after , True )
749
779
_assert_pass_over ([op0 ], ps_before , ps_after )
750
780
751
781
op0 = cirq .PauliInteractionGate (Z , t_or_f1 , X , t_or_f2 )(q0 , q1 )
752
782
ps_before = cirq .PauliString ({q0 : Z , q1 : Y }, sign )
753
- ps_after = cirq .PauliString ({q1 : Y }, sign )
783
+ ps_after = cirq .PauliString ({q1 : Y }, - sign if t_or_f1 else sign )
784
+ assert_conjugation (ps_before , op0 , ps_after , True )
754
785
_assert_pass_over ([op0 ], ps_before , ps_after )
755
786
756
787
op0 = cirq .PauliInteractionGate (Y , t_or_f1 , X , t_or_f2 )(q0 , q1 )
757
788
ps_before = cirq .PauliString ({q0 : Z , q1 : Y }, sign )
758
789
ps_after = cirq .PauliString ({q0 : X , q1 : Z }, - 1 if neg ^ t_or_f1 ^ t_or_f2 else + 1 )
790
+ assert_conjugation (ps_before , op0 , ps_after , True )
759
791
_assert_pass_over ([op0 ], ps_before , ps_after )
760
792
761
793
op0 = cirq .PauliInteractionGate (X , t_or_f1 , X , t_or_f2 )(q0 , q1 )
762
794
ps_before = cirq .PauliString ({q0 : Z , q1 : Y }, sign )
763
795
ps_after = cirq .PauliString ({q0 : Y , q1 : Z }, + 1 if neg ^ t_or_f1 ^ t_or_f2 else - 1 )
796
+ assert_conjugation (ps_before , op0 , ps_after , True )
764
797
_assert_pass_over ([op0 ], ps_before , ps_after )
765
798
766
799
@@ -774,7 +807,12 @@ def test_pass_operations_over_cz():
774
807
775
808
def test_pass_operations_over_no_common_qubits ():
776
809
class ExampleGate (cirq .testing .SingleQubitGate ):
777
- pass
810
+
811
+ def num_qubits (self ):
812
+ return 1
813
+
814
+ def _decompose_ (self , qubits ):
815
+ return cirq .X (qubits [0 ])
778
816
779
817
q0 , q1 = _make_qubits (2 )
780
818
op0 = ExampleGate ()(q1 )
@@ -786,7 +824,11 @@ class ExampleGate(cirq.testing.SingleQubitGate):
786
824
def test_pass_unsupported_operations_over ():
787
825
(q0 ,) = _make_qubits (1 )
788
826
pauli_string = cirq .PauliString ({q0 : cirq .X })
789
- with pytest .raises (TypeError , match = 'not a known Clifford' ):
827
+ with pytest .raises (
828
+ ValueError ,
829
+ match = 'Clifford Gate can only be constructed from the operations'
830
+ ' that has stabilizer effect.' ,
831
+ ):
790
832
pauli_string .pass_operations_over ([cirq .T (q0 )])
791
833
792
834
@@ -1523,8 +1565,8 @@ def _decompose_(self, qubits):
1523
1565
def test_conjugated_by_move_into_uninvolved ():
1524
1566
a , b , c , d = cirq .LineQubit .range (4 )
1525
1567
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 ))
1568
+ assert_conjugation_multi_ops (ps , [cirq .SWAP (c , d ), cirq .SWAP (b , c )], cirq .X (a ) * cirq .Z (d ))
1569
+ assert_conjugation_multi_ops (ps , [cirq .SWAP (b , c ), cirq .SWAP (c , d )], cirq .X (a ) * cirq .Z (c ))
1528
1570
1529
1571
1530
1572
def test_conjugated_by_common_single_qubit_gates ():
@@ -1549,7 +1591,7 @@ def test_conjugated_by_common_single_qubit_gates():
1549
1591
# pauli gate on a, clifford on b: pauli gate preserves.
1550
1592
assert_conjugation (p (a ), g (b ), p (a ))
1551
1593
# pauli gate on a, clifford on a: check conjugation in matrices.
1552
- assert_conjugation (p (a ), g (a ), None )
1594
+ assert_conjugation (p (a ), g (a ))
1553
1595
1554
1596
1555
1597
def test_conjugated_by_common_two_qubit_gates ():
@@ -1580,7 +1622,7 @@ def test_conjugated_by_common_two_qubit_gates():
1580
1622
assert_conjugation (p , g (c , d ), p )
1581
1623
# pauli_string on (a,b), clifford on (a,b): compare unitaries of
1582
1624
# the conjugated_by and actual matrix conjugation.
1583
- assert_conjugation (p , g .on (a , b ), None )
1625
+ assert_conjugation (p , g .on (a , b ))
1584
1626
1585
1627
1586
1628
def test_conjugated_by_ordering ():
0 commit comments