Skip to content

Commit a24470f

Browse files
authored
Add identity removal pass to presets (#13363)
* Add identity removal pass to presets This commit adds the newly added RemoveIdentityEquivalent transpiler pass to the preset pass managers for optimization levels 2 and 3. The pass is added to the init and optimization stages. For the init stage the pass is run after 3 or more qubit decomposition. While the pass works fine with 3 qubit gates, the thinking behind this placement was it seems less likely for a multi qubit identity equivalent gate to be added while components of it's decomposition are more likely to be equivalent to an identity. For the optimization stage it is added to the optimization loop. One test needed to be updated because the additional pass changes the decomposition outcome in that test. Although the output circuit is different it is equivalent to the other decomposition and the original circuit. A unitary equivalence check is added to the test to verify that. * Fix lint
1 parent 50217b6 commit a24470f

3 files changed

Lines changed: 42 additions & 10 deletions

File tree

qiskit/transpiler/preset_passmanagers/builtin_plugins.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
CommutativeCancellation,
4343
ConsolidateBlocks,
4444
InverseCancellation,
45+
RemoveIdentityEquivalent,
4546
)
4647
from qiskit.transpiler.passes import Depth, Size, FixedPoint, MinimumPoint
4748
from qiskit.transpiler.passes.utils.gates_basis import GatesInBasis
@@ -156,6 +157,13 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana
156157
if pass_manager_config.routing_method != "none":
157158
init.append(ElidePermutations())
158159
init.append(RemoveDiagonalGatesBeforeMeasure())
160+
# Target not set on RemoveIdentityEquivalent because we haven't applied a Layout
161+
# yet so doing anything relative to an error rate in the target is not valid.
162+
init.append(
163+
RemoveIdentityEquivalent(
164+
approximation_degree=pass_manager_config.approximation_degree
165+
)
166+
)
159167
init.append(
160168
InverseCancellation(
161169
[
@@ -580,6 +588,10 @@ def _opt_control(property_set):
580588

581589
elif optimization_level == 2:
582590
_opt = [
591+
RemoveIdentityEquivalent(
592+
approximation_degree=pass_manager_config.approximation_degree,
593+
target=pass_manager_config.target,
594+
),
583595
Optimize1qGatesDecomposition(
584596
basis=pass_manager_config.basis_gates, target=pass_manager_config.target
585597
),
@@ -602,6 +614,10 @@ def _opt_control(property_set):
602614
plugin_config=pass_manager_config.unitary_synthesis_plugin_config,
603615
target=pass_manager_config.target,
604616
),
617+
RemoveIdentityEquivalent(
618+
approximation_degree=pass_manager_config.approximation_degree,
619+
target=pass_manager_config.target,
620+
),
605621
Optimize1qGatesDecomposition(
606622
basis=pass_manager_config.basis_gates, target=pass_manager_config.target
607623
),
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
features_transpiler:
3+
- |
4+
The :class:`.RemoveIdentityEquivalent` transpiler pass is now run as part
5+
of the preset pass managers at optimization levels 2 and 3. The pass is
6+
run in the ``init`` stage and the ``optimization`` stage, because the
7+
optimizations it applies are valid in both stages and the pass is
8+
fast to execute.

test/python/compiler/test_transpiler.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,21 +1796,29 @@ def test_no_infinite_loop(self, optimization_level):
17961796
seed_transpiler=42,
17971797
)
17981798

1799-
# Expect a -pi/2 global phase for the U3 to RZ/SX conversion, and
1800-
# a -0.5 * theta phase for RZ to P twice, once at theta, and once at 3 pi
1801-
# for the second and third RZ gates in the U3 decomposition.
1802-
expected = QuantumCircuit(
1803-
1, global_phase=-np.pi / 2 - 0.5 * (-0.2 + np.pi) - 0.5 * 3 * np.pi
1804-
)
1805-
expected.p(-np.pi, 0)
1806-
expected.sx(0)
1807-
expected.p(np.pi - 0.2, 0)
1808-
expected.sx(0)
1799+
if optimization_level == 1:
1800+
# Expect a -pi/2 global phase for the U3 to RZ/SX conversion, and
1801+
# a -0.5 * theta phase for RZ to P twice, once at theta, and once at 3 pi
1802+
# for the second and third RZ gates in the U3 decomposition.
1803+
expected = QuantumCircuit(
1804+
1, global_phase=-np.pi / 2 - 0.5 * (-0.2 + np.pi) - 0.5 * 3 * np.pi
1805+
)
1806+
expected.p(-np.pi, 0)
1807+
expected.sx(0)
1808+
expected.p(np.pi - 0.2, 0)
1809+
expected.sx(0)
1810+
else:
1811+
expected = QuantumCircuit(1, global_phase=(15 * np.pi - 1) / 10)
1812+
expected.sx(0)
1813+
expected.p(1.0 / 5.0 + np.pi, 0)
1814+
expected.sx(0)
1815+
expected.p(3 * np.pi, 0)
18091816

18101817
error_message = (
18111818
f"\nOutput circuit:\n{out!s}\n{Operator(out).data}\n"
18121819
f"Expected circuit:\n{expected!s}\n{Operator(expected).data}"
18131820
)
1821+
self.assertEqual(Operator(qc), Operator(out))
18141822
self.assertEqual(out, expected, error_message)
18151823

18161824
@data(0, 1, 2, 3)

0 commit comments

Comments
 (0)