Skip to content

Conversation

@arthurostrauss
Copy link
Contributor

@arthurostrauss arthurostrauss commented Jun 16, 2025

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
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
Copy link

coveralls commented Jun 19, 2025

Pull Request Test Coverage Report for Build 20016330999

Details

  • 159 of 287 (55.4%) changed or added relevant lines in 11 files are covered.
  • 15 unchanged lines in 4 files lost coverage.
  • Overall coverage decreased (-0.08%) to 88.282%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/qasm3/ast.py 4 5 80.0%
crates/circuit/src/operations.rs 0 2 0.0%
qiskit/qasm3/exporter.py 4 6 66.67%
qiskit/circuit/classical/expr/visitors.py 6 10 60.0%
qiskit/visualization/circuit/matplotlib.py 0 21 0.0%
crates/circuit/src/classical/expr/expr.rs 0 30 0.0%
crates/circuit/src/classical/expr/range.rs 138 206 66.99%
Files with Coverage Reduction New Missed Lines %
crates/circuit/src/parameter/parameter_expression.rs 1 82.3%
crates/qasm2/src/expr.rs 1 93.82%
crates/qasm2/src/parse.rs 6 97.56%
crates/qasm2/src/lex.rs 7 91.0%
Totals Coverage Status
Change from base Build 20001590113: -0.08%
Covered Lines: 96292
Relevant Lines: 109073

💛 - Coveralls

@arthurostrauss
Copy link
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
Copy link
Member

1ucian0 commented Aug 13, 2025

Seems to be related to #14888

Copy link
Member

@1ucian0 1ucian0 left a comment

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.

@1ucian0 1ucian0 added the Changelog: New Feature Include in the "Added" section of the changelog label Aug 13, 2025
@arthurostrauss
Copy link
Contributor Author

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

@1ucian0
Copy link
Member

1ucian0 commented Aug 14, 2025

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
Contributor Author

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

@1ucian0
Copy link
Member

1ucian0 commented Aug 18, 2025

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
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
Contributor Author

@1ucian0

Still waiting for another review round on this PR.

Thank you.

Copy link
Contributor

@gadial gadial left a comment

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.

return false;
}
}
(ExprRef::Range(a), ExprRef::Range(b)) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't fully understand what this function does - and so, whether we should also compare the values of start and stop (and step).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It recursively goes into the equivalence checks of the components of the Range, which are defined in other modules. I did not pay too much attention of what it was checking under the hood

gadial
gadial previously approved these changes Sep 11, 2025
Copy link
Contributor

@gadial gadial left a comment

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)

@arthurostrauss
Copy link
Contributor Author

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

self.assertEqual(range_expr.type, types.Uint(8))
self.assertTrue(range_expr.const)

def test_range_with_float_values(self):
Copy link
Member

Choose a reason for hiding this comment

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

I think this should just check start, just like the next test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure to understand that either. Which tests are you referring to?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think start should be the only one tested, because we want to test the type casting of the step when not explicitly provided.

@1ucian0
Copy link
Member

1ucian0 commented Oct 3, 2025

I think there are still some unaddressed comments from @gadial

@1ucian0 1ucian0 added this to the 2.3.0 milestone Nov 25, 2025
@1ucian0 1ucian0 moved this from Ready to In review in Qiskit 2.3 Nov 25, 2025
@1ucian0 1ucian0 moved this from Waiting for maintainer response to Blocked by another issue in Contributor Monitoring Nov 25, 2025
@1ucian0 1ucian0 modified the milestones: 2.3.0, 2.2.4 Nov 26, 2025
@1ucian0
Copy link
Member

1ucian0 commented Nov 26, 2025

There are some high-priority changes on control flow coming that mostly probably will conflict with this PR. So probably this PR wont make it in 2.3. Bumping it for 2.4.

Extends the circuit representation to support range objects (both `expr.Range` and Python `range`) as index sets for for-loops, in addition to lists of integers.

This change ensures that for-loops can iterate over dynamically-sized ranges defined by `expr.Range`, preserving the Python `range` object when provided as input. This allows users to use Python ranges as loop iterators instead of just lists of indices.
The length of `expr.Range` objects can only be determined at runtime, a fallback mechanism is added to handle this case gracefully.

Also introduces a dedicated enum `ForLoopIndexSet` to encapsulate the different types of index sets.
@arthurostrauss
Copy link
Contributor Author

The latest commits aim to solve both the integration issue related to #14568 and to address the issue #15380 by doing a careful check of the Python range in Rust. The latter check is done by inspecting the name of the type, which might not appear robust at first glance if the Python range is bound to change its name but it could probably pass as a temporary solution to recover the expected behavior.

Elsewhere, the indexset check is relaxed in such a way that one can either recover access to Python range or the expr.Range expression done by this PR.

Enhances the visualization of `ForLoopOp` nodes in the circuit drawer.

It now correctly displays the range parameters (start, stop, step) when the index set is an `expr.Range` object, extracting and displaying their values or names.

This provides a clearer and more informative representation of loop indices in circuit diagrams, especially when using dynamic ranges.
@arthurostrauss
Copy link
Contributor Author

@1ucian0, as this PR got updated with the recently merged internal change for control flow, and that it furthermore intends to solve another supported behavior for Python ranges, could this PR be reviewed in the expectation to be included in the next release? Thanks

arthurostrauss and others added 4 commits November 27, 2025 20:02
Streamlines the formatting of range expressions displayed in circuit visualizations, improving readability.

Removes redundant conditional logic and simplifies the construction of the range string.
Refactors the logic for displaying range objects within circuit visualizations.

Simplifies the handling of `range` and `IndexSet` objects to provide a more consistent and readable representation, especially when dealing with step values.

The changes enhance the display of dynamic ranges to avoid fallback to string representations of the `IndexSet`.
@jakelishman jakelishman removed this from Qiskit 2.3 Nov 30, 2025
Updated ForLoopIndexSet to match latest ForCollection definition
Addresses comments to reduce unnecessary cloning during the creation of range expressions.

This change reduces clone statements in the core range.rs logic. It also introduces getter methods that are now used in the `__repr__` method to further reduce unnecessary cloning.
@arthurostrauss
Copy link
Contributor Author

This PR has been updated with the latest modifications brought by #15404 and complies with the recent Rust porting done by #14568. It also addressed the remaining comments of @gadial on implementation details of the new range.rs file. All tests are passing and build on top of the previous changes of control-flow that were planned for Qiskit 2.3.

@1ucian0, @jakelishman, it is ready for a last review round and could be reintegrated to the 2.3 milestone unless there are critical reasons not to do it (e.g. anything else on control-flow revamping that needs to be prioritized over adding this).

To comply with the current model of ForCollection, new methods called is_empty() and len() have been implemented in the Range object, and return by default False and 1 as both those methods would not be relevant at compile time.

@jakelishman jakelishman removed this from the 2.2.4 milestone Dec 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changelog: New Feature Include in the "Added" section of the changelog Community PR PRs from contributors that are not 'members' of the Qiskit repo on hold Can not fix yet

Projects

Status: Blocked by another issue

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

6 participants