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 controlflow handling to CheckMap transpiler pass. #8793

Merged
merged 9 commits into from
Sep 30, 2022
13 changes: 13 additions & 0 deletions qiskit/transpiler/passes/utils/check_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"""Check if a DAG circuit is already mapped to a coupling map."""

from qiskit.transpiler.basepasses import AnalysisPass
from qiskit.circuit.controlflow import ControlFlowOp
from qiskit.transpiler.layout import Layout


class CheckMap(AnalysisPass):
Expand Down Expand Up @@ -41,6 +43,8 @@ def run(self, dag):
Args:
dag (DAGCircuit): DAG to map.
"""
from qiskit.converters import circuit_to_dag

self.property_set["is_swap_mapped"] = True

if self.coupling_map is None or len(self.coupling_map.graph) == 0:
Expand All @@ -64,3 +68,12 @@ def run(self, dag):
)
self.property_set["is_swap_mapped"] = False
return
for cf_instr in dag.op_nodes(op=ControlFlowOp):
order = [qubit_indices[bit] for bit in cf_instr.qargs]
for block in cf_instr.op.blocks:
dag_block = circuit_to_dag(block)
mapped_dag = dag.copy_empty_like()
mapped_dag.compose(dag_block, qubits=order)
self.run(mapped_dag)
if not self.property_set["is_swap_mapped"]:
return
132 changes: 131 additions & 1 deletion test/python/transpiler/test_check_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import unittest

from qiskit import QuantumRegister, QuantumCircuit
from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister
from qiskit.transpiler.passes import CheckMap
from qiskit.transpiler import CouplingMap
from qiskit.converters import circuit_to_dag
Expand Down Expand Up @@ -85,6 +85,136 @@ def test_swap_mapped_false(self):

self.assertFalse(pass_.property_set["is_swap_mapped"])

def test_swap_mapped_cf_true(self):
"""Check control flow blocks are mapped."""
num_qubits = 3
coupling = CouplingMap.from_line(num_qubits)
qr = QuantumRegister(3)
cr = ClassicalRegister(3)
circuit = QuantumCircuit(qr, cr)
true_body = QuantumCircuit(qr)
true_body.swap(0, 1)
true_body.cx(2, 1)
circuit.if_else((cr[0], 0), true_body, None, qr, cr)
dag = circuit_to_dag(circuit)
pass_ = CheckMap(coupling)
pass_.run(dag)
self.assertTrue(pass_.property_set["is_swap_mapped"])

def test_swap_mapped_cf_false(self):
"""Check control flow blocks are not mapped."""
num_qubits = 3
coupling = CouplingMap.from_line(num_qubits)
qr = QuantumRegister(3)
cr = ClassicalRegister(3)
circuit = QuantumCircuit(qr, cr)
true_body = QuantumCircuit(qr)
true_body.cx(0, 2)
circuit.if_else((cr[0], 0), true_body, None, qr, cr)
dag = circuit_to_dag(circuit)
pass_ = CheckMap(coupling)
pass_.run(dag)
self.assertFalse(pass_.property_set["is_swap_mapped"])

def test_swap_mapped_cf_layout_change_false(self):
"""Check control flow blocks with layout change are not mapped."""
num_qubits = 3
coupling = CouplingMap.from_line(num_qubits)
qr = QuantumRegister(3)
cr = ClassicalRegister(3)
circuit = QuantumCircuit(qr, cr)
true_body = QuantumCircuit(qr)
true_body.cx(1, 2)
circuit.if_else((cr[0], 0), true_body, None, qr[[1, 0, 2]], cr)
dag = circuit_to_dag(circuit)
pass_ = CheckMap(coupling)
pass_.run(dag)
self.assertFalse(pass_.property_set["is_swap_mapped"])

def test_swap_mapped_cf_layout_change_true(self):
"""Check control flow blocks with layout change are mapped."""
num_qubits = 3
coupling = CouplingMap.from_line(num_qubits)
qr = QuantumRegister(3)
cr = ClassicalRegister(3)
circuit = QuantumCircuit(qr, cr)
true_body = QuantumCircuit(qr)
true_body.cx(0, 2)
circuit.if_else((cr[0], 0), true_body, None, qr[[1, 0, 2]], cr)
dag = circuit_to_dag(circuit)
pass_ = CheckMap(coupling)
pass_.run(dag)
self.assertTrue(pass_.property_set["is_swap_mapped"])

def test_swap_mapped_cf_different_bits(self):
"""Check control flow blocks with layout change are mapped."""
num_qubits = 3
coupling = CouplingMap.from_line(num_qubits)
qr = QuantumRegister(3)
cr = ClassicalRegister(3)
circuit = QuantumCircuit(qr, cr)
true_body = QuantumCircuit(3)
true_body.cx(0, 2)
circuit.if_else((cr[0], 0), true_body, None, qr[[1, 0, 2]], cr)
dag = circuit_to_dag(circuit)
pass_ = CheckMap(coupling)
pass_.run(dag)
self.assertTrue(pass_.property_set["is_swap_mapped"])

def test_disjoint_controlflow_bits(self):
"""test control flow on with different registers"""
num_qubits = 4
coupling = CouplingMap.from_line(num_qubits)
qr1 = QuantumRegister(4, "qr")
qr2 = QuantumRegister(3, "qrif")
cr = ClassicalRegister(3)
circuit = QuantumCircuit(qr1, cr)
true_body = QuantumCircuit(qr2)
true_body.cx(0, 2)
circuit.if_else((cr[0], 0), true_body, None, qr1[[1, 0, 2]], cr)
dag = circuit_to_dag(circuit)
pass_ = CheckMap(coupling)
pass_.run(dag)
self.assertTrue(pass_.property_set["is_swap_mapped"])

def test_nested_controlflow_true(self):
"""Test nested controlflow with true evaluation."""
num_qubits = 4
coupling = CouplingMap.from_line(num_qubits)
qr1 = QuantumRegister(4, "qr")
qr2 = QuantumRegister(3, "qrif")
cr1 = ClassicalRegister(1)
cr2 = ClassicalRegister(1)
circuit = QuantumCircuit(qr1, cr1)
true_body = QuantumCircuit(qr2, cr2)
for_body = QuantumCircuit(3)
for_body.cx(0, 2)
true_body.for_loop(range(5), body=for_body, qubits=qr2, clbits=cr2)
circuit.if_else((cr1[0], 0), true_body, None, qr1[[1, 0, 2]], cr1)
dag = circuit_to_dag(circuit)
pass_ = CheckMap(coupling)
pass_.run(dag)
self.assertTrue(pass_.property_set["is_swap_mapped"])

def test_nested_controlflow_false(self):
"""Test nested controlflow with true evaluation."""
num_qubits = 4
coupling = CouplingMap.from_line(num_qubits)
qr1 = QuantumRegister(4, "qr")
qr2 = QuantumRegister(3, "qrif")
cr1 = ClassicalRegister(1)
cr2 = ClassicalRegister(1)
circuit = QuantumCircuit(qr1, cr1)
true_body = QuantumCircuit(qr2, cr2)
for_body = QuantumCircuit(3)
for_body.cx(0, 2)
true_body.for_loop(range(5), body=for_body, qubits=qr2, clbits=cr2)
circuit.if_else((cr1[0], 0), true_body, None, qr1[[0, 1, 2]], cr1)
dag = circuit_to_dag(circuit)
pass_ = CheckMap(coupling)
pass_.run(dag)
self.assertFalse(pass_.property_set["is_swap_mapped"])


if __name__ == "__main__":
unittest.main()