Support bit registers, arrays and index expressions as for-loop iterables (#393) - #406
Conversation
…bles (#393) `Qasm3Visitor._visit_forin_loop` branched on the concrete type of `set_declaration` and rejected anything that was not a `DiscreteSet` or a `RangeDefinition`. Factor that branch into `_resolve_loop_iterable`, which returns the plain list of values to iterate and the loop-variable initializer, leaving the unrolling loop unchanged. The new path evaluates the iterable expression once and dispatches on the result: a `BitValue` yields its bits in `b[0]`, `b[1]`, ... order, and a one-dimensional `ndarray` yields `tolist()`. That covers a `bit[n]` register, a one-dimensional `array[<scalar>, n]`, and any index expression arriving at either. A multi-dimensional array raises `ValidationError`, per the spec's one-dimension restriction, and `tolist()` copies into native Python scalars so a write to the loop variable cannot reach the source. Classical `let` aliases are still unsupported; they fail at the alias statement itself and are tracked in #392. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Argus reviewAuto-review is off for this repo. Tick the box below to run a review on this PR.
Estimated cost
Tip: you can also comment |
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes #393.
Problem
Qasm3Visitor._visit_forin_loopbranched on the concrete type ofset_declarationand fell through for anything that was not aDiscreteSetor aRangeDefinition. The spec also allows abit[n]value, a one-dimensionalarray[<scalar>, n], and an index expression arriving at either.Approach
The branch is factored into
_resolve_loop_iterable, which returns the plain list of values plus the loop-variable initializer. The unrolling loop below is unchanged.For an
IdentifierorIndexExpression, the expression is evaluated once and the result dispatched on type: aBitValueyields its bits inb[0],b[1], ... order (bit 0 is the leftmost bitstring character); a one-dimensionalndarrayyieldstolist().tolist()produces native Python scalars, so the loop variable is bound by copy and a write to it cannot reach the source array. Anything else — a scalar, aBitstringLiteral— still raises the original "Unexpected type ... of set_declaration in loop." error. The existing loop-limit check now covers the new forms too.Tests
tests/qasm3/test_loop.py: abit[n]register asserting MSB-first order, abitloop variable over a register, a one-dimensional array, an index-expression iterable (a[1:2], inclusive), a write to the loop variable asserting the source array is unchanged, a multi-dimensional array raisingValidationError, and a scalar index expression raising the unsupported-type error.Gap
A loop variable of type
bitinherits the pre-existing unroll behavior: each iteration emits its ownbit[1] x;declaration, exactly asfor bit x in {0, 1}does today. That is unchanged by this PR.Classical
letaliases (case 3 of the issue) are not implemented.let c = b;on a classical register still fails at the alias statement itself, before any loop is reached, because_visit_alias_statementonly resolves quantum registers. That work is tracked in #392.Stacked on #404 (
feature-385-391-bit-repr-negative-indices); rebases ontomainonce #404 merges.🤖 Generated with Claude Code