Skip to content

Commit

Permalink
updated to allow cf blocks with different registers than containing
Browse files Browse the repository at this point in the history
circuit.
  • Loading branch information
ewinston committed Sep 30, 2022
1 parent fb0496e commit cb32908
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 113 deletions.
14 changes: 13 additions & 1 deletion qiskit/dagcircuit/dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,18 @@ def remove_cregs(self, *cregs):
del self.cregs[creg.name]

def remove_qubits(self, *qubits):
"""
Remove quantum bits from the circuit. All bits MUST be idle.
Any registers with references to at least one of the specified bits will
also be removed.
Args:
qubits (List[Qubit]): The bits to remove.
Raises:
DAGCircuitError: a qubit is not a :obj:`.Qubit`, is not in the circuit,
or is not idle.
"""
if any(not isinstance(qubit, Qubit) for qubit in qubits):
raise DAGCircuitError(
"qubits not of type Qubit: %s" % [b for b in qubits if not isinstance(b, Qubit)]
Expand All @@ -397,7 +409,7 @@ def remove_qubits(self, *qubits):
for qubit in qubits:
self._remove_idle_wire(qubit)
self.qubits.remove(qubit)

def remove_qregs(self, *qregs):
"""
Remove classical registers from the circuit, leaving underlying bits
Expand Down
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", "cz"}:
return set(node1_qargs) == set(node2_qargs)

if node1_qargs == node2_qargs:
Expand Down
18 changes: 11 additions & 7 deletions qiskit/transpiler/passes/routing/stochastic_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class StochasticSwap(TransformationPass):
2. We do not use the fact that the input state is zero to simplify
the circuit.
"""

_count = 0 # track number of instances of this class

def __init__(
Expand Down Expand Up @@ -294,14 +295,16 @@ def _mapper(self, circuit_graph, coupling_graph, trials=20):
dagcircuit_output = circuit_graph.copy_empty_like()

logger.debug("layout = %s", layout)

# Iterate over layers
from qiskit.converters import dag_to_circuit, circuit_to_dag
for i, layer in enumerate(layerlist):
subdag = layer["graph"]
cf_layer = False
cf_layout = None
for node in subdag.op_nodes(op=ControlFlowOp):
updated_ctrl_op, cf_layout, idle_qubits = self._transpile_controlflow_op(node, layout, circuit_graph)
updated_ctrl_op, cf_layout, idle_qubits = self._transpile_controlflow_op(
node, layout, circuit_graph
)
cf_subdag = DAGCircuit()
cf_qubits = [qubit for qubit in circuit_graph.qubits if qubit not in idle_qubits]
qreg = QuantumRegister(len(cf_qubits), "q")
Expand All @@ -312,7 +315,10 @@ def _mapper(self, circuit_graph, coupling_graph, trials=20):
subdag = cf_subdag
cf_layer = True
if cf_layer:
order = layout.reorder_bits(range(len(cf_qubits)))
target_qubits = [
qubit for qubit in dagcircuit_output.qubits if qubit not in idle_qubits
]
order = layout.reorder_bits(target_qubits)
dagcircuit_output.compose(subdag, qubits=order)
success_flag = True
else:
Expand Down Expand Up @@ -388,12 +394,10 @@ def _transpile_controlflow_op(self, cf_opnode, current_layout, dag, _depth=0):
seed = self.seed

_pass = self.__class__(
self.coupling_map, initial_layout=current_layout, seed=seed,
_depth=self._depth + 1
self.coupling_map, initial_layout=current_layout, seed=seed, _depth=self._depth + 1
)
if isinstance(cf_opnode.op, IfElseOp):
return route_cf_multiblock(_pass, cf_opnode, current_layout, self.qregs,
dag, seed=seed)
return route_cf_multiblock(_pass, cf_opnode, current_layout, self.qregs, dag, seed=seed)
elif isinstance(cf_opnode.op, (ForLoopOp, WhileLoopOp)):
return route_cf_looping(_pass, cf_opnode, current_layout, dag, seed=seed)
else:
Expand Down
34 changes: 19 additions & 15 deletions qiskit/transpiler/passes/routing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import numpy as np
from qiskit.transpiler.layout import Layout
from qiskit.dagcircuit import DAGCircuit
from qiskit.circuit import QuantumRegister, ClassicalRegister
from qiskit.circuit import QuantumRegister


def route_cf_multiblock(tpass, cf_opnode, current_layout, qregs, root_dag, seed=None):
Expand All @@ -26,11 +26,11 @@ def route_cf_multiblock(tpass, cf_opnode, current_layout, qregs, root_dag, seed=
Args:
tpass (BasePass): Transpiler pass object to use recursively.
cf_op (IfElseOp): multiblock instruction.
cf_opnode (DAGOpNode): multiblock instruction node e.g. IfElseOp.
current_layout (Layout): The current layout at the start of the instruction.
qregs (list(QuantumRegister)): quantum registers for circuit
seed (int): seed for RNG of internal layout transformation.
root_dag (DAGCircuit): root dag of compilation
seed (int): seed for RNG of internal layout transformation.
Returns:
IfElseOp: transpiled control flow operation
final_layout (Layout): layout after instruction
Expand All @@ -48,7 +48,7 @@ def route_cf_multiblock(tpass, cf_opnode, current_layout, qregs, root_dag, seed=
block_layouts = [] # control flow layouts
# expand to full width for routing
cf_op = cf_opnode.op
order = [root_dag.qubits.index(bit) for bit in cf_opnode.qargs]
order = [root_dag.qubits.index(bit) for bit in cf_opnode.qargs]
for block in cf_op.blocks:
full_dag_block = root_dag.copy_empty_like()
dag_block = circuit_to_dag(block)
Expand Down Expand Up @@ -94,22 +94,23 @@ def route_cf_multiblock(tpass, cf_opnode, current_layout, qregs, root_dag, seed=
new_qargs = [qreg[updated_dag_block.qubits.index(bit)] for bit in node.qargs]
new_dag_block.apply_operation_back(node.op, new_qargs, node.cargs)
block_circuits[i] = dag_to_circuit(new_dag_block)

final_layout = block_layouts[maxind]
return cf_op.replace_blocks(block_circuits), final_layout, cfop_idle_qubits


def route_cf_looping(tpass, cf_opnode, current_layout, dag, seed=None):
def route_cf_looping(tpass, cf_opnode, current_layout, root_dag, seed=None):
"""For looping this pass adds a swap layer using LayoutTransformation
to the end of the loop body to bring the layout back to the
starting layout. This prevents reapplying layout changing
swaps for every iteration of the loop.
Args:
tpass (BasePass): pass object to run
cf_op (ForLoopOp, WhileLoopOp): looping instruction.
cf_opnode (DAGOpNode): looping instruction e.g. ForLoopOp, WhileLoopOp
current_layout (Layout): The current layout at the start and by the
end of the instruction.
root_dag (DAGCircuit): root dagcircuit
seed (int): seed for RNG of internal layout transformation.
Returns:
Expand All @@ -123,15 +124,14 @@ def route_cf_looping(tpass, cf_opnode, current_layout, dag, seed=None):

cf_op = cf_opnode.op
coupling = tpass.coupling_map
full_num_qubits = coupling.size()
dag_block = circuit_to_dag(cf_op.blocks[0])
# expand to full width for routing
full_dag_block = dag.copy_empty_like()
full_dag_block = root_dag.copy_empty_like()
start_layout = current_layout
order = [dag.qubits.index(bit) for bit in cf_opnode.qargs]
order = [root_dag.qubits.index(bit) for bit in cf_opnode.qargs]
full_dag_block.compose(dag_block, qubits=order)
updated_dag_block = tpass.run(full_dag_block)

updated_layout = tpass.property_set["final_layout"].copy()

layout_xform = LayoutTransformation(
Expand All @@ -142,7 +142,10 @@ def route_cf_looping(tpass, cf_opnode, current_layout, dag, seed=None):
if physical_swap_dag.depth():
p2v = current_layout._p2v
virtual_swap_dag = updated_dag_block.copy_empty_like()
order = [p2v[virtual_swap_dag.qubits.index(qubit)] for qubit in layout_xform.property_set["perm_qubits"]]
order = [
p2v[virtual_swap_dag.qubits.index(qubit)]
for qubit in layout_xform.property_set["perm_qubits"]
]
virtual_swap_dag.compose(physical_swap_dag, qubits=order)
updated_dag_block.compose(virtual_swap_dag)
# contract from full width post routing
Expand Down Expand Up @@ -192,16 +195,17 @@ def combine_permutations(*permutations):
order = [order[i] for i in this_order]
return order


def _qubit_wires(wires):
"""
Return list of Qubits from list of wires.
Args:
wires (list(Bit)): list of bits
Returns:
list(Qubit)
list(Qubit): returns qubit only wires
"""
from qiskit.circuit import Qubit

return [bit for bit in wires if isinstance(bit, Qubit)]
Loading

0 comments on commit cb32908

Please sign in to comment.