diff --git a/qiskit/transpiler/passes/optimization/inverse_cancellation.py b/qiskit/transpiler/passes/optimization/inverse_cancellation.py index bb9552b3aa19..c814f50d4a18 100644 --- a/qiskit/transpiler/passes/optimization/inverse_cancellation.py +++ b/qiskit/transpiler/passes/optimization/inverse_cancellation.py @@ -111,7 +111,8 @@ def _run_on_self_inverse(self, dag: DAGCircuit): for gate_cancel_run in gate_runs: partitions = [] chunk = [] - for i in range(len(gate_cancel_run) - 1): + max_index = len(gate_cancel_run) - 1 + for i in range(len(gate_cancel_run)): if gate_cancel_run[i].op == gate: chunk.append(gate_cancel_run[i]) else: @@ -119,11 +120,9 @@ def _run_on_self_inverse(self, dag: DAGCircuit): partitions.append(chunk) chunk = [] continue - if gate_cancel_run[i].qargs != gate_cancel_run[i + 1].qargs: + if i == max_index or gate_cancel_run[i].qargs != gate_cancel_run[i + 1].qargs: partitions.append(chunk) chunk = [] - chunk.append(gate_cancel_run[-1]) - partitions.append(chunk) # Remove an even number of gates from each chunk for chunk in partitions: if len(chunk) % 2 == 0: diff --git a/releasenotes/notes/fix-inverse-cancellation-self-inverse-e09a5553331e1b0b.yaml b/releasenotes/notes/fix-inverse-cancellation-self-inverse-e09a5553331e1b0b.yaml new file mode 100644 index 000000000000..dde704c26931 --- /dev/null +++ b/releasenotes/notes/fix-inverse-cancellation-self-inverse-e09a5553331e1b0b.yaml @@ -0,0 +1,8 @@ +--- + +fixes: + - | + Fixed an issue in the :class:`.InverseCancellation` transpiler pass where in some cases it + would incorrectly cancel a self-inverse parameterized gate even if the parameter value + didn't match. + Fixed `#11815 `__ \ No newline at end of file diff --git a/test/python/transpiler/test_inverse_cancellation.py b/test/python/transpiler/test_inverse_cancellation.py index 7c210bd92682..64d7812888b3 100644 --- a/test/python/transpiler/test_inverse_cancellation.py +++ b/test/python/transpiler/test_inverse_cancellation.py @@ -358,8 +358,10 @@ def test_parameterized_self_inverse(self): new_circ = inverse_pass(qc) self.assertEqual(new_circ, QuantumCircuit(1)) - def test_parameterized_self_inverse_not_equal_parameter(self): - """Test that a parameterized self inverse gate doesn't cancel incorrectly.""" + def test_parameterized_self_inverse_not_equal_parameter_1(self): + """Test that a parameterized self inverse gate doesn't cancel incorrectly. + This test, checks three gates with the same name but the middle one has a + different parameter.""" qc = QuantumCircuit(1) qc.rz(0, 0) qc.rz(3.14159, 0) @@ -368,6 +370,16 @@ def test_parameterized_self_inverse_not_equal_parameter(self): new_circ = inverse_pass(qc) self.assertEqual(new_circ, qc) + def test_parameterized_self_inverse_not_equal_parameter_2(self): + """Test that a parameterized self inverse gate doesn't cancel incorrectly. + This test, checks two gates with the same name but different parameters.""" + qc = QuantumCircuit(1) + qc.rz(0, 0) + qc.rz(3.14159, 0) + inverse_pass = InverseCancellation([RZGate(0)]) + new_circ = inverse_pass(qc) + self.assertEqual(qc, new_circ) + def test_controlled_gate_open_control_does_not_cancel(self): """Test that a controlled gate with an open control doesn't cancel.""" qc = QuantumCircuit(2)