Skip to content

Commit

Permalink
Support target and basis gates in Unroll3qOrMore transpiler pass
Browse files Browse the repository at this point in the history
This commit adds two new constructor arguments to the Unroll3qOrMore
transpiler pass, target and basis_gates, which are used to specify a
backend target and basis gate list respectively. If these are specified
the pass will not decompose any multiqubit operations present in the
circuit if they are in the target or basis_gates list.

Fixes Qiskit#5518
Related to Qiskit#7812
Part of Qiskit#7113
  • Loading branch information
mtreinish committed Apr 28, 2022
1 parent 04807a1 commit 43e636f
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 8 deletions.
30 changes: 30 additions & 0 deletions qiskit/transpiler/passes/basis/unroll_3q_or_more.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,27 @@
class Unroll3qOrMore(TransformationPass):
"""Recursively expands 3q+ gates until the circuit only contains 2q or 1q gates."""

def __init__(self, target=None, basis_gates=None):
"""Initialize the Unroll3qOrMore pass
Args:
target (Target): The target object reprsenting the compilation
target. If specified any multiqubit instructions in the
circuit when the pass is run that are supported by the target
device will be left in place. If both this and ``basis_gates``
are specified only the target will be checked.
basis_gates (list): A list of basis gate names that the target
device supports. If specified any gate names in the circuit
which are present in this list will not be unrolled. If both
this and ``target`` are specified only the target will be used
for checking which gates are supported.
"""
super().__init__()
self.target = target
self.basis_gates = None
if basis_gates is not None:
self.basis_gates = set(basis_gates)

def run(self, dag):
"""Run the Unroll3qOrMore pass on `dag`.
Expand All @@ -33,6 +54,15 @@ def run(self, dag):
for node in dag.multi_qubit_ops():
if dag.has_calibration_for(node):
continue
if self.target is not None:
# Treat target instructions as global since this pass can be run
# prior to layout and routing we don't have phsyical qubits from
# the circuit yet
if node.name in self.target:
continue
elif self.basis_gates is not None and node.name in self.basis_gates:
continue

# TODO: allow choosing other possible decompositions
rule = node.op.definition.data
if not rule:
Expand Down
4 changes: 2 additions & 2 deletions qiskit/transpiler/preset_passmanagers/level0.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager:
plugin_config=unitary_synthesis_plugin_config,
target=target,
),
Unroll3qOrMore(),
Unroll3qOrMore(target=target, basis_gates=basis_gates),
]

# 2. Choose an initial layout if not set by user (default: trivial layout)
Expand Down Expand Up @@ -190,7 +190,7 @@ def _swap_condition(property_set):
plugin_config=unitary_synthesis_plugin_config,
target=target,
),
Unroll3qOrMore(),
Unroll3qOrMore(target=target, basis_gates=basis_gates),
Collect2qBlocks(),
Collect1qRuns(),
ConsolidateBlocks(basis_gates=basis_gates, target=target),
Expand Down
4 changes: 2 additions & 2 deletions qiskit/transpiler/preset_passmanagers/level1.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def _vf2_match_not_found(property_set):
plugin_config=unitary_synthesis_plugin_config,
target=target,
),
Unroll3qOrMore(),
Unroll3qOrMore(target=target, basis_gates=basis_gates),
]

# 3. Use a better layout on densely connected qubits, if circuit needs swaps
Expand Down Expand Up @@ -253,7 +253,7 @@ def _swap_condition(property_set):
min_qubits=3,
target=target,
),
Unroll3qOrMore(),
Unroll3qOrMore(target=target, basis_gates=basis_gates),
Collect2qBlocks(),
ConsolidateBlocks(basis_gates=basis_gates, target=target),
UnitarySynthesis(
Expand Down
4 changes: 2 additions & 2 deletions qiskit/transpiler/preset_passmanagers/level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager:
plugin_config=unitary_synthesis_plugin_config,
target=target,
),
Unroll3qOrMore(),
Unroll3qOrMore(target=target, basis_gates=basis_gates),
]

# 2. Search for a perfect layout, or choose a dense layout, if no layout given
Expand Down Expand Up @@ -238,7 +238,7 @@ def _swap_condition(property_set):
min_qubits=3,
target=target,
),
Unroll3qOrMore(),
Unroll3qOrMore(target=target, basis_gates=basis_gates),
Collect2qBlocks(),
ConsolidateBlocks(basis_gates=basis_gates, target=target),
UnitarySynthesis(
Expand Down
4 changes: 2 additions & 2 deletions qiskit/transpiler/preset_passmanagers/level3.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager:
min_qubits=3,
target=target,
),
Unroll3qOrMore(),
Unroll3qOrMore(target=target, basis_gates=basis_gates),
]

# 2. Layout on good qubits if calibration info available, otherwise on dense links
Expand Down Expand Up @@ -236,7 +236,7 @@ def _swap_condition(property_set):
min_qubits=3,
target=target,
),
Unroll3qOrMore(),
Unroll3qOrMore(target=target, basis_gates=basis_gates),
Collect2qBlocks(),
ConsolidateBlocks(basis_gates=basis_gates, target=target),
UnitarySynthesis(
Expand Down
10 changes: 10 additions & 0 deletions releasenotes/notes/unroll3q-target-bf57cc4365808862.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
features:
- |
The constructor for the :class:`~.Unroll3qOrMore` transpiler pass has
two new optional keyword arguments, ``target`` and ``basis`` gates. These
options enable you to specify the :class:`~.Target` or supported basis
gates respectively to describe the target backend. If any of the operations
in the circuit are in the ``target`` or ``basis_gates`` those will not
be unrolled by the pass as the target device has native support for the
operation.
39 changes: 39 additions & 0 deletions test/python/transpiler/test_unroll_3q_or_more.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@

"""Test the Unroll3qOrMore pass"""
import numpy as np

from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit.circuit.library import CCXGate, RCCXGate
from qiskit.transpiler.passes import Unroll3qOrMore
from qiskit.converters import circuit_to_dag, dag_to_circuit
from qiskit.quantum_info.operators import Operator
from qiskit.quantum_info.random import random_unitary
from qiskit.test import QiskitTestCase
from qiskit.extensions import UnitaryGate
from qiskit.transpiler import Target


class TestUnroll3qOrMore(QiskitTestCase):
Expand Down Expand Up @@ -91,3 +94,39 @@ def test_identity(self):
after_dag = pass_.run(dag)
after_circ = dag_to_circuit(after_dag)
self.assertTrue(Operator(circuit).equiv(Operator(after_circ)))

def test_target(self):
"""Test target is respected by the unroll 3q or more pass."""
target = Target(num_qubits=3)
target.add_instruction(CCXGate())
qc = QuantumCircuit(3)
qc.ccx(0, 1, 2)
qc.append(RCCXGate(), [0, 1, 2])
unroll_pass = Unroll3qOrMore(target=target)
res = unroll_pass(qc)
self.assertIn('ccx', res.count_ops())
self.assertNotIn('rccx', res.count_ops())

def test_basis_gates(self):
"""Test basis_gates are respected by the unroll 3q or more pass."""
basis_gates = ["rccx"]
qc = QuantumCircuit(3)
qc.ccx(0, 1, 2)
qc.append(RCCXGate(), [0, 1, 2])
unroll_pass = Unroll3qOrMore(basis_gates=basis_gates)
res = unroll_pass(qc)
self.assertNotIn('ccx', res.count_ops())
self.assertIn('rccx', res.count_ops())

def test_target_over_basis_gates(self):
"""Test target is respected over basis_gates by the unroll 3q or more pass."""
target = Target(num_qubits=3)
basis_gates = ['rccx']
target.add_instruction(CCXGate())
qc = QuantumCircuit(3)
qc.ccx(0, 1, 2)
qc.append(RCCXGate(), [0, 1, 2])
unroll_pass = Unroll3qOrMore(target=target, basis_gates=basis_gates)
res = unroll_pass(qc)
self.assertIn('ccx', res.count_ops())
self.assertNotIn('rccx', res.count_ops())

0 comments on commit 43e636f

Please sign in to comment.