Skip to content

Commit 360d625

Browse files
committed
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.
1 parent e89cb47 commit 360d625

3 files changed

Lines changed: 44 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
@@ -43,6 +43,7 @@
4343
Collect2qBlocks,
4444
ConsolidateBlocks,
4545
InverseCancellation,
46+
RemoveIdentityEquivalent,
4647
)
4748
from qiskit.transpiler.passes import Depth, Size, FixedPoint, MinimumPoint
4849
from qiskit.transpiler.passes.utils.gates_basis import GatesInBasis
@@ -157,6 +158,13 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana
157158
if pass_manager_config.routing_method != "none":
158159
init.append(ElidePermutations())
159160
init.append(RemoveDiagonalGatesBeforeMeasure())
161+
# Target not set on RemoveIdentityEquivalent because we haven't applied a Layout
162+
# yet so doing anything relative to an error rate in the target is not valid.
163+
init.append(
164+
RemoveIdentityEquivalent(
165+
approximation_degree=pass_manager_config.approximation_degree
166+
)
167+
)
160168
init.append(
161169
InverseCancellation(
162170
[
@@ -582,6 +590,10 @@ def _opt_control(property_set):
582590

583591
elif optimization_level == 2:
584592
_opt = [
593+
RemoveIdentityEquivalent(
594+
approximation_degree=pass_manager_config.approximation_degree,
595+
target=pass_manager_config.target,
596+
),
585597
Optimize1qGatesDecomposition(
586598
basis=pass_manager_config.basis_gates, target=pass_manager_config.target
587599
),
@@ -605,6 +617,10 @@ def _opt_control(property_set):
605617
plugin_config=pass_manager_config.unitary_synthesis_plugin_config,
606618
target=pass_manager_config.target,
607619
),
620+
RemoveIdentityEquivalent(
621+
approximation_degree=pass_manager_config.approximation_degree,
622+
target=pass_manager_config.target,
623+
),
608624
Optimize1qGatesDecomposition(
609625
basis=pass_manager_config.basis_gates, target=pass_manager_config.target
610626
),
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: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,21 +1756,31 @@ def test_no_infinite_loop(self, optimization_level):
17561756
seed_transpiler=42,
17571757
)
17581758

1759-
# Expect a -pi/2 global phase for the U3 to RZ/SX conversion, and
1760-
# a -0.5 * theta phase for RZ to P twice, once at theta, and once at 3 pi
1761-
# for the second and third RZ gates in the U3 decomposition.
1762-
expected = QuantumCircuit(
1763-
1, global_phase=-np.pi / 2 - 0.5 * (-0.2 + np.pi) - 0.5 * 3 * np.pi
1764-
)
1765-
expected.p(-np.pi, 0)
1766-
expected.sx(0)
1767-
expected.p(np.pi - 0.2, 0)
1768-
expected.sx(0)
1759+
if optimization_level == 1:
1760+
# Expect a -pi/2 global phase for the U3 to RZ/SX conversion, and
1761+
# a -0.5 * theta phase for RZ to P twice, once at theta, and once at 3 pi
1762+
# for the second and third RZ gates in the U3 decomposition.
1763+
expected = QuantumCircuit(
1764+
1, global_phase=-np.pi / 2 - 0.5 * (-0.2 + np.pi) - 0.5 * 3 * np.pi
1765+
)
1766+
expected.p(-np.pi, 0)
1767+
expected.sx(0)
1768+
expected.p(np.pi - 0.2, 0)
1769+
expected.sx(0)
1770+
else:
1771+
expected = QuantumCircuit(
1772+
1, global_phase=(15 * np.pi - 1) / 10
1773+
)
1774+
expected.sx(0)
1775+
expected.p(1.0 / 5.0 + np.pi, 0)
1776+
expected.sx(0)
1777+
expected.p(3 * np.pi, 0)
17691778

17701779
error_message = (
17711780
f"\nOutput circuit:\n{out!s}\n{Operator(out).data}\n"
17721781
f"Expected circuit:\n{expected!s}\n{Operator(expected).data}"
17731782
)
1783+
self.assertEqual(Operator(qc), Operator(out))
17741784
self.assertEqual(out, expected, error_message)
17751785

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

0 commit comments

Comments
 (0)