Skip to content

Use struct for NodeDurations in both ALAP and ASAP Scheduling Passes#15276

Merged
alexanderivrii merged 14 commits intoQiskit:mainfrom
raynelfss:struct-node-start
Mar 18, 2026
Merged

Use struct for NodeDurations in both ALAP and ASAP Scheduling Passes#15276
alexanderivrii merged 14 commits intoQiskit:mainfrom
raynelfss:struct-node-start

Conversation

@raynelfss
Copy link
Copy Markdown
Contributor

@raynelfss raynelfss commented Oct 29, 2025

Summary

The following commits introduce a PyO3 class, NodeDurations, that represents a mapping between DAGOpNode instances and their duration values in either units of dt or seconds.

The main purpose of this structure is to avoid the costly conversion from PyDict to HashMap and back in each instance.

The following PR also restructures the directories for scheduling passes to allow this struct to live in its own file under a common directory.

Details and comments

- Add initial ``NodeDurations`` struct.
This commit is incomplete and most features will stop working.
- Add magic methods to `PyNodeDurations`.
@raynelfss raynelfss force-pushed the struct-node-start branch from 00bd40d to 90d3049 Compare March 2, 2026 14:57
- Add an extra field to `PyNodeDurations` to keep mapping between indices and original dag nodes.
- Add methods to update `NodeDurations` using mappings with a subset of the current nodes or new mappings as long as the user has the original dag.
- Reverted some changes inside of Context Aware DD.
@raynelfss raynelfss added this to the 2.4.0 milestone Mar 2, 2026
@github-project-automation github-project-automation Bot moved this to Ready in Qiskit 2.4 Mar 2, 2026
@raynelfss
Copy link
Copy Markdown
Contributor Author

Does this PR need a release note? Although it is a very internal change, the property slot that stores it is mentioned in documentation, but its type is never mentioned explicitly.

@raynelfss raynelfss marked this pull request as ready for review March 2, 2026 22:49
@raynelfss raynelfss requested a review from a team as a code owner March 2, 2026 22:49
@qiskit-bot
Copy link
Copy Markdown
Collaborator

One or more of the following people are relevant to this code:

  • @Qiskit/terra-core

@raynelfss raynelfss changed the title [WIP] Use struct for NodeDurations in both ALAP and ASAP Scheduling Passes Use struct for NodeDurations in both ALAP and ASAP Scheduling Passes Mar 2, 2026
@alexanderivrii alexanderivrii self-assigned this Mar 10, 2026
Copy link
Copy Markdown
Member

@alexanderivrii alexanderivrii left a comment

Choose a reason for hiding this comment

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

Thanks Ray, I have left a few questions (in particular there is something about the equality of PyNodeDurations that I do not quite understand).

Comment thread crates/transpiler/src/passes/schedule_analysis/mod.rs Outdated
Comment thread crates/transpiler/src/passes/schedule_analysis/mod.rs
Comment thread crates/transpiler/src/passes/schedule_analysis/mod.rs Outdated
Comment thread crates/transpiler/src/passes/schedule_analysis/mod.rs
Comment thread crates/transpiler/src/passes/schedule_analysis/mod.rs
Comment thread crates/transpiler/src/passes/schedule_analysis/mod.rs
Comment thread crates/transpiler/src/passes/schedule_analysis/mod.rs Outdated
raynelfss and others added 2 commits March 11, 2026 10:52
alexanderivrii
alexanderivrii previously approved these changes Mar 11, 2026
Copy link
Copy Markdown
Member

@alexanderivrii alexanderivrii left a comment

Choose a reason for hiding this comment

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

Ray, thanks for explanations and quick updates. Based on Matthew's comment that node durations should only be used for look-ups by node id, I think that using HashMap to represent node durations and iterating over DAG's Delay nodes in dynamical decoupling both make sense.

This PR does change the type of property_set["node_duration"] from dict to class 'qiskit._accelerate.scheduling.NodeDurations, however I don't think this poses a problem from the backward compatibility standpoint.

@alexanderivrii alexanderivrii dismissed their stale review March 12, 2026 14:09

As we discussed during the meeting today, we need to preserve backward compatibility as much as possible (in particular we need to go back to using IndexMap).

raynelfss and others added 2 commits March 12, 2026 18:01
- An oversight allowed an error variant to precompute itself even if the result was `Ok` via `ok_or`. Replaced it with `ok_or_else`.
- Fix formatting issue.
@raynelfss
Copy link
Copy Markdown
Contributor Author

@alexanderivrii I reverted the changes back to using IndexMap and we're lucky to have done so as during testing I found a performance regression I had accidentally introduced 😅. The PR should be in a much better state now.

@raynelfss raynelfss added the Changelog: None Do not include in the GitHub Release changelog. label Mar 13, 2026
@raynelfss raynelfss added Rust This PR or issue is related to Rust code in the repository mod: transpiler Issues and PRs related to Transpiler labels Mar 13, 2026
Copy link
Copy Markdown
Member

@alexanderivrii alexanderivrii left a comment

Choose a reason for hiding this comment

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

Thanks for the updates, Ray!

I did not fully understand where the performance regression that you mentioned was coming from, is it from using HashMap instead of IndexMap?

Overall this looks very nice to me. I believe to fully look a Python dict, you should also implement the __iter__ magic method, what do you think?

Otherwise, it's ready to merge.

@raynelfss
Copy link
Copy Markdown
Contributor Author

raynelfss commented Mar 18, 2026

I did not fully understand where the performance regression that you mentioned was coming from, is it from using HashMap instead of IndexMap?

Oh, I forgot to explain it but it was part of the commit message of the last commit:

cf08009

Fix: Pre-computing error in __getitem__
- An oversight allowed an error variant to precompute itself even if the result was `Ok` via `ok_or`. Replaced it with `ok_or_else`.
...

The regression I introduced simply called Python's __repr__ method on each node regardless of if it was to be used for an error message or not, which caused the performance to worsen greatly.

I believe to fully look a Python dict, you should also implement the iter magic method, what do you think?

I might be wrong but because the struct is specified to be a mapping and it implements the __getitem__, __setitem__ and __len__ methods, Python provides a default implementation. Or at least that what it's supposed to do. I haven't tested this so allow me to confirm that it is possible.

Update: it in fact does not make it iterable...

@raynelfss
Copy link
Copy Markdown
Contributor Author

Added iteration methods (__iter__, keys and values) in 95ccf0c

Copy link
Copy Markdown
Member

@alexanderivrii alexanderivrii left a comment

Choose a reason for hiding this comment

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

Thanks for the explanations, and thanks for remembering to also implement keys and values. After experimenting with the code, the NodeDurations data structure now looks like a dict and quacks like a dict, therefore for all practical purposes it's backwards compatible.

@alexanderivrii alexanderivrii added this pull request to the merge queue Mar 18, 2026
Merged via the queue into Qiskit:main with commit 301aac0 Mar 18, 2026
25 checks passed
@github-project-automation github-project-automation Bot moved this from Ready to Done in Qiskit 2.4 Mar 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changelog: None Do not include in the GitHub Release changelog. mod: transpiler Issues and PRs related to Transpiler Rust This PR or issue is related to Rust code in the repository

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants