Skip to content

Commit

Permalink
Make GatesInBasis transpiler pass Target aware
Browse files Browse the repository at this point in the history
This commit makes the GatesInBasis transpiler pass target aware. It adds
a new kwarg, target, which optionally takes a Target object. If it's
specified the basis_gates required field will be ignored and the pass
will check that the gates and their qargs are valid in the target.

Part of Qiskit#7113
  • Loading branch information
mtreinish committed Jan 20, 2022
1 parent d662fbb commit 9a74727
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 7 deletions.
29 changes: 22 additions & 7 deletions qiskit/transpiler/passes/utils/gates_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,37 @@
class GatesInBasis(AnalysisPass):
"""Check if all gates in a DAG are in a given set of gates"""

def __init__(self, basis_gates):
def __init__(self, basis_gates, target=None):
"""Initialize the GatesInBasis pass.
Args:
basis_gates (list): The list of strings representing the set of basis gates.
target (Target): If specified the target represnting the backend. If specified
this will be used instead of the ``basis_gates`` parameter
"""
super().__init__()
self._basis_gates = set(basis_gates)
self._target = target

def run(self, dag):
"""Run the GatesInBasis pass on `dag`."""
gates_out_of_basis = False
basic_instrs = {"measure", "reset", "barrier", "snapshot", "delay"}
for gate in dag._op_names:
if gate not in self._basis_gates and gate not in basic_instrs:
gates_out_of_basis = True
break

if self._target is not None:
qubit_map = {qubit: index for index, qubit in enumerate(dag.qubits)}
for gate in dag.topological_op_nodes():
# Barrier is universal and supported by all backends
if gate.name == "barrier":
continue
if gate.name not in self._target:
gates_out_of_basis = True
break
if tuple(qubit_map[bit] for bit in gate.qargs) not in self._target[gate.name]:
gates_out_of_basis = True
break
else:
basic_instrs = {"measure", "reset", "barrier", "snapshot", "delay"}
for gate in dag._op_names:
if gate not in self._basis_gates and gate not in basic_instrs:
gates_out_of_basis = True
break
self.property_set["all_gates_in_basis"] = not gates_out_of_basis
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
features:
- |
Added a new kwarg, ``target``, to the constructor for the
:class:`.GatesInBasis` transpiler pass. This new argument can be used to
optionally specify a :class:`.Target` object that represents the backend.
When set this :class:`.Target` will be used for determining whether
a :class:`.DAGCircuit` contains gates outside the basis set.
86 changes: 86 additions & 0 deletions test/python/transpiler/test_gates_in_basis_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import BasisTranslator
from qiskit.transpiler.passes import GatesInBasis
from qiskit.transpiler.target import Target
from qiskit.test import QiskitTestCase
from qiskit.test.mock.fake_backend_v2 import FakeBackend5QV2


class TestGatesInBasisPass(QiskitTestCase):
Expand Down Expand Up @@ -88,3 +90,87 @@ def test_all_gates_in_basis_after_translation(self):
pm.append(analysis_pass)
pm.run(circuit)
self.assertTrue(pm.property_set["all_gates_in_basis"])

def test_all_gates_in_basis_with_target(self):
"""Test circuit with all gates in basis with target."""
target = FakeBackend5QV2().target
basis_gates = ["cx", "u"] # not used
property_set = {}
analysis_pass = GatesInBasis(basis_gates, target=target)
circuit = QuantumCircuit(2)
circuit.u(0, 0, 0, 0)
circuit.cx(0, 1)
circuit.measure_all()
analysis_pass(circuit, property_set=property_set)
self.assertTrue(property_set["all_gates_in_basis"])

def test_all_gates_not_in_basis_with_target(self):
"""Test circuit with not all gates in basis with target."""
target = FakeBackend5QV2().target
basis_gates = ["cx", "h"]
property_set = {}
analysis_pass = GatesInBasis(basis_gates, target=target)
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
analysis_pass(circuit, property_set=property_set)
self.assertFalse(property_set["all_gates_in_basis"])

def test_all_gates_in_basis_not_on_all_qubits_with_target(self):
"""Test circuit with gate in global basis but not local basis."""
target = FakeBackend5QV2().target
basis_gates = ["ecr", "cx", "h"]
property_set = {}
analysis_pass = GatesInBasis(basis_gates, target=target)
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.ecr(0, 1)
circuit.measure_all()
analysis_pass(circuit, property_set=property_set)
self.assertFalse(property_set["all_gates_in_basis"])

def test_all_gates_in_basis_empty_circuit_with_target(self):
"""Test circuit with no gates with target."""
target = FakeBackend5QV2().target
basis_gates = ["cx", "u"]
property_set = {}
analysis_pass = GatesInBasis(basis_gates, target=target)
circuit = QuantumCircuit(2)
analysis_pass(circuit, property_set=property_set)
self.assertTrue(property_set["all_gates_in_basis"])

def test_all_gates_in_empty_target(self):
"""Test circuit with gates and empty basis with target."""
target = Target()
basis_gates = []
property_set = {}
analysis_pass = GatesInBasis(basis_gates, target=target)
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
analysis_pass(circuit, property_set=property_set)
self.assertFalse(property_set["all_gates_in_basis"])

def test_all_gates_in_basis_after_translation_with_target(self):
"""Test circuit with gates in basis after conditional translation."""
target = FakeBackend5QV2().target
basis_gates = ["cx", "u"]
property_set = {}
analysis_pass = GatesInBasis(basis_gates, target)
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
analysis_pass(circuit, property_set=property_set)
self.assertFalse(property_set["all_gates_in_basis"])
pm = PassManager()
pm.append(analysis_pass)
pm.append(
BasisTranslator(SessionEquivalenceLibrary, basis_gates, target=target),
condition=lambda property_set: not property_set["all_gates_in_basis"],
)
pm.append(analysis_pass)
pm.run(circuit)
self.assertTrue(pm.property_set["all_gates_in_basis"])

0 comments on commit 9a74727

Please sign in to comment.