Skip to content
This repository has been archived by the owner on Jul 24, 2024. It is now read-only.

Commit

Permalink
Map clbits.
Browse files Browse the repository at this point in the history
  • Loading branch information
taalexander committed Feb 1, 2023
1 parent 988edf8 commit c2abbac
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
Instruction,
Measure,
)
from qiskit.circuit.bit import Bit
from qiskit.circuit.library import Barrier
from qiskit.circuit.delay import Delay
from qiskit.circuit.parameterexpression import ParameterExpression
Expand Down Expand Up @@ -69,7 +70,7 @@ def __init__(self) -> None:
self._dag = None
self._block_dag = None
self._prev_node: Optional[DAGNode] = None
self._wire_map: Optional[Dict[Qubit, Qubit]] = None
self._wire_map: Optional[Dict[Bit, Bit]] = None
self._block_duration = 0
self._current_block_idx = 0
self._conditional_block = False
Expand Down Expand Up @@ -104,7 +105,7 @@ def run(self, dag: DAGCircuit) -> DAGCircuit:
self._init_run(dag)

# Trivial wire map at the top-level
wire_map = {qubit: qubit for qubit in dag.qubits}
wire_map = {wire: wire for wire in dag.wires}
# Top-level dag is the entry block
new_dag = self._visit_block(dag, wire_map)

Expand Down Expand Up @@ -425,7 +426,10 @@ def _visit_control_flow_op(self, node: DAGNode) -> None:
block_dag = self._node_block_dags[node][block_idx]
inner_wire_map = {
inner: outer
for outer, inner in zip(self._map_wires(node.qargs), block_dag.qubits)
for outer, inner in zip(
self._map_wires(node.qargs + node.cargs),
block_dag.qubits + block_dag.clbits,
)
}
new_node_block_dags.append(
self._visit_block(
Expand All @@ -446,7 +450,7 @@ def _visit_control_flow_op(self, node: DAGNode) -> None:
t0,
new_control_flow_op,
self._map_wires(node.qargs) if fast_path_node else self._block_dag.qubits,
node.cargs,
self._map_wires(node.cargs),
)

def _visit_delay(self, node: DAGNode) -> None:
Expand Down Expand Up @@ -510,7 +514,11 @@ def _visit_generic(self, node: DAGNode) -> None:
self._dirty_qubits |= set(self._map_wires(node.qargs))

new_node = self._apply_scheduled_op(
block_idx, t0, node.op, self._map_wires(node.qargs), node.cargs
block_idx,
t0,
node.op,
self._map_wires(node.qargs),
self._map_wires(node.cargs),
)
self._last_node_to_touch.update(
{
Expand Down Expand Up @@ -577,9 +585,9 @@ def _apply_scheduled_op(
self.property_set["node_start_time"][new_node] = (block_idx, t_start)
return new_node

def _map_wires(self, wires: Iterable[Qubit]) -> List[Qubit]:
def _map_wires(self, wires: Iterable[Bit]) -> List[Bit]:
"""Map the wires from the current block to the top-level block's wires.
TODO: We should have an easier approach to wire mapping from the transpiler.
"""
return [self._wire_map[q] for q in wires]
return [self._wire_map[w] for w in wires]
75 changes: 36 additions & 39 deletions qiskit_ibm_provider/transpiler/passes/scheduling/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from qiskit.transpiler.passes.scheduling.time_unit_conversion import TimeUnitConversion

from qiskit.circuit import Barrier, Clbit, ControlFlowOp, Measure, Qubit, Reset
from qiskit.circuit.bit import Bit
from qiskit.dagcircuit import DAGCircuit, DAGNode
from qiskit.transpiler.exceptions import TranspilerError

Expand Down Expand Up @@ -59,8 +60,8 @@ def __init__(

self._dag: Optional[DAGCircuit] = None
self._block_dag: Optional[DAGCircuit] = None
self._wire_map: Optional[Dict[Qubit, Qubit]] = None
self._node_wire_maps: Optional[Dict[DAGNode, List[Qubit]]] = None
self._wire_map: Optional[Dict[Bit, Bit]] = None
self._node_mapped_wires: Optional[Dict[DAGNode, List[Bit]]] = None
self._node_block_dags: Dict[DAGNode, DAGCircuit] = {}
# Mapping of control-flow nodes to their containing blocks
self._block_idx_dag_map: Dict[int, DAGCircuit] = {}
Expand Down Expand Up @@ -140,8 +141,7 @@ def _visit_control_flow_op(self, node: DAGNode) -> None:
self._node_block_dags[node] = node_block_dags = []

t0 = max( # pylint: disable=invalid-name
self._current_block_bit_times[bit]
for bit in itertools.chain(self._map_wires(node), node.cargs)
self._current_block_bit_times[bit] for bit in self._map_wires(node)
)

# Duration is 0 as we do not schedule across terminator
Expand All @@ -154,7 +154,9 @@ def _visit_control_flow_op(self, node: DAGNode) -> None:
new_dag = circuit_to_dag(block)
inner_wire_map = {
inner: outer
for outer, inner in zip(self._map_wires(node), new_dag.qubits)
for outer, inner in zip(
self._map_wires(node), new_dag.qubits + new_dag.clbits
)
}
node_block_dags.append(new_dag)
self._visit_block(new_dag, inner_wire_map)
Expand All @@ -179,8 +181,8 @@ def _init_run(self, dag: DAGCircuit) -> None:

self._dag = dag
self._block_dag = None
self._wire_map = {qubit: qubit for qubit in dag.qubits}
self._node_wire_maps = {}
self._wire_map = {wire: wire for wire in dag.wires}
self._node_mapped_wires = {}
self._node_block_dags = {}
self._block_idx_dag_map = {}

Expand All @@ -205,7 +207,7 @@ def _get_duration(self, node: DAGNode, dag: Optional[DAGCircuit] = None) -> int:
# as zero duration to avoid padding.
return 0

indices = [self._bit_indices[qarg] for qarg in self._map_wires(node)]
indices = [self._bit_indices[qarg] for qarg in self._map_qubits(node)]

# Fall back to current block dag if not specified.
dag = dag or self._block_dag
Expand Down Expand Up @@ -237,11 +239,7 @@ def _update_bit_times( # pylint: disable=invalid-name
self._max_block_t1.get(self._current_block_idx, 0), t1
)

update_bits = (
itertools.chain(self._map_wires(node), node.cargs)
if update_cargs
else self._map_wires(node)
)
update_bits = self._map_wires(node) if update_cargs else self._map_qubits(node)
for bit in update_bits:
self._current_block_bit_times[bit] = t1

Expand All @@ -254,11 +252,7 @@ def _begin_new_circuit_block(self) -> None:
self._block_idx_dag_map[self._current_block_idx] = self._block_dag
self._control_flow_block = False
self._bit_stop_times[self._current_block_idx] = {
q: 0
for q in itertools.chain(
(self._wire_map[qubit] for qubit in self._block_dag.qubits),
self._block_dag.clbits,
)
self._wire_map[wire]: 0 for wire in self._block_dag.wires
}
self._flush_measures()

Expand All @@ -274,11 +268,11 @@ def _current_block_measure_qargs(self) -> Set[Qubit]:
return set(
qarg
for measure in self._current_block_measures
for qarg in self._map_wires(measure)
for qarg in self._map_qubits(measure)
)

def _check_flush_measures(self, node: DAGNode) -> None:
if self._current_block_measure_qargs() & set(self._map_wires(node)):
if self._current_block_measure_qargs() & set(self._map_qubits(node)):
if self._current_block_measures_has_reset:
# If a reset is included we must trigger the end of a block.
self._begin_new_circuit_block()
Expand All @@ -291,13 +285,20 @@ def _map_wires(self, node: DAGNode) -> List[Qubit]:
TODO: We should have an easier approach to wire mapping from the transpiler.
"""
if node not in self._node_wire_maps:
self._node_wire_maps[node] = wire_map = [
self._wire_map[q] for q in node.qargs
if node not in self._node_mapped_wires:
self._node_mapped_wires[node] = wire_map = [
self._wire_map[q] for q in node.qargs + node.cargs
]
return wire_map

return self._node_wire_maps[node]
return self._node_mapped_wires[node]

def _map_qubits(self, node: DAGNode) -> List[Qubit]:
"""Map the qubits from the current node to the top-level block's qubits.
TODO: We should have an easier approach to wire mapping from the transpiler.
"""
return [wire for wire in self._map_wires(node) if isinstance(wire, Qubit)]


class ASAPScheduleAnalysis(BaseDynamicCircuitAnalysis):
Expand Down Expand Up @@ -334,7 +335,7 @@ def run(self, dag: DAGCircuit) -> DAGCircuit:
self._init_run(dag)

# Trivial wire map at the top-level
wire_map = {qubit: qubit for qubit in dag.qubits}
wire_map = {wire: wire for wire in dag.wires}
# Top-level dag is the entry block
self._visit_block(dag, wire_map)

Expand All @@ -359,7 +360,7 @@ def _visit_measure(self, node: DAGNode) -> None:
current_block_measure_qargs = self._current_block_measure_qargs()
# We handle a set of qubits here as _visit_reset currently calls
# this method and a reset may have multiple qubits.
measure_qargs = set(self._map_wires(node))
measure_qargs = set(self._map_qubits(node))

t0q = max(
self._current_block_bit_times[q] for q in measure_qargs
Expand Down Expand Up @@ -397,7 +398,7 @@ def _visit_measure(self, node: DAGNode) -> None:
}
measure_duration = self._durations.get(
Measure(),
[bit_indices[qarg] for qarg in self._map_wires(measure)],
[bit_indices[qarg] for qarg in self._map_qubits(measure)],
unit="dt",
)
t1 = t0 + measure_duration # pylint: disable=invalid-name
Expand Down Expand Up @@ -426,8 +427,7 @@ def _visit_generic(self, node: DAGNode) -> None:
self._check_flush_measures(node)

t0 = max( # pylint: disable=invalid-name
self._current_block_bit_times[bit]
for bit in itertools.chain(self._map_wires(node), node.cargs)
self._current_block_bit_times[bit] for bit in self._map_wires(node)
)

t1 = t0 + op_duration # pylint: disable=invalid-name
Expand Down Expand Up @@ -468,7 +468,7 @@ def run(self, dag: DAGCircuit) -> None:
self._init_run(dag)

# Trivial wire map at the top-level
wire_map = {qubit: qubit for qubit in dag.qubits}
wire_map = {wire: wire for wire in dag.wires}
# Top-level dag is the entry block
self._visit_block(dag, wire_map)
self._push_block_durations()
Expand All @@ -493,7 +493,7 @@ def _visit_measure(self, node: DAGNode) -> None:
current_block_measure_qargs = self._current_block_measure_qargs()
# We handle a set of qubits here as _visit_reset currently calls
# this method and a reset may have multiple qubits.
measure_qargs = set(self._map_wires(node))
measure_qargs = set(self._map_qubits(node))

t0q = max(
self._current_block_bit_times[q] for q in measure_qargs
Expand Down Expand Up @@ -531,7 +531,7 @@ def _visit_measure(self, node: DAGNode) -> None:
}
measure_duration = self._durations.get(
Measure(),
[bit_indices[qarg] for qarg in self._map_wires(measure)],
[bit_indices[qarg] for qarg in self._map_qubits(measure)],
unit="dt",
)
t1 = t0 + measure_duration # pylint: disable=invalid-name
Expand Down Expand Up @@ -566,8 +566,7 @@ def _visit_generic(self, node: DAGNode) -> None:
self._check_flush_measures(node)

t0 = max( # pylint: disable=invalid-name
self._current_block_bit_times[bit]
for bit in itertools.chain(self._map_wires(node), node.cargs)
self._current_block_bit_times[bit] for bit in self._map_wires(node)
)

t1 = t0 + op_duration # pylint: disable=invalid-name
Expand Down Expand Up @@ -602,7 +601,7 @@ def _calculate_new_times(
block: int, node: DAGNode, block_bit_times: Dict[int, Dict[Qubit, int]]
) -> int:
max_block_time = min(
block_bit_times[block][bit] for bit in self._map_wires(node)
block_bit_times[block][bit] for bit in self._map_qubits(node)
)

t0 = self._node_start_time[node][1] # pylint: disable=invalid-name
Expand All @@ -629,7 +628,7 @@ def _update_time(
)

# Update available times by bit
for bit in self._map_wires(node):
for bit in self._map_qubits(node):
block_bit_times[block][bit] = new_time

for node, (
Expand All @@ -642,9 +641,7 @@ def _update_time(
# Start with last time as the time to push to
if block not in block_bit_times:
block_bit_times[block] = {
q: self._max_block_t1[block]
for q in self._dag.qubits
+ self._dag.clbits # Use top-level circuit qubits
q: self._max_block_t1[block] for q in self._dag.wires
}

# Calculate the latest available time to push to collectively for tied nodes
Expand Down

0 comments on commit c2abbac

Please sign in to comment.