Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add control-flow support to GatesInBasis #8823

Merged
merged 2 commits into from
Oct 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions qiskit/transpiler/passes/utils/gates_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

"""Check if all gates in the DAGCircuit are in the specified basis gates."""

from qiskit.circuit import ControlFlowOp
from qiskit.converters import circuit_to_dag
from qiskit.transpiler.basepasses import AnalysisPass


Expand Down Expand Up @@ -41,18 +43,32 @@ def run(self, dag):
return
gates_out_of_basis = False
if self._target is not None:

def _visit_target(dag, wire_map):
for gate in dag.op_nodes():
# Barrier is universal and supported by all backends
if gate.name == "barrier":
continue
if not self._target.instruction_supported(
gate.name, tuple(wire_map[bit] for bit in gate.qargs)
):
return True
# Control-flow ops still need to be supported, so don't skip them in the
# previous checks.
if isinstance(gate.op, ControlFlowOp):
for block in gate.op.blocks:
inner_wire_map = {
inner: wire_map[outer]
for outer, inner in zip(gate.qargs, block.qubits)
}
if _visit_target(circuit_to_dag(block), inner_wire_map):
return True
return False

qubit_map = {qubit: index for index, qubit in enumerate(dag.qubits)}
for gate in dag.op_nodes():
# Barrier is universal and supported by all backends
if gate.name == "barrier":
continue
if not self._target.instruction_supported(
gate.name, tuple(qubit_map[bit] for bit in gate.qargs)
):
gates_out_of_basis = True
break
gates_out_of_basis = _visit_target(dag, qubit_map)
else:
for gate in dag._op_names:
for gate in dag.count_ops(recurse=True):
if gate not in self._basis_gates:
gates_out_of_basis = True
break
Expand Down
61 changes: 59 additions & 2 deletions test/python/transpiler/test_gates_in_basis_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

"""Test GatesInBasis pass."""

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import HGate, CXGate, UGate
from qiskit.circuit import QuantumCircuit, ForLoopOp, IfElseOp, Clbit
from qiskit.circuit.library import HGate, CXGate, UGate, XGate, ZGate
from qiskit.circuit.measure import Measure
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary
from qiskit.transpiler import PassManager
Expand Down Expand Up @@ -206,3 +206,60 @@ def test_all_gates_in_basis_after_translation_with_target(self):
pm.append(analysis_pass)
pm.run(circuit)
self.assertTrue(pm.property_set["all_gates_in_basis"])

def test_basis_gates_control_flow(self):
"""Test that the pass recurses into control flow."""
circuit = QuantumCircuit(4, 1)
circuit.h(0)
circuit.measure(0, 0)
with circuit.for_loop((1, 2)):
circuit.cx(0, 1)
with circuit.if_test((circuit.clbits[0], True)) as else_:
circuit.x(2)
with else_:
circuit.z(3)

one_missing = {"h", "measure", "for_loop", "cx", "if_else", "x"}
pass_ = GatesInBasis(one_missing)
pass_(circuit)
self.assertFalse(pass_.property_set["all_gates_in_basis"])

complete = one_missing | {"z"}
pass_ = GatesInBasis(complete)
pass_(circuit)
self.assertTrue(pass_.property_set["all_gates_in_basis"])

def test_basis_gates_target(self):
"""Test that the pass recurses into control flow."""
circuit = QuantumCircuit(4, 1)
circuit.h(0)
circuit.measure(0, 0)
with circuit.for_loop((1, 2)):
circuit.cx(0, 1)
with circuit.if_test((circuit.clbits[0], True)) as else_:
circuit.x(2)
with else_:
circuit.z(3)

instructions = [
HGate(),
Measure(),
ForLoopOp((), None, QuantumCircuit(4)),
CXGate(),
IfElseOp((Clbit(), True), QuantumCircuit(2), QuantumCircuit(2)),
XGate(),
ZGate(),
]
one_missing = Target(num_qubits=4)
for instruction in instructions[:-1]:
one_missing.add_instruction(instruction, {None: None})
pass_ = GatesInBasis(target=one_missing)
pass_(circuit)
self.assertFalse(pass_.property_set["all_gates_in_basis"])

complete = Target(num_qubits=4)
for instruction in instructions:
complete.add_instruction(instruction, {None: None})
pass_ = GatesInBasis(target=complete)
pass_(circuit)
self.assertTrue(pass_.property_set["all_gates_in_basis"])