diff --git a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py index 8c928a47f69..85b0c05d5ca 100644 --- a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py +++ b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py @@ -42,6 +42,7 @@ CommutativeCancellation, ConsolidateBlocks, InverseCancellation, + RemoveIdentityEquivalent, ) from qiskit.transpiler.passes import Depth, Size, FixedPoint, MinimumPoint from qiskit.transpiler.passes.utils.gates_basis import GatesInBasis @@ -156,6 +157,13 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana if pass_manager_config.routing_method != "none": init.append(ElidePermutations()) init.append(RemoveDiagonalGatesBeforeMeasure()) + # Target not set on RemoveIdentityEquivalent because we haven't applied a Layout + # yet so doing anything relative to an error rate in the target is not valid. + init.append( + RemoveIdentityEquivalent( + approximation_degree=pass_manager_config.approximation_degree + ) + ) init.append( InverseCancellation( [ @@ -580,6 +588,10 @@ def _opt_control(property_set): elif optimization_level == 2: _opt = [ + RemoveIdentityEquivalent( + approximation_degree=pass_manager_config.approximation_degree, + target=pass_manager_config.target, + ), Optimize1qGatesDecomposition( basis=pass_manager_config.basis_gates, target=pass_manager_config.target ), @@ -602,6 +614,10 @@ def _opt_control(property_set): plugin_config=pass_manager_config.unitary_synthesis_plugin_config, target=pass_manager_config.target, ), + RemoveIdentityEquivalent( + approximation_degree=pass_manager_config.approximation_degree, + target=pass_manager_config.target, + ), Optimize1qGatesDecomposition( basis=pass_manager_config.basis_gates, target=pass_manager_config.target ), diff --git a/releasenotes/notes/add-identity-pass-builtin-2061b29b53b928d3.yaml b/releasenotes/notes/add-identity-pass-builtin-2061b29b53b928d3.yaml new file mode 100644 index 00000000000..0cf3d503aee --- /dev/null +++ b/releasenotes/notes/add-identity-pass-builtin-2061b29b53b928d3.yaml @@ -0,0 +1,8 @@ +--- +features_transpiler: + - | + The :class:`.RemoveIdentityEquivalent` transpiler pass is now run as part + of the preset pass managers at optimization levels 2 and 3. The pass is + run in the ``init`` stage and the ``optimization`` stage, because the + optimizations it applies are valid in both stages and the pass is + fast to execute. diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index 851117671ef..851c6817d82 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -1796,21 +1796,29 @@ def test_no_infinite_loop(self, optimization_level): seed_transpiler=42, ) - # Expect a -pi/2 global phase for the U3 to RZ/SX conversion, and - # a -0.5 * theta phase for RZ to P twice, once at theta, and once at 3 pi - # for the second and third RZ gates in the U3 decomposition. - expected = QuantumCircuit( - 1, global_phase=-np.pi / 2 - 0.5 * (-0.2 + np.pi) - 0.5 * 3 * np.pi - ) - expected.p(-np.pi, 0) - expected.sx(0) - expected.p(np.pi - 0.2, 0) - expected.sx(0) + if optimization_level == 1: + # Expect a -pi/2 global phase for the U3 to RZ/SX conversion, and + # a -0.5 * theta phase for RZ to P twice, once at theta, and once at 3 pi + # for the second and third RZ gates in the U3 decomposition. + expected = QuantumCircuit( + 1, global_phase=-np.pi / 2 - 0.5 * (-0.2 + np.pi) - 0.5 * 3 * np.pi + ) + expected.p(-np.pi, 0) + expected.sx(0) + expected.p(np.pi - 0.2, 0) + expected.sx(0) + else: + expected = QuantumCircuit(1, global_phase=(15 * np.pi - 1) / 10) + expected.sx(0) + expected.p(1.0 / 5.0 + np.pi, 0) + expected.sx(0) + expected.p(3 * np.pi, 0) error_message = ( f"\nOutput circuit:\n{out!s}\n{Operator(out).data}\n" f"Expected circuit:\n{expected!s}\n{Operator(expected).data}" ) + self.assertEqual(Operator(qc), Operator(out)) self.assertEqual(out, expected, error_message) @data(0, 1, 2, 3)