Skip to content

Commit

Permalink
simplify function and naming of control flow layer transpilation
Browse files Browse the repository at this point in the history
function
  • Loading branch information
ewinston committed Oct 5, 2022
1 parent 5477c50 commit 1487b80
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 35 deletions.
2 changes: 1 addition & 1 deletion qiskit/dagcircuit/dagnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None):
node2_cargs = [bit_indices2[carg] for carg in node2.cargs]

# For barriers, qarg order is not significant so compare as sets
if node1.op.name == node2.op.name and node1.name in {"barrier", "swap", "cz"}:
if node1.op.name == node2.op.name and node1.name in {"barrier", "swap"}:
return set(node1_qargs) == set(node2_qargs)

if node1_qargs == node2_qargs:
Expand Down
83 changes: 49 additions & 34 deletions qiskit/transpiler/passes/routing/stochastic_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ class StochasticSwap(TransformationPass):

_instance_num = 0 # track number of instances of this class

def __init__(
self, coupling_map, trials=20, seed=None, fake_run=False, initial_layout=None, _depth=0
):
def __init__(self, coupling_map, trials=20, seed=None, fake_run=False, initial_layout=None):
"""StochasticSwap initializer.
The coupling map is a connected graph
Expand All @@ -67,6 +65,7 @@ def __init__(
seed (int): seed for random number generator
fake_run (bool): if true, it only pretend to do routing, i.e., no
swap is effectively added.
initial_layout (Layout): starting layout at beginning of pass.
"""
super().__init__()
self.coupling_map = coupling_map
Expand All @@ -77,7 +76,6 @@ def __init__(
self.trivial_layout = None
self.initial_layout = initial_layout
self._qubit_indices = None
self._depth = _depth
self._instance_num += 1

def run(self, dag):
Expand Down Expand Up @@ -318,9 +316,9 @@ def _mapper(self, circuit_graph, coupling_graph, trials=20):

# Go through each gate in the layer
for j, serial_layer in enumerate(serial_layerlist):
subdag = serial_layer["graph"]
# subdag has only one operation
op_node = subdag.op_nodes()[0]
layer_dag = serial_layer["graph"]
# layer_dag has only one operation
op_node = layer_dag.op_nodes()[0]
if not isinstance(op_node.op, ControlFlowOp):
(
success_flag,
Expand Down Expand Up @@ -354,26 +352,9 @@ def _mapper(self, circuit_graph, coupling_graph, trials=20):
best_circuit,
)
else:
updated_ctrl_op, cf_layout, idle_qubits = self._transpile_controlflow_op(
op_node, layout, circuit_graph, _seed=self.seed
)
cf_subdag = DAGCircuit()
cf_qubits = [
qubit for qubit in circuit_graph.qubits if qubit not in idle_qubits
]
qreg = QuantumRegister(len(cf_qubits), "q")
cf_subdag.add_qreg(qreg)
for creg in subdag.cregs.values():
cf_subdag.add_creg(creg)
cf_subdag.apply_operation_back(
updated_ctrl_op, cf_subdag.qubits, op_node.cargs
layout = self._controlflow_layer_update(
dagcircuit_output, layer_dag, layout, circuit_graph, _seed=self.seed
)
target_qubits = [
qubit for qubit in dagcircuit_output.qubits if qubit not in idle_qubits
]
order = layout.reorder_bits(target_qubits)
dagcircuit_output.compose(cf_subdag, qubits=order)
layout = cf_layout
else:
# Update the record of qubit positions for each iteration
layout = best_layout
Expand All @@ -394,17 +375,51 @@ def _mapper(self, circuit_graph, coupling_graph, trials=20):
return circuit_graph
return dagcircuit_output

def _transpile_controlflow_op(self, cf_opnode, current_layout, dag, _depth=0, _seed=None):
"""handle controlflow ops by type"""
def _controlflow_layer_update(
self, dagcircuit_output, layer_dag, current_layout, root_dag, _seed=None
):
"""
Updates the new dagcircuit with a routed control flow operation.
Args:
dagcircuit_output (DAGCircuit): dagcircuit that is being built with routed operations.
layer_dag (DAGCircuit): layer to route containing a single controlflow operation.
current_layout (Layout): current layout coming into this layer.
root_dag (DAGCircuit): root dag of pass
_seed (int or None): seed used to derive seeds for child instances of this pass where
it is used by stochastic_swap_rs.swap_trials as well as LayoutTransformation. If
the seed is not None the instance_num class variable gets added to this seed to
seed other instances.
Returns:
Layout: updated layout after this layer has been routed.
Raises:
TranspilerError: if layer_dag does not contain a recognized ControlFlowOp.
"""
cf_opnode = layer_dag.op_nodes()[0]
seed = _seed if _seed is None else _seed + self._instance_num
_pass = self.__class__(
self.coupling_map, initial_layout=current_layout, seed=seed, _depth=self._depth + 1
)
_pass = self.__class__(self.coupling_map, initial_layout=current_layout, seed=seed)
if isinstance(cf_opnode.op, IfElseOp):
return route_cf_multiblock(
_pass, cf_opnode, current_layout, self.qregs, dag, seed=self.seed
updated_ctrl_op, cf_layout, idle_qubits = route_cf_multiblock(
_pass, cf_opnode, current_layout, self.qregs, root_dag, seed=self.seed
)
elif isinstance(cf_opnode.op, (ForLoopOp, WhileLoopOp)):
return route_cf_looping(_pass, cf_opnode, current_layout, dag, seed=self.seed)
updated_ctrl_op, cf_layout, idle_qubits = route_cf_looping(
_pass, cf_opnode, current_layout, root_dag, seed=self.seed
)
else:
raise TranspilerError(f"unsupported control flow operation: {cf_opnode}")

cf_layer_dag = DAGCircuit()
cf_qubits = [qubit for qubit in root_dag.qubits if qubit not in idle_qubits]
qreg = QuantumRegister(len(cf_qubits), "q")
cf_layer_dag.add_qreg(qreg)
for creg in layer_dag.cregs.values():
cf_layer_dag.add_creg(creg)
cf_layer_dag.apply_operation_back(updated_ctrl_op, cf_layer_dag.qubits, cf_opnode.cargs)
target_qubits = [qubit for qubit in dagcircuit_output.qubits if qubit not in idle_qubits]
order = current_layout.reorder_bits(target_qubits)
dagcircuit_output.compose(cf_layer_dag, qubits=order)
return cf_layout
1 change: 1 addition & 0 deletions test/python/transpiler/test_stochastic_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,7 @@ def test_controlflow_intra_if_else_route(self):
expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg, creg)
new_order = [1, 2, 0, 4, 3]
expected.measure(qreg, creg[new_order])

self.assertEqual(cqc, expected)
check_map_pass = CheckMap(coupling)
check_map_pass.run(circuit_to_dag(expected))
Expand Down

0 comments on commit 1487b80

Please sign in to comment.