Skip to content

Commit

Permalink
Add control-flow support to GatesInBasis (#8823)
Browse files Browse the repository at this point in the history
It's not yet entirely clear how control-flow will be supported through
the `Target` and `basis_gates`, but for the time being, we just test
them as if they will be added like any other instruction.  This is
unlikely to entirely remain the case as more classical handling is
added.

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
jakelishman and mergify[bot] authored Oct 1, 2022
1 parent c701b10 commit 890f450
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 12 deletions.
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"])

0 comments on commit 890f450

Please sign in to comment.