Skip to content

New classical expr.Range specification - #14618

Open
arthurostrauss wants to merge 212 commits into
Qiskit:mainfrom
arthurostrauss:dynamic_range_expr
Open

New classical expr.Range specification#14618
arthurostrauss wants to merge 212 commits into
Qiskit:mainfrom
arthurostrauss:dynamic_range_expr

Conversation

@arthurostrauss

@arthurostrauss arthurostrauss commented Jun 16, 2025

Copy link
Copy Markdown
Contributor

Summary

This PR introduces a new feature enabling the specification of Range objects that can contain real-time expressions for start, stop and step. This provides a Qiskit entrypoint for OpenQASM3 RangeDefinition specification, and opens new ways of performing dynamically evolving for loops that can now depend on a wider set of expressions than the compile time specification of index set.
Closes #13725
Closes #13729

Details and comments

The Range expression is now one of the core expressions available in the expr module, as suggested in the feedback of #14277. This specification (written in Rust to comply with other expr specifications) also involves the rewriting of the OpenQASM3 exporter to include special handling of this new object, and also updates the QIskit internal OpenQASM3 AST to comply with the latest AST of the official OpenQASM3 specification (notably by specifying the type of the looping variable).

@arthurostrauss
arthurostrauss requested a review from a team as a code owner June 16, 2025 15:18
@qiskit-bot qiskit-bot added the Community PR PRs from contributors that are not 'members' of the Qiskit repo label Jun 16, 2025
@qiskit-bot

Copy link
Copy Markdown
Collaborator

Thank you for opening a new pull request.

Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient.

While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone.

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

@coveralls

coveralls commented Jun 19, 2025

Copy link
Copy Markdown

Coverage Report for CI Build 28173681343

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage increased (+0.03%) to 87.671%

Details

  • Coverage increased (+0.03%) from the base build.
  • Patch coverage: 136 uncovered changes across 13 files (713 of 849 lines covered, 83.98%).
  • 7 coverage regressions across 3 files.

Uncovered Changes

Top 10 Files by Coverage Impact Changed Covered %
crates/circuit/src/classical/expr/range.rs 435 384 88.28%
crates/circuit/src/classical/expr/expr.rs 130 98 75.38%
qiskit/visualization/circuit/matplotlib.py 21 0 0.0%
crates/qpy/src/expr.rs 41 32 78.05%
crates/cext/src/classical_expr.rs 8 0 0.0%
crates/qpy/src/value.rs 19 15 78.95%
qiskit/circuit/classical/expr/visitors.py 10 6 60.0%
crates/circuit/src/operations.rs 2 0 0.0%
crates/cext/src/control_flow.rs 1 0 0.0%
crates/qpy/src/py_methods.rs 1 0 0.0%
Total (26 files) 849 713 83.98%

Coverage Regressions

7 previously-covered lines in 3 files lost coverage.

File Lines Losing Coverage Coverage
crates/qasm2/src/lex.rs 5 92.29%
crates/qasm2/src/expr.rs 1 93.88%
qiskit/qpy/binary_io/value.py 1 66.72%

Coverage Stats

Coverage Status
Relevant Lines: 129520
Covered Lines: 113552
Line Coverage: 87.67%
Coverage Strength: 991549.42 hits per line

💛 - Coveralls

@arthurostrauss

Copy link
Copy Markdown
Contributor Author

@1ucian0, the current tests that are failing have a priori no connection with the implemented features of this PR:
2 tests, related to high level synthesis and layoutTransformation. In both cases, the error seems to come from two circuits that do not look equivalent. Would it be possible that the seeding might have changed the way the circuit is transformed ?
I can't see why my feature would make those tests fail. Any assistance would be appreciated.

@1ucian0

1ucian0 commented Aug 13, 2025

Copy link
Copy Markdown
Member

Seems to be related to #14888

@1ucian0 1ucian0 left a comment

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.

Thanks Arthur! I took a look to the python part and added few comments.

Comment thread test/python/circuit/classical/test_range.py Outdated
Comment thread releasenotes/notes/expr_range_feature-1091deab8f458eae.yaml
Comment thread qiskit/circuit/controlflow/for_loop.py
Comment thread qiskit/circuit/quantumcircuit.py
Comment thread qiskit/qasm3/ast.py Outdated
Comment thread qiskit/qasm3/ast.py Outdated
Comment thread test/python/circuit/classical/test_range.py
Comment thread test/python/circuit/classical/test_range.py Outdated
@1ucian0 1ucian0 added the Changelog: Added Add an "Added" entry in the GitHub Release changelog. label Aug 13, 2025
@arthurostrauss

Copy link
Copy Markdown
Contributor Author

@1ucian0, ready for another review round. Not too sure what is going on the docs side for the tests.

@1ucian0

1ucian0 commented Aug 14, 2025

Copy link
Copy Markdown
Member

Seems to be related to #14888

it was indeed. solved now.

@1ucian0 1ucian0 self-assigned this Aug 14, 2025
@1ucian0 1ucian0 moved this to Waiting for maintainer response in Contributor Monitoring Aug 14, 2025
@arthurostrauss

Copy link
Copy Markdown
Contributor Author

@1ucian0
All the tests are now passing. Ready for another review round.

@1ucian0

1ucian0 commented Aug 18, 2025

Copy link
Copy Markdown
Member

Not too sure what is going on the docs side for the tests.

It seems to be related with an issue in the release notes.

@arthurostrauss

Copy link
Copy Markdown
Contributor Author

Not too sure what is going on the docs side for the tests.

It seems to be related with an issue in the release notes.

It was indeed, I found an alternative phrasing to make it pass. Let me know what you think.

@arthurostrauss

Copy link
Copy Markdown
Contributor Author

@1ucian0

Still waiting for another review round on this PR.

Thank you.

@gadial gadial left a comment

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.

Overall looks very good. I left specific remarks and questions about things I did not understand.

My main concern is the way step is handled. I don't see the need to allow it to be None and why unwrap is used every time it's accessed, which might lead to panic.

Comment thread crates/circuit/src/classical/expr/range.rs Outdated
Comment thread crates/circuit/src/classical/expr/range.rs Outdated
Comment thread crates/circuit/src/classical/expr/range.rs Outdated
Comment thread crates/circuit/src/classical/expr/range.rs
Comment thread crates/circuit/src/classical/expr/range.rs Outdated
Comment thread crates/circuit/src/classical/expr/range.rs Outdated
Comment thread crates/circuit/src/classical/expr/range.rs Outdated
Comment thread crates/circuit/src/classical/expr/range.rs Outdated
Comment thread crates/circuit/src/classical/expr/expr.rs Outdated
Comment thread crates/circuit/src/classical/expr/expr.rs
gadial
gadial previously approved these changes Sep 11, 2025

@gadial gadial left a comment

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.

The changes look good to me, I approve the part I've looked at (the rust code)

Comment thread crates/circuit/src/classical/expr/range.rs Outdated
@arthurostrauss

Copy link
Copy Markdown
Contributor Author

@1ucian0
@gadial
Ready for another review. Waiting for your approval.

Comment thread qiskit/qasm3/ast.py Outdated
Comment thread releasenotes/notes/expr_range_feature-1091deab8f458eae.yaml Outdated
Comment thread releasenotes/notes/expr_range_feature-1091deab8f458eae.yaml Outdated
Comment thread releasenotes/notes/expr_range_feature-1091deab8f458eae.yaml Outdated
Comment thread test/python/circuit/classical/test_range.py Outdated
Comment thread releasenotes/notes/expr_range_feature-1091deab8f458eae.yaml
@1ucian0

1ucian0 commented Oct 3, 2025

Copy link
Copy Markdown
Member

I think there are still some unaddressed comments from @gadial

Conform expr.Range / UnrollForLoops work to upstream Qiskit#16273's input-var
loop counter (re-inferred in QPY), drop the branch's 'w' LOOP_VARIABLE
element, relax validation so range+Var is allowed, and fix the pyo3-0.29
subclass-init deprecation. Known limitation (Var-counter body cannot
capture outer vars) deferred to a follow-up PR.
… Var loop param on QPY read

When substituting variables in a ForLoopOp, exclude the loop's parameter (the body's input
variable) from substitutions so the body's input var isn't removed or mismatched with the
ForLoopOp.loop_parameter. This prevents accidental capture/removal of the loop counter during
substitution.

Also adjust QPY reading to handle ForLoopOp entries where the loop-parameter slot is serialized
as Null for runtime expr.Var counters: if the body circuit has exactly one input variable, treat
that as the loop parameter (matching the data model and the Rust reader behavior).

Update tests and release notes to reflect the loop-parameter semantics (Var loop counters are the
body's input variable and are re-inferred on QPY read). No public API signature changes, but this
behavior change affects substitution semantics and QPY deserialization for ForLoopOp.
@arthurostrauss

Copy link
Copy Markdown
Contributor Author

@gadial I have updated the PR to conform to your recent support for LoopParam.

One use case that is currently not working and that was flagged by @jakelishman in your PR is that there is currently no way in this new data model that has been introduced to insert an expr.Var from the global scope into a ForLoop operation (as it would be recast to a captured var and is hence now incompatible with the input var model). This remark should be independent of the status of this PR though.

I however decided to leave the substitute_vars within the scope of this PR as it directly unfolds the use case of the UnrollForLooptranspiler pass for the case where expr.Range only have constant constituents (i.e. expr.Value for all start, stop and step).

arthurostrauss and others added 6 commits June 25, 2026 22:29
…/dynamic ranges

Change the ForCollection::List variant from Vec to Vec so list-based loop collections can represent negative indices or other signed integer ranges. This enables expressing dynamic/range-like collections that include negative values.

Breaking change: the ForCollection::List type in the public API now contains Vec instead of Vec; callers and pattern matches must be updated accordingly.
@1ucian0 1ucian0 moved this from Ready to In review in Qiskit 2.6 Jul 27, 2026
arthurostrauss and others added 8 commits July 28, 2026 10:22
Clean up test/python/qpy/test_roundtrip.py by removing duplicated manual
write/read sequences and related assertions that duplicated what
assert_roundtrip_equal already verifies. Also remove an unused QpyError
import and correct a docstring to more precisely describe the limitation
on dumping expr.Range for-loops below QPY v18.

This is a test-only change (no runtime/API behavior change). It reduces
noise and duplication in the tests and makes expectations rely on the
central assert_roundtrip_equal helper.
…nd consolidate roundtrip tests

Introduce assert_dump_raises_unsupported to centralize checks that dumping a circuit with a given writer/version raises UnsupportedFeatureForVersion. Replace duplicated manual write_circuit/io.BytesIO blocks with calls to this helper across QPY roundtrip tests, and adjust writer iteration logic for versions that support the Rust writer.

This is a test-only refactor that reduces duplication and improves clarity; it does not change runtime or public API behavior.
gadial
gadial previously approved these changes Aug 23, 2026

@gadial gadial left a comment

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 think this PR can be merged as part of the QPY18 update. Note the changes in the python QPY component are not required as python QPY does not support QPY18, but you can leave them.

Comment thread qiskit/qasm3/exporter.py
@arthurostrauss
arthurostrauss requested a review from 1ucian0 August 26, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changelog: Added Add an "Added" entry in the GitHub Release changelog. Community PR PRs from contributors that are not 'members' of the Qiskit repo

Projects

Status: PR open / Contributor working on it
Status: In review

Development

Successfully merging this pull request may close these issues.

Add real-time Var support for ForLoopOp range OpenQASM3 import/export mechanism not working with for loop

7 participants