@@ -534,10 +534,11 @@ def test_pauli_based_gates(self, gate_type):
534534 for p1 , q1 , p2 , q2 , expected in cases :
535535 if p1 == "I" and gate_type == "measure" :
536536 continue # PPM doesn't support all-identity gates
537+ c1 , c2 = ([0 ], [1 ]) if gate_type == "measure" else ([], [])
537538
538539 gate1 = build_pauli_gate (p1 , gate_type )
539540 gate2 = build_pauli_gate (p2 , gate_type )
540- self .assertEqual (expected , scc .commute (gate1 , q1 , [] , gate2 , q2 , [] ))
541+ self .assertEqual (expected , scc .commute (gate1 , q1 , c1 , gate2 , q2 , c2 ))
541542
542543 @data (
543544 ("pauli" , "measure" ),
@@ -553,10 +554,45 @@ def test_mix_pauli_gates(self, gate_type1, gate_type2):
553554 ]
554555
555556 for p1 , q1 , p2 , q2 , expected in cases :
557+ c1 = [0 ] if gate_type1 == "measure" else []
558+ c2 = [1 ] if gate_type2 == "measure" else []
559+
556560 gate1 = build_pauli_gate (p1 , gate_type1 )
557561 gate2 = build_pauli_gate (p2 , gate_type2 )
562+
558563 with self .subTest (p1 = p1 , p2 = p2 ):
559- self .assertEqual (expected , scc .commute (gate1 , q1 , [], gate2 , q2 , []))
564+ self .assertEqual (expected , scc .commute (gate1 , q1 , c1 , gate2 , q2 , c2 ))
565+
566+ def test_ppms_with_same_clbit (self ):
567+ """Test commutativity of two Pauli product measurements with the same clbit."""
568+
569+ # Each case represents (pauli1, qubits1, pauli2, qubits2, expected result).
570+ # Recall that the convention is that pauli strings are read right-to-left, i.e.
571+ # pauli strings and qubits are in reverse order relative to each other.
572+ cases = [
573+ # different Paulis
574+ ("XXII" , [1 , 0 , 2 , 3 ], "IIZZ" , [1 , 0 , 2 , 3 ], False ),
575+ # different qubits
576+ ("XYIZ" , [1 , 0 , 2 , 3 ], "XYIZ" , [1 , 0 , 4 , 3 ], False ),
577+ # different Paulis (including sign)
578+ ("ZXII" , [1 , 0 , 2 , 3 ], "-ZXII" , [1 , 0 , 2 , 3 ], False ),
579+ # same Paulis and qubits
580+ ("XYIZ" , [1 , 0 , 2 , 3 ], "XYIZ" , [1 , 0 , 2 , 3 ], True ),
581+ # same Paulis and qubits
582+ ("-XYIZ" , [1 , 0 , 2 , 3 ], "-XYIZ" , [1 , 0 , 2 , 3 ], True ),
583+ # same Paulis and qubits up to reordering
584+ ("XXIY" , [0 , 1 , 2 , 3 ], "YIXX" , [3 , 2 , 1 , 0 ], True ),
585+ # same Paulis and qubits up to reordering
586+ ("XXIY" , [0 , 1 , 2 , 3 ], "XXIY" , [0 , 1 , 3 , 2 ], True ),
587+ # same Paulis and qubits up to reordering
588+ ("-XXIY" , [0 , 1 , 2 , 3 ], "-YIXX" , [2 , 3 , 1 , 0 ], True ),
589+ ]
590+
591+ for pauli1 , qubits1 , pauli2 , qubits2 , expected in cases :
592+ with self .subTest (pauli1 = pauli1 , qubits1 = qubits1 , pauli2 = pauli2 , qubits2 = qubits2 ):
593+ ppm1 = build_pauli_gate (pauli1 , "measure" )
594+ ppm2 = build_pauli_gate (pauli2 , "measure" )
595+ self .assertEqual (scc .commute (ppm1 , qubits1 , [0 ], ppm2 , qubits2 , [0 ]), expected )
560596
561597 def test_pauli_evolution_sums (self ):
562598 """Test PauliEvolutionGate commutations for operators that are sums of Paulis."""
@@ -589,6 +625,42 @@ def test_pauli_evolution_parameterized(self):
589625 with self .subTest (left = z , right = x ):
590626 self .assertFalse (scc .commute (z , qargs , [], x , qargs , []))
591627
628+ < << << << HEAD
629+ == == == =
630+ @data ("evolution" , "pauli" , "measure" , "rotation" )
631+ def test_pauli_and_standard_gate (self , pauli_type ):
632+ """Test Pauli-based gates and standard gate commutations are efficiently supported."""
633+ # 40-qubit Pauli gate with following terms: X: 0-9, Y: 10-19, Z: 20-29, I: 30-39
634+ pauli = 10 * "I" + 10 * "Z" + 10 * "Y" + 10 * "X"
635+ pauli_qubits = list (range (len (pauli )))
636+ pauli_clbits = [0 ] if pauli_type == "measure" else []
637+ pauli_gate = build_pauli_gate (pauli , pauli_type )
638+
639+ # Test cases in the format: (gate, indices, commutes)
640+ x = Parameter ("x" )
641+ cases = [
642+ (CXGate (), [30 , 0 ], True ), # CX vs. IX
643+ (CXGate (), [29 , 0 ], True ), # CX vs. ZX
644+ (CXGate (), [29 , 10 ], False ), # CX vs. ZY
645+ (RXXGate (x ), [0 , 1 ], True ),
646+ (RXXGate (1.2 ), [11 , 15 ], True ),
647+ (RXXGate (x ), [0 , 15 ], False ),
648+ (HGate (), [33 ], True ),
649+ (HGate (), [2 ], False ),
650+ (CPhaseGate (0.1 ), [30 , 31 ], True ),
651+ (CPhaseGate (0.1 ), [2 , 3 ], False ),
652+ (XXPlusYYGate (1 , 1 ), [0 , 1 ], False ),
653+ (XXPlusYYGate (1 , 0 ), [0 , 1 ], True ),
654+ ]
655+
656+ for std_gate , indices , expected in cases :
657+ with self .subTest (std_gate = std_gate , indices = indices ):
658+ commutes = scc .commute (
659+ pauli_gate , pauli_qubits , pauli_clbits , std_gate , indices , []
660+ )
661+ self .assertEqual (expected , commutes )
662+
663+ >> >> >> > 89 ff976e0 (Fixed commutation checking between two Pauli product measurements (#16023))
592664
593665def build_pauli_gate (pauli_string : str , gate_type : str ) - > Gate :
594666 """Build a Pauli-based gate off a Pauli string.
0 commit comments