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

Remove recursion from ConstrainedReschedule pass (backport #10051) #10057

Merged
merged 1 commit into from
May 2, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 56 additions & 54 deletions qiskit/transpiler/passes/scheduling/alignments/reschedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,9 @@ def _get_next_gate(cls, dag: DAGCircuit, node: DAGOpNode) -> List[DAGOpNode]:
Returns:
A list of non-delay successors.
"""
op_nodes = []
for next_node in dag.successors(node):
if isinstance(next_node, DAGOutNode):
continue
op_nodes.append(next_node)

return op_nodes
if not isinstance(next_node, DAGOutNode):
yield next_node

def _push_node_back(self, dag: DAGCircuit, node: DAGOpNode, shift: int):
"""Update start time of current node. Successors are also shifted to avoid overlap.
Expand All @@ -114,57 +110,63 @@ def _push_node_back(self, dag: DAGCircuit, node: DAGOpNode, shift: int):
conditional_latency = self.property_set.get("conditional_latency", 0)
clbit_write_latency = self.property_set.get("clbit_write_latency", 0)

# Compute shifted t1 of this node separately for qreg and creg
this_t0 = node_start_time[node]
new_t1q = this_t0 + node.op.duration + shift
this_qubits = set(node.qargs)
if isinstance(node.op, Measure):
# creg access ends at the end of instruction
new_t1c = new_t1q
this_clbits = set(node.cargs)
else:
if node.op.condition_bits:
# conditional access ends at the beginning of node start time
new_t1c = this_t0 + shift
this_clbits = set(node.op.condition_bits)
else:
new_t1c = None
this_clbits = set()

# Check successors for overlap
for next_node in self._get_next_gate(dag, node):
# Compute next node start time separately for qreg and creg
next_t0q = node_start_time[next_node]
next_qubits = set(next_node.qargs)
if isinstance(next_node.op, Measure):
# creg access starts after write latency
next_t0c = next_t0q + clbit_write_latency
next_clbits = set(next_node.cargs)
nodes_with_overlap = [(node, shift)]
shift_stack = []
while nodes_with_overlap:
node, shift = nodes_with_overlap.pop()
shift_stack.append((node, shift))
# Compute shifted t1 of this node separately for qreg and creg
this_t0 = node_start_time[node]
new_t1q = this_t0 + node.op.duration + shift
this_qubits = set(node.qargs)
if isinstance(node.op, Measure):
# creg access ends at the end of instruction
new_t1c = new_t1q
this_clbits = set(node.cargs)
else:
if next_node.op.condition_bits:
# conditional access starts before node start time
next_t0c = next_t0q - conditional_latency
next_clbits = set(next_node.op.condition_bits)
if node.op.condition_bits:
# conditional access ends at the beginning of node start time
new_t1c = this_t0 + shift
this_clbits = set(node.op.condition_bits)
else:
next_t0c = None
next_clbits = set()
# Compute overlap if there is qubits overlap
if any(this_qubits & next_qubits):
qreg_overlap = new_t1q - next_t0q
else:
qreg_overlap = 0
# Compute overlap if there is clbits overlap
if any(this_clbits & next_clbits):
creg_overlap = new_t1c - next_t0c
else:
creg_overlap = 0
# Shift next node if there is finite overlap in either in qubits or clbits
overlap = max(qreg_overlap, creg_overlap)
if overlap > 0:
self._push_node_back(dag, next_node, overlap)

new_t1c = None
this_clbits = set()

# Check successors for overlap
for next_node in self._get_next_gate(dag, node):
# Compute next node start time separately for qreg and creg
next_t0q = node_start_time[next_node]
next_qubits = set(next_node.qargs)
if isinstance(next_node.op, Measure):
# creg access starts after write latency
next_t0c = next_t0q + clbit_write_latency
next_clbits = set(next_node.cargs)
else:
if next_node.op.condition_bits:
# conditional access starts before node start time
next_t0c = next_t0q - conditional_latency
next_clbits = set(next_node.op.condition_bits)
else:
next_t0c = None
next_clbits = set()
# Compute overlap if there is qubits overlap
if any(this_qubits & next_qubits):
qreg_overlap = new_t1q - next_t0q
else:
qreg_overlap = 0
# Compute overlap if there is clbits overlap
if any(this_clbits & next_clbits):
creg_overlap = new_t1c - next_t0c
else:
creg_overlap = 0
# Shift next node if there is finite overlap in either in qubits or clbits
overlap = max(qreg_overlap, creg_overlap)
if overlap > 0:
nodes_with_overlap.append((next_node, overlap))
# Update start time of this node after all overlaps are resolved
node_start_time[node] += shift
while shift_stack:
node, shift = shift_stack.pop()
node_start_time[node] += shift

def run(self, dag: DAGCircuit):
"""Run rescheduler.
Expand Down