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

Update scheduling passes to group measurements#391

Merged
kdk merged 2 commits into
Qiskit:mainfrom
taalexander:taa-update-dd-scheduling
Sep 20, 2022
Merged

Update scheduling passes to group measurements#391
kdk merged 2 commits into
Qiskit:mainfrom
taalexander:taa-update-dd-scheduling

Conversation

@taalexander
Copy link
Copy Markdown
Contributor

Summary

This addresses the comments from @ajavadia here.

This pass also updates the scheduling so as not to place a barrier between conditional operations to enable the backend to have the opportunity to optimize them.

FYI @kdk

Details and comments

@coveralls
Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 3078473168

  • 0 of 38 (100.0%) changed or added relevant lines in 3 files are covered.
  • 1 unchanged line in 1 file lost coverage.
  • Overall coverage decreased (-2.7%) to 34.042%

Files with Coverage Reduction New Missed Lines %
qiskit_ibm_provider/transpiler/passes/scheduling/scheduler.py 1 97.09%
Totals Coverage Status
Change from base Build 3009736367: -2.7%
Covered Lines: 2018
Relevant Lines: 5928

💛 - Coveralls

@coveralls
Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 3078473168

  • 38 of 38 (100.0%) changed or added relevant lines in 3 files are covered.
  • 1 unchanged line in 1 file lost coverage.
  • Overall coverage decreased (-2.7%) to 34.042%

Files with Coverage Reduction New Missed Lines %
qiskit_ibm_provider/transpiler/passes/scheduling/scheduler.py 1 97.09%
Totals Coverage Status
Change from base Build 3009736367: -2.7%
Covered Lines: 2018
Relevant Lines: 5928

💛 - Coveralls

Copy link
Copy Markdown
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't particularly comment on the internals of the scheduler, but here's a couple of minor ones on the blocking algorithm. Nothing is major, and if I were responsible for merging I'd be pretty close to being ready to merge.

TODO: The need for this should be mitigated when Qiskit adds better support for
blocks and walking them in its program representation.
"""
# Dictionary is used as an ordered set of nodes to process
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment might be out of date - there's no dictionary here?

Comment on lines +31 to +35
next_nodes = dag.topological_op_nodes()
while next_nodes:
curr_nodes = next_nodes
next_nodes_set = set()
next_nodes = []
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This iterator confused me a bit at first. The main reason is, I think, just naming - next_nodes implied to me that nodes in there were in some sort of "layer" to be immediately placed. If it (and _set) was called something like deferred_nodes, I don't think I'd have done a double-take.

Comment on lines +21 to +29
def block_order_op_nodes(dag: DAGCircuit) -> Generator[DAGOpNode, None, None]:
"""Yield nodes such that they are sorted into blocks that they minimize synchronization.

This should be used when iterating nodes in order to find blocks within the circuit
for IBM dynamic circuit hardware

TODO: The need for this should be mitigated when Qiskit adds better support for
blocks and walking them in its program representation.
"""
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function internally generates a kind of blocky structure, but the exposed iterator is flat - would we be better yielding blocks at a time to maintain the structure for consumers? I see it doesn't seem to be needed in the current PR, but I worry a little about us needing to re-encode the block-splitting logic in consumers.

Comment on lines +48 to +53
if isinstance(node.op, (Reset, Measure)):
next_nodes_set |= set(
node
for node in dag.descendants(node)
if isinstance(node, DAGOpNode)
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This algorithm feels quadratic in the number of nodes in the graph, since descendants is all descendants, not just immediate ones. If that's a concern (and it may well not be), I think it's possible to invert the "node-blocking" logic to track a "placeable frontier", rather than having all nodes start placeable, and having to remove ones that aren't repeatedly. We use a similar algorithm in the Sabre routing passes - I can write a summary if it's something you want to look at.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, It should be possible to accomplish the same via the key to kwarg to DAGCircuit.topological_op_nodes (for example, see
https://github.com/Qiskit/qiskit-terra/blob/4f650581f2395ecc4c46c9259bbf35fc82955a26/qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py#L108 )

@@ -129,8 +138,18 @@ def _visit_conditional_node(self, node: DAGNode) -> None:
"""
# Special processing required to resolve conditional scheduling dependencies
if node.op.condition_bits:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this if block? With change at this line the _visit_conditional_node will be never called when conditional bits are empty, so this is obvious.


# If True we are coming from a conditional block.
# start a new block for the unconditional operations.
if self._conditional_block:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if we input

qc = QuantumCircuit(3, 1)
qc.x(0).c_if(0, True)
qc.x(1)  # <- seems like new block is created here
qc.x(2).c_if(0, True)

It seems to me like having all three instructions in a single block should be fine. Perhaps starting new block is not a problem because this program doesn't have barrier.


self._current_block_idx = block_idx

t1 = t0 + node.op.duration # pylint: disable=invalid-name
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed I had misunderstanding about conditional delay. This is likely not the scope of this PR, but for example a conditional X gate can be understood as (if my understanding is correct)

  • condition = True: Apply X gate of duration 160 dt
  • condition = False: Apply delay of duration 160 dt, e.g. turn off port output

and this is an implicit assumption in the current scheduling logic, i.e. conditional operation doesn't change instruction duration. However, in case of conditional delay,

  • condition = True: Apply delay of duration 100 dt
  • condition = False: Apply what? delay of duration 100 dt? eliminate itself from dag?

If we want to eliminate delay, the backend should dynamically reschedule instructions and update event table -- this is not currently supported I guess. So we should exclude Delay from CONDITIONAL_SUPPORTED.

from qiskit.dagcircuit import DAGCircuit, DAGOpNode


def block_order_op_nodes(dag: DAGCircuit) -> Generator[DAGOpNode, None, None]:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work in the same way also for ALAP? If not perhaps *_asap?

Copy link
Copy Markdown
Member

@kdk kdk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM, and since this is new functionality that is opt-in, we can address the comments (none of which looked blocking) in follow-on issues.

@kdk kdk merged commit 98ecb21 into Qiskit:main Sep 20, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants